Многогранный выбор SVG (цвет заливки) и экспорт маски в изображение - PullRequest
0 голосов
/ 04 января 2019

Требуется загрузить изображение + SVGmask, выбрать полигоны SVG (цвет заливки) и экспортировать маску SVG в и изображение.

Я основал свой исходный HTML-код на @Praveen ответе на этот другой вопрос чтобы иметь возможность иметь фоновое изображение и наложить поверх него многоугольный SVG, который у меня уже есть, для определения краев каждого цвета.

Цель состоит в том, чтобы иметь возможность выбрать требуемые полигоны и затемсохранить только маску.Процесс, шаг за шагом, будет чем-то похожим на изображение ниже, где пользователь выбирает, например, красный и черный, и маска SVG сохраняется с учетом невыделенных многоугольников в черном (выбранных в белом).

Process

Я сделал пример для JSFiddle , чтобы было более понятно в коде HTML, где src изображения и SVG встраиваются, но они будут в локальномфайлы, как прокомментировано в коде.

<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>TEST SVG</title>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!--
https://github.com/eligrey/Blob.js/
https://github.com/eligrey/FileSaver.js
-->
<script src="Blob.js"></script>
<script src="FileSaver.js"></script>
<script>
$(document).ready(function(e) {
        $('img.svg').each(function(){
                var $img = jQuery(this);
                var imgID = $img.attr('id');
                var imgClass = $img.attr('class');
                var imgURL = $img.attr('src');

                jQuery.get(imgURL, function(data) {
                    // Get the SVG tag, ignore the rest
                    var $svg = jQuery(data).find('svg');

                    // Add replaced image's ID to the new SVG
                    if(typeof imgID !== 'undefined') {
                        $svg = $svg.attr('id', imgID);
                    }
                    // Add replaced image's classes to the new SVG
                    if(typeof imgClass !== 'undefined') {
                        $svg = $svg.attr('class', imgClass+' replaced-svg');
                    }

                    // Remove any invalid XML tags as per http://validator.w3.org
                    $svg = $svg.removeAttr('xmlns:a');

                    // Replace image with new SVG
                    $img.replaceWith($svg);

                    $('path').click(function(){
                        if($(this).attr("class")=="selected"){
                            $(this).attr("class", "");
                        }
                        else{
                            $(this).attr("class","selected");
                        }
                    });

                }, 'xml');
        });
});


function writeDownloadLink(){
    try {
        var isFileSaverSupported = !!new Blob();
    } catch (e) {
        alert("blob not supported");
    }
    /*
    var blob = new Blob([mySVG], {type: "image/svg+xml"});
    saveAs(blob, "mySVG_selection.png");
    */
};

</script>
<style>
    #bg div{
        position:absolute;  
        top:0px;
        left:0px;
    }
    #bg .path{
        z-index:1;  
    }
    #bg .bg{
        z-index:0;  
    }
    path{
        fill:transparent;
    }
    path:hover{
        fill:rgba(255,255,255,0.6);
        cursor:pointer;
    }
    path.selected{
        fill:rgba(255,255,255,0.6); 
    }
    #savebutton {
        position:absolute;  
        top:0px;
        left:400px;
    }
</style>
</head>
<body>
    <div id="bg">
        <div class="path">
            <!--<img src="Sample_svg.svg" class="svg" />-->
            <img src='data:image/svg+xml;utf8,
                <svg width="1000" height="1000" xmlns="http://www.w3.org/2000/svg">
                    <path d="M0 0 0 200 200 200 200 0 "/>
                    <path d="M0 200 0 400 200 400 200 200 "/>
                    <path d="M200 0 200 200 400 200 400 0 "/>
                    <path d="M200 200 200 400 400 400 400 200 "/>
                </svg>
            ' class="svg" />
        </div>
        <div class="bg">
            <!--<img src="Sample_Bg.png" />-->
            <img src="https://imgur.com/olRQfPy.png" />
        </div>
    </div>
    <div id="savebutton">
        <button onclick="writeDownloadLink()">Save PNG</button>
    </div>
</body>
</html>

Таким образом, проблема, которую нужно решить, состоит в том, чтобы извлечь / экспортировать "маску SVG" и сохранить ее в файле PNG.У меня есть предположение (я не очень хорошо разбираюсь в веб-сервисах, javascript, ...), что Blob JavaScript может помочь сделать это с помощью кода, подобного следующему:

var blob = new Blob([mySVG], {type: "image/svg+xml"});
saveAs(blob, "mySVG_selection.png");

, который каким-то образом прокомментирован на примере:но не знаю, как взять только «маску SVG» и преобразовать ее в изображение.

РЕДАКТИРОВАТЬ

На основе комментариев @enxaneta я обновляю рабочий код, но безвозможность отменить выбор полигона:

<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>TEST SVG</title>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<script>
function myFunction()
{

    let canv = document.createElement("canvas");
    canv.width = svg.getAttribute("width");
    canv.height = svg.getAttribute("height");
    //canv.width = $('svg').attr("width");
    //canv.height = $('svg').attr("height");
    let ctx = canv.getContext("2d");
    ctx.fillRect(0,0,canv.width,canv.height)

    let selectedRy = [];

    svg.addEventListener("click",(e)=>{
      if(e.target.nodeName == "path"){
        e.target.classList.add("selected");
        selectedRy.push(e.target.getAttribute("d"));
      } 
    })

    action.addEventListener("click",()=>{
      for(let i = 0; i < selectedRy.length; i++){
          let thisPath = new Path2D(selectedRy[i]);
          ctx.fillStyle = "white";
          ctx.fill(thisPath); 
      }
      img.setAttribute("src",canv.toDataURL("myImg.png"));
    })
}
</script>
<style>
    #bg div{
        position:absolute;  
        top:30px;
        left:0px;
    }
    #bg .path{
        z-index:1;  
    }
    #bg .bg{
        z-index:0;  
    }
    path{
        fill:transparent;
    }
    path:hover{
        fill:rgba(255,255,255,0.6);
        cursor:pointer;
    }
    img{
        border:0px solid
    }
</style>
</head>
<body onload="myFunction()">
   <button id="action">click</button>
   <div id="bg">
      <div class="path">
         <!--<img src="Sample_svg.svg" class="svg" />-->
         <svg id="svg" xmlns="http://www.w3.org/2000/svg" width="400" height="400" class="svg replaced-svg">
            <path d="M0 0 0 200 200 200 200 0"></path>
            <path d="M0 200 0 400 200 400 200 200"></path>
            <path d="M200 0 200 200 400 200 400 0"></path>
            <path d="M200 200 200 400 400 400 400 200 " ></path>
         </svg>
         <img id="img" width="400" height="400"/> 
      </div>
      <div class="bg">
         <!--<img src="Sample_Bg.png" />-->
         <img src="https://imgur.com/olRQfPy.png" />
      </div>
   </div>
</body>
</html>

1 Ответ

0 голосов
/ 04 января 2019

Я понимаю, что пользователь будет щелкать по некоторым svg-ректам, а затем вам нужно сохранить его в изображение, где выбранные ректы будут белыми на черном фоне. В этом случае это мое решение:

  1. пользователь нажимает на рец.
  2. Вы выбираете эти строки и сохраняете атрибут d в selectedRy
  3. когда пользователь нажимает кнопку (или какое-либо другое событие), вы копируете эти ректы на холст (в данном случае не прикрепленный к DOM), а затем используете toDataURL(), чтобы сохранить его как изображение в виде данных.

let canv = document.createElement("canvas");
canv.width = svg.getAttribute("width");
canv.height = svg.getAttribute("height");
let ctx = canv.getContext("2d");
ctx.fillRect(0,0,canv.width,canv.height)

let selectedRy = [];

svg.addEventListener("click",(e)=>{
  if(e.target.nodeName == "path"){
    e.target.classList.add("selected");
    selectedRy.push(e.target.getAttribute("d"));
  } 
})


action.addEventListener("click",()=>{
  for(let i = 0; i < selectedRy.length; i++){
  let thisPath = new Path2D(selectedRy[i]);
  ctx.fillStyle = "white";
  ctx.fill(thisPath); 
  }
  img.setAttribute("src",canv.toDataURL());
})
path:hover{opacity:.5}
img{border:1px solid}
<button id="action">click</button>
<div class="path">
	<svg id="svg" xmlns="http://www.w3.org/2000/svg" width="400" height="400" class="svg replaced-svg">
		<path d="M0 0 0 200 200 200 200 0" fill="red"></path>
		<path d="M0 200 0 400 200 400 200 200" fill="blue"></path>
		<path d="M200 0 200 200 400 200 400 0" fill="lightgreen"></path>
		<path d="M200 200 200 400 400 400 400 200 " ></path>
    </svg>
  
<img id="img" width="400" height="400"/>  
</div>

Надеюсь, это то, что вам нужно.

UPDATE

ОП комментирует:

ваш код не позволяет "удалить выделение", поскольку он делает толчок. Есть ли способ отменить выбор предыдущего выбранного многоугольника?

Это обновление отвечает на эту часть их комментария.

Вместо добавления класса по клику вы можете переключать этот класс. Все выбранные ректы являются классами .selected: sel = svg.querySelectorAll(".selected"). Затем, когда вы нажимаете кнопку для каждого выбранного пути, вы рисуете путь на холсте.

Чтобы узнать, какие svg-ректы выбраны, в css я добавил .selected{opacity:.25}

let canv = document.createElement("canvas");
canv.width = svg.getAttribute("width");
canv.height = svg.getAttribute("height");
let ctx = canv.getContext("2d");

let sel = [];
svg.addEventListener("click",(e)=>{
  if(e.target.nodeName == "path"){
    e.target.classList.toggle("selected");
    sel = svg.querySelectorAll(".selected")
  } 
})


action.addEventListener("click",()=>{
  //painting a black rect
  ctx.fillStyle = "black";
  ctx.fillRect(0,0,canv.width,canv.height);
  //for every selected element in the SVG is painting a white rect on the canvas
  for(let i = 0; i < sel.length; i++){
  let thisPath = new Path2D(sel[i].getAttribute("d"));
  ctx.fillStyle = "white";
  ctx.fill(thisPath); 
  }
  //paint the image
  img.setAttribute("src",canv.toDataURL());
})
path:hover{opacity:.75}
img{border:1px solid}
.selected{opacity:.25}
<button id="action">click</button>
<div class="path">
	<svg id="svg" xmlns="http://www.w3.org/2000/svg" width="400" height="400" class="svg replaced-svg">
		<path d="M0 0 0 200 200 200 200 0" fill="red"></path>
		<path d="M0 200 0 400 200 400 200 200" fill="blue"></path>
		<path d="M200 0 200 200 400 200 400 0" fill="lightgreen"></path>
		<path d="M200 200 200 400 400 400 400 200 " ></path>
    </svg>
  
<img id="img" width="400" height="400"/>  
</div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...