下载 HTML Canvas/BLOB 为 PNG
Download HTML Canvas/BLOB as a PNG
我正在以编程方式创建多个房屋图像,如下所示:
我通过简单地遍历一个循环来做到这一点:
- 在每次迭代时创建一个新的 Canvas 对象
- 将房子的 SVG 绘制到这个新的 Canvas 对象上
- 从 Canvas
创建一个 PNG 文件
为了获得一些变化,我还在每次迭代中以编程方式更改每个房子的颜色,只需从我创建的配色方案数组中查找配色方案即可。
这一切都很好。
但我遇到的困难是让我的脚本自动将每个新创建的房屋“.PNG”文件下载到我的硬盘。
我正在尝试通过为我的每个 canvas/PNG 创建一个 ANCHOR <a>
标记,然后在每个上调用 “.click()”
方法来做到这一点(代码如下) - 但它不起作用。
Chrome 给我这个错误:
而 Firefox 给我这个错误:
知道这里需要做什么吗?
我的代码如下。
这是基本的房屋 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>
那么我有:
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");
}
终于有了这个:
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。
我正在以编程方式创建多个房屋图像,如下所示:
我通过简单地遍历一个循环来做到这一点:
- 在每次迭代时创建一个新的 Canvas 对象
- 将房子的 SVG 绘制到这个新的 Canvas 对象上
- 从 Canvas 创建一个 PNG 文件
为了获得一些变化,我还在每次迭代中以编程方式更改每个房子的颜色,只需从我创建的配色方案数组中查找配色方案即可。
这一切都很好。
但我遇到的困难是让我的脚本自动将每个新创建的房屋“.PNG”文件下载到我的硬盘。
我正在尝试通过为我的每个 canvas/PNG 创建一个 ANCHOR <a>
标记,然后在每个上调用 “.click()”
方法来做到这一点(代码如下) - 但它不起作用。
Chrome 给我这个错误:
而 Firefox 给我这个错误:
知道这里需要做什么吗?
我的代码如下。
这是基本的房屋 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>
那么我有:
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"); }
终于有了这个:
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。