Использование D3 и BLOB-объектов для визуализации SVG изображения - PullRequest
0 голосов
/ 11 сентября 2018

Я пытаюсь сделать своего рода обратную капчу, в конце я хочу иметь возможность вводить длинные строки текста, до 500 символов, и запускать некоторые базовые капчи, такие как запутывание слов, но все еще быть читабельным. Но я также хочу, чтобы сгенерированное изображение могло быть загружено, а не svg.

Мне удалось создать эффект для текста и отобразить svg, и я нашел пример использования d3 для отображения его в datauri и blob to image. Я пытался вставить svg в место, где происходит рендеринг примера d3, но я не думаю, что делаю это правильно.

вот мой рабочий текст text2captcha gen с частью нерабочего d3 / svg / blob to image, я процитирую html

https://codepen.io/anon/pen/zJRLdx

    <!DOCTYPE html>
<meta charset="utf-8">
<style>

path {
  stroke: #000;
  fill-opacity: .8;
}

</style>
<body>
  <center>
  <h1>text2Captcha gen</h1>
  </br>
  <textarea placeholder="put your text here please"></textarea>
  </br>
  <button id="gen">gen</button>
  </br>
    <div id="svg"></div>
    <button id="save">Save as Image</button>
    <div id="svgdataurl"></div>
<script src="http://d3js.org/d3.v3.min.js"></script>


  <svg width="250" height="75">
    <text x="25" y="45" fill="black" id="text" filter="url(#warp)" style="font-size:34px;">test</text>
    <filter id="warp">
      <feMorphology radius="3" operator="dilate" />
      <feComponentTransfer>
        <feFuncA type="table" tableValues="0.75 0.2" />
      </feComponentTransfer>
      <feMerge result="text">
        <feMergeNode/>
        <feMergeNode in="SourceGraphic" />
      </feMerge>
      <feTurbulence type="fractalNoise" baseFrequency="0.023" numOctaves="2" result="warp" id="turb" />
      <feDisplacementMap xChannelSelector="R" yChannelSelector="G" scale="60" in="text" in2="warp" id="sdm" />
    </filter>
  </svg>

<script>
  var svg = d3.select("#svg").append("idm")

d3.select("#save").on("click", function(){
  var html = d3.select("svg")
        .attr("version", 1.1)
        .attr("xmlns", "http://www.w3.org/2000/svg")
        .node().parentNode.innerHTML;

  //console.log(html);
  var imgsrc = 'data:image/svg+xml;base64,'+ btoa(html);
  var img = '<img src="'+imgsrc+'">'; 
  d3.select("#svgdataurl").html(img);

});
</script>

^ вот JS для этого

$(function () {
  var rnum, rnum2
  $("button").click(function () {
    $("#text")
      .text($("textarea")
            .val());
    rnum = Math
      .floor((Math.random() * 80) + 40);
    $("#sdm").attr("scale", rnum
                   .toString());
    rnum2 = Math
      .floor((Math.random() * 4) + 1);
    $("#turb")
    .attr("numOctaves", rnum2
          .toString());
  });  
});

и вот ссылка на рабочий блоб d3 для изображения. Я процитирую этот HTML тоже. https://codepen.io/anon/pen/jvZpLX

<!DOCTYPE html>
<meta charset="utf-8">
<style>

path {
  stroke: #000;
  fill-opacity: .8;
}

</style>
<body>
    <div id="svg"></div>
    <button id="save">Save as Image</button>
    <h2>SVG dataurl:</h2>
    <div id="svgdataurl"></div>

    <h2>SVG converted to PNG dataurl via HTML5 CANVAS:</h2>
    <div id="pngdataurl"></div>

    <h2>SVG converted to PNG dataurl via HTML5 CANVAS and then converted into a filename using :</h2>
    <div id="pngdataurl"></div>

    <canvas width="960" height="500" style="display:none"></canvas>

<script src="http://d3js.org/d3.v3.min.js"></script>
<script>

var width = 960,
    height = 500;

var m = 5, // number of series
    n = 90; // number of values

// Generate random data into five arrays.
var data = d3.range(m).map(function() {
  return d3.range(n).map(function() {
    return Math.random() * 100 | 0;
  });
});

var x = d3.scale.linear()
    .domain([0, n - 1])
    .range([0, width]);

var y = d3.scale.ordinal()
    .domain(d3.range(m))
    .rangePoints([0, height], 1);

var color = d3.scale.ordinal()
    .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56"]);

var area = d3.svg.area()
    .interpolate("basis")
    .x(function(d, i) { return x(i); })
    .y0(function(d) { return -d / 2; })
    .y1(function(d) { return d / 2; });

var svg = d3.select("#svg").append("svg")
    .attr("width", width)
    .attr("height", height);

svg.selectAll("path")
    .data(data)
  .enter().append("path")
    .attr("transform", function(d, i) { return "translate(0," + y(i) + ")"; })
    .style("fill", function(d, i) { return color(i); })
    .attr("d", area);




d3.select("#save").on("click", function(){
  var html = d3.select("svg")
        .attr("version", 1.1)
        .attr("xmlns", "http://www.w3.org/2000/svg")
        .node().parentNode.innerHTML;

  //console.log(html);
  var imgsrc = 'data:image/svg+xml;base64,'+ btoa(html);
  var img = '<img src="'+imgsrc+'">'; 
  d3.select("#svgdataurl").html(img);

    var canvas = document.querySelector("canvas"),
        context = canvas.getContext("2d");

    var image = new Image;
    image.src = imgsrc;
    image.onload = function() {
      context.drawImage(image, 0, 0);

      //save and serve it as an actual filename
    binaryblob();

      var a = document.createElement("a");
      a.download = "sample.png";
      a.href = canvas.toDataURL("image/png");

       var pngimg = '<img src="'+a.href+'">'; 
       d3.select("#pngdataurl").html(pngimg);

      a.click();
    };

});


function binaryblob(){
    var byteString = atob(document.querySelector("canvas").toDataURL().replace(/^data:image\/(png|jpg);base64,/, "")); //wtf is atob?? https://developer.mozilla.org/en-US/docs/Web/API/Window.atob
    var ab = new ArrayBuffer(byteString.length);
    var ia = new Uint8Array(ab);
    for (var i = 0; i < byteString.length; i++) {
        ia[i] = byteString.charCodeAt(i);
    }
    var dataView = new DataView(ab);
    var blob = new Blob([dataView], {type: "image/png"});
    var DOMURL = self.URL || self.webkitURL || self;
    var newurl = DOMURL.createObjectURL(blob);

    var img = '<img src="'+newurl+'">'; 
  d3.select("#img").html(img);
}
</script>

большое спасибо за то, что даже посмотрел на мою ветку, я не лучший в кодировании.

1 Ответ

0 голосов
/ 11 сентября 2018

Ваш выбор неверен. Когда вы выполните

var html = d3.select("svg")
    .attr("version", 1.1)
    .attr("xmlns", "http://www.w3.org/2000/svg")
    .node().parentNode.innerHTML;

parentNode - это элемент <center>, а innerHTML - это все на вашей странице, а не только элемент <svg>. Вы можете сделать весь процесс гораздо более лаконичным с помощью интерфейса XMLSerializer :

var svgNode = d3.select('svg').node();
var html = new XMLSerializer().serializeToString(svgNode);

Это также позаботится об атрибуте xmlns (version не требуется).

Вторая часть заключается в том, что btoa() не конвертер файлов, а кодировщик. Разница в том, что браузер декодирует его обратно в SVG еще до того, как отображает его. Это идет вразрез с тем, чего вы хотите достичь. Вы можете использовать код из примера, которому вы следуете, или посмотреть на этот пример , который отличается в деталях, но достигает в основном того же самого, а именно, конвертирует SVG в растровое изображение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...