下载 HTML Canvas/BLOB 为 PNG

Download HTML Canvas/BLOB as a PNG

我正在以编程方式创建多个房屋图像,如下所示:

我通过简单地遍历一个循环来做到这一点:

  1. 在每次迭代时创建一个新的 Canvas 对象
  2. 将房子的 SVG 绘制到这个新的 Canvas 对象上
  3. 从 Canvas
  4. 创建一个 PNG 文件

为了获得一些变化,我还在每次迭代中以编程方式更改每个房子的颜色,只需从我创建的配色方案数组中查找配色方案即可。

这一切都很好。

但我遇到的困难是让我的脚本自动将每个新创建的房屋“.PNG”文件下载到我的硬盘。

我正在尝试通过为我的每个 canvas/PNG 创建一个 ANCHOR <a> 标记,然后在每个上调用 “.click()” 方法来做到这一点(代码如下) - 但它不起作用。

Chrome 给我这个错误:

Firefox 给我这个错误:

知道这里需要做什么吗?

我的代码如下。

  1. 这是基本的房屋 SVG:

         <svg id="HOUSE" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" width="240.26" height="311.24" viewBox="0 0 240.26 311.24">
             <defs>
                 <style>
                 .roof-class, .window-class, .door-class {
                     stroke: #000;
                     stroke-miterlimit: 10;
                     }
                 </style>
             </defs>
    
             <g id="House">
                 <rect class="house-class" x="30.08" y="131.74" width="173.07" height="179"/>
                 <path d="M270,242V420H98V242H270m1-1H97V421H271V241Z" transform="translate(-67.39 -109.76)"/>
             </g>
    
             <polygon id="Roof" class="roof-class" points="1.11 131.74 239.11 131.74 117.11 0.74 1.11 131.74"/>
             <rect id="Window2" class="window-class" x="145.11" y="160.74" width="30" height="42"/>
             <rect id="Window1" class="window-class" x="58.61" y="160.74" width="30" height="42"/>
             <rect id="Door" class="door-class" x="92.11" y="228.74" width="52" height="82"/>
         </svg>
    
  2. 那么我有:

         window.onload = function() {
             alert("window.onload - yo!"); 
    
             let svgHolder = document.getElementById("HOUSE");
             console.log("'svgHolder' = ");
             console.log(svgHolder);
             // console.log("DIR of 'svgHolder' = " + svgHolder );
    
             svgHolder.onload = function() {
                 console.log("==> 'svgHolder.onload' --> 'TheHouse' has been loaded!!!");
             }
         }
    
    
         // GLOBAL VARIABLES:
         const TOTAL_IMAGES = 10;
         const canvasWidth = 250;
         const canvasHeight = 320;
    
         var canvasX = 0;
         var canvasY = 0;
    
         // COLOR-SCHEME VARIABLES:
         var colorCounter = 0;
    
         let houseColorSchemesArray = [ 
             {
                 ".house-class": "fuchsia",
                 ".door-class": "darkblue",
                 ".window-class": "yellow",
                 ".roof-class": "maroon"
             },
    
             {
                 ".house-class": "gold",
                 ".door-class": "purple",
                 ".window-class": "pink",
                 ".roof-class": "crimson"
             },
    
             {
                 ".house-class": "lightblue",
                 ".door-class": "darkslategray",
                 ".window-class": "lightgreen",
                 ".roof-class": "darkred"
             } ,
    
             {
                 ".house-class": "blue",
                 ".door-class": "orange",
                 ".window-class": "pink",
                 ".roof-class": "lime"
             } 
         ];
    
    
         // CLASS-NAMES:
         let classNamesToPaintArray = [".house-class", ".door-class", ".window-class", ".roof-class"];
    
         // SVG Template:
         let houseSVG = document.getElementById("HOUSE");
    
         // var loadedImageCount = 0;
    
         var masterHouseImagesArray = [];
    
    
         function designOneHouse(theCanvas) {
             console.log("= =>>In 'designOneHouse()'!\n");
    
             let context = theCanvas.getContext("2d");
    
             // Now GET-AT and PAINT the Individual SVG Components.
             // STRATEGY:
             // 1. Iterate through the Array containing all the CLASS-NAMES who's color I want to change.
             // 2. For each of these classes, I'll need to iterate through all the HTML elements that are OF that class type
             //    (there may be like 10 elements that are all styled by the same Style; I want all of them to be updated!)
             // 
             let colorScheme = houseColorSchemesArray[colorCounter];
             console.log("==>>Current 'colorScheme' = ");
             console.log(colorScheme);
    
    
             console.log("\n\nNOW Going into a 'forEach' loop!");
             classNamesToPaintArray.forEach(className => {
                 console.log("==>>In 'forEach', current 'className' = " + className);
                 let elementsArray = houseSVG.querySelectorAll(className);
    
                 elementsArray.forEach(element => element.style.fill = colorScheme[className]);
             });
    
    
             var imageData = houseSVG.outerHTML;
             var DOMURL = window.URL || window.webkitURL || window;
             var img = new Image();
             var svg = new Blob([imageData], { type: 'image/svg+xml;charset=utf-8' });
             var url = DOMURL.createObjectURL(svg);
    
             img.onload = function () {
                 context.drawImage(img, 0, 0);
                 DOMURL.revokeObjectURL(url);
    
                 // Now ADD this new House Image to the 'masterHouseImagesArray':
                 masterHouseImagesArray.push(img);
                 console.log("\n  >>>'masterHouseImagesArray' now has " + masterHouseImagesArray.length + " images in it." );
    
    
                 if(masterHouseImagesArray.length == TOTAL_IMAGES) {
                     alert("ALL IMAGES ACCOUNTED FOR!!! \n>Going to make ANCHOR TAGS NOW!!!");
                     createAnchorTags();
                 }
    
             }
    
             img.src = url;
    
    
             // Iterate the ColorCounter - making sure we don't overflow the ColorsArrays:
             colorCounter++;
             if(colorCounter == houseColorSchemesArray.length) {
                 colorCounter = 0;
             }
    
             console.log("\n\nEXITING 'designOneHouse()'!\n");
    
         }
    
  3. 终于有了这个:

         function makeCanvasGrid() {
             console.log("\n\n====>In 'makeCanvasGrid()'!\n");
    
             for(var canvasCounter = 0; canvasCounter < TOTAL_IMAGES; canvasCounter++) {
                 console.log("\n >FOR LOOP - canvasCounter = " + canvasCounter);
    
                 // 1. Create a new Canvas Object:
                 let newCanvas = document.createElement("canvas");
                 newCanvas.setAttribute("width", canvasWidth);
                 newCanvas.setAttribute("height", canvasHeight);
                 newCanvas.setAttribute("id", "newCanvas" + canvasCounter);
                 // Log-out just to verify the "id" property was set correctly:
                 console.log("  >newCanvas.id  = " + newCanvas.id);
    
                 // 2. Place the Canvas at (x,y) (top, left) coordinates:
                 newCanvas.style.backgroundColor = "lightblue";
                 newCanvas.style.position = "absolute";
                 newCanvas.style.left = canvasX + "px";
                 newCanvas.style.top = canvasY + "px";
    
                 document.body.appendChild(newCanvas);
    
                 designOneHouse(newCanvas);
    
    
                 // Check the current Canvas' (X, Y) coords, and if needed, reset X to 0 and SKIP to
                 // the next "ROW" of Canvasses:
                 if(canvasCounter > 0 && canvasCounter % 3 == 0) {
                     console.log("  >>NEXT ROW PLEASE!!!! canvasCount = ", canvasCounter);
                     canvasX = 0;
                     canvasY += canvasHeight + 20;
                 }
                 else {
                     canvasX += canvasWidth + 10;
                     console.log("\n >Increasing 'canvasX' to:" + canvasX);
                 }
             }
    
         }
    
    
    
         makeCanvasGrid();
    
    
    
         function createAnchorTags() {
             console.log("\n\n==========================\n=\n=");
             console.log("==>>In 'createAnchorTags()'!");
    
             for(anchorTagsCounter = 0; anchorTagsCounter < TOTAL_IMAGES; anchorTagsCounter++) {
                 // 1. CREATE a new HTML "a" (anchor) TAG/Element and give it an ID:
                 let newAnchorTag = document.createElement("a");
                 newAnchorTag.id = "anchorTag#" + anchorTagsCounter;
    
                 // 2. ASSIGN a value to its "href" property:
                 newAnchorTag.href = masterHouseImagesArray[anchorTagsCounter].src;
                 console.log("\n >newAnchorTag.href = " + newAnchorTag.href);
    
                 // 3. ASSIGN a value to its "download" property:
                 newAnchorTag.download = "PunkPass#" + anchorTagsCounter;
    
                 // 4. APPEND this newly created ANCHOR tag/element to the page:
                 document.body.appendChild(newAnchorTag);
    
                 console.log("   ... ... ....");
                 console.log("   ->'newAnchorTag' created!");
                 console.log("    >'newAnchorTag.id' = " + newAnchorTag.id);
    
    
                 newAnchorTag.click();
             }
    
         }
    

非常感谢您的帮助。 谢谢!

如果我没理解错的话,你应该仔细看看FileSaver.js - a convenient library for downloading files generated on the client. There is even an example of saving canvas in png file