简体   繁体   English

多面SVG选择(填充颜色)和遮罩导出到图像

[英]Multi polygon SVG selection (fill color) and mask export to an image

Need to load image+SVGmask, select polygons of SVG (fill color) and export tha SVG mask to and image. 需要加载image + SVGmask,选择SVG的多边形(填充颜色),然后将SVG蒙版导出到和图像。

I based my initial HTML code on @Praveen answer to this other question to be able to have a background image and put over it a multi-polygon SVG that I already have, to define each color edges. 我将最初的HTML代码基于@Praveen的另一个问题答案,以便能够具有背景图像,并在上面放置一个已经具有的多多边形SVG,以定义每个颜色边缘。

The objective is to be able to select the polygons required and then save only the mask. 目的是能够选择所需的多边形,然后仅保存蒙版。 A process, step-by-step would be something to the image below where the user selects, for example red and black, and the SVG mask is saved considering not selected polygons in black (selected in white). 逐步处理将是用户选择下面的图像(例如红色和黑色)的图像,并且考虑到未选择黑色(白色选择)的多边形,将保存SVG蒙版。

处理

I have done an example on JSFiddle to be more clear on the HTML code where src of image and SVG are embebed but they will be in local files as commented on the code. 我在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>

So the problem to solve is to extract/export the "SVG mask" and save it in a PNG file. 因此要解决的问题是提取/导出“ SVG遮罩”并将其保存在PNG文件中。 I have a guess (I am not good on web services, javascript,...) that Blob JavaScript can help to do it with a code similar to: 我有一个猜测(我对Web服务,JavaScript不好,...),Blob JavaScript可以通过类似于以下代码来帮助实现这一点:

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

that is someway commented on the example, but no idea how to take only "SVG mask" abd convert it to a image. 对此示例进行了评论,但不知道如何仅使用“ SVG蒙版” abd将其转换为图像。

EDIT 编辑

Based on @enxaneta comments, I update a working code but without the possibility to deselect a selected polygon: 基于@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>

I understand that the user will click on some svg rects, and then you need to save it to an image where the selected rects are white on a black background. 我了解用户会单击某些svg矩形,然后需要将其保存到所选矩形在黑色背景上为白色的图像中。 I this is the case this is my solution: 我是这种情况,这是我的解决方案:

  1. user click the rects. 用户单击矩形。
  2. you select those rects and save the d attribute in the selectedRy 您选择这些矩形并将d属性保存在selectedRy
  3. when the user clicks the button (or some other event) you copy those rects to a canvas (not attached to the DOM in this case) and then you use the toDataURL() to save it as a data uri image. 当用户单击按钮(或其他事件)时, toDataURL()这些toDataURL()复制到画布(在这种情况下未附加到DOM上),然后使用toDataURL()将其另存为数据uri图像。

 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> 

I hope this is what you need. 我希望这是您所需要的。

UPDATE UPDATE

the OP is commenting: OP在评论:

your code does not allow to "delete a selection" as it makes a push. 您的代码不允许进行“删除选择”操作。 Is there any way to deselect a previous selected polygon? 有什么办法可以取消选择先前选择的多边形?

This update is answering this part of their comment. 此更新正在回答他们的评论的这一部分。

Instead of adding a class on click you can toggle that class. 无需单击即可添加类,而是可以切换该类。 The selected rects are all the rects with a .selected class: sel = svg.querySelectorAll(".selected") . 所选的rect是具有.selected类的所有.selectedsel = svg.querySelectorAll(".selected") Then, when you click the button for every selected path you draw a path on the canvas. 然后,当您单击每个选定路径的按钮时,会在画布上绘制一个路径。

In order to know what svg rects are selected, in the css I've added .selected{opacity:.25} 为了知道选择了哪些svg .selected{opacity:.25}我在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> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM