如何自动下载画布图像?
Posted
技术标签:
【中文标题】如何自动下载画布图像?【英文标题】:How can I automatically download canvas images? 【发布时间】:2020-07-03 05:48:37 【问题描述】:我正在开发一个小型卡片创建器。它背后的想法是从 CSV 中获取数据,相应地从文件夹中获取一些图像,将它们与相关文本(名称、权力、奖金等)一起放入画布中,然后将其保存为图像(如果文件名会很棒= 卡名.jpg)。但我实际上坚持让下载正常工作。主要问题是我尝试的每个解决方案都给我一个空白的 jpeg,没有我填充的画布的痕迹。第二个问题是我不希望下载事件被按钮触发。只需选择 CSV,上传它,让代码为每张卡片创建一个画布,然后将每张卡片下载到同一个文件夹中,无需任何确认。有可能吗?
CSV 结构很简单,只有很多行具有相同的模式: 部落名称,卡牌名称,1,1,1,卡牌强度,卡牌奖励,全名
Papaparse 库由我从他们的网站获得的两个文件处理,因为我没有找到任何 CDN。
我是初学者,所以答案越简单越好。重要的一点是将每个 img 保存为同一文件夹中的 jpg。 (例如:C:\Users\MyName\Desktop\CardCollectionFolder)
代码只需要运行一次,只是为了在我自己的计算机上离线和创建 jpeg 格式的大量卡片。因此,内部没有安全问题。
这是我的代码(HTML/CSS + JS/JQuery)
$( document ).ready(function()
function loadImages(sources, callback)
var images = ;
var loadedImages = 0;
var numImages = 0;
// get num of sources
for(var src in sources)
numImages++;
for(var src in sources)
images[src] = new Image();
images[src].onload = function()
if(++loadedImages >= numImages)
callback(images);
;
images[src].src = sources[src];
function creaCartaFinale(results, i)
var canvas = document.getElementById("myCanvas"+i);
var context = canvas.getContext('2d');
var clan=(results.data[i][0]);
const nome =(results.data[i][1]);
var rarita =(results.data[i][2]);
var stelle =(results.data[i][3]);
var potenza =(results.data[i][4]);
var danno =(results.data[i][5]);
const potere =(results.data[i][6]);
const bonus=(results.data[i][7]);
var nomeintero=(results.data[i][8]);
imgStelle = "Immagini/LivelloCarte/livello"+ stelle +".png";
imgClan= "Immagini/IconeClan/"+ clan +"_42.png";
if (rarita=="Non comune")
imgRarita = "Immagini/RaritaCarta/raritanoncomune.png";
else
imgRarita = "Immagini/RaritaCarta/rarita"+rarita+".png";
immagine ="Immagini/ImmaginiChar/"+clan+"_"+nomeintero+"_N"+stelle+"_HD_673.png"
var sources =
image1: 'Immagini/SfondoCarte/base.png',
image2:'Immagini/SfondoCarte/riquadro.png',
image3: immagine,
image4:'Immagini/SfondoCarte/poteri.png',
image5: imgRarita,
image6: imgStelle,
image7: 'Immagini/SfondoCarte/riquadrobis.png',
image8: imgClan,
image9: 'Immagini/Numeri/'+potenza+'.png',
image10:'Immagini/Numeri/'+danno+'.png',
;
loadImages(sources, function(images)
context.drawImage(images.image1, 0, 0, 2220 , 3240); //SFONDO * x - y
context.drawImage(images.image2, 80, 80, 2040 ,1900);//RIQUADRO
context.drawImage(images.image3, 0, 0, 2220 ,3150); //IMMAGINE *
context.drawImage(images.image4, 80, 2000, 2050 ,1150); //LAYOUT POTERI *
context.drawImage(images.image5, 520, 80, 1610 ,200); //RARITA *
context.drawImage(images.image6, 600, 2000, 1240 ,260); //STELLE *
context.drawImage(images.image7, 100, 70, 360 ,360); //RIQUADRO CLAN *
context.drawImage(images.image8, 120, 80, 320 ,320); //CLAN *
context.drawImage(images.image9, 170, 2350, 130 ,170); //FORZA *
context.drawImage(images.image10, 170, 2950, 130 ,170); //DANNO *
//STAMPA NOME
context.font = "200px Calibri";
var gradient = context.createLinearGradient (0,0, canvas.width,0)
gradient.addColorStop("0", "white")
context.fillStyle = gradient;
context.fillText(nome, 600, 250);
//STAMPA POTERI E BONUS
context.font = "105px Calibri";
if (potere.length > 34)
var ultimoIndice = potere.length -1;
var frase30 = potere.slice(0,33);
var n = frase30.lastIndexOf(" ");
var primaFrase = potere.slice(0,n)
var secondaFrase = potere.slice(n,ultimoIndice)
context.fillText(primaFrase, 750, 2500);
context.fillText(secondaFrase, 750, 2620);
else
context.fillText(potere, 750, 2500);
if (bonus.length > 34)
var ultimoIndice = bonus.length -1;
var frase30 = bonus.slice(0,33);
var n = frase30.lastIndexOf(" ");
var primaFrase = bonus.slice(0,n)
var secondaFrase = bonus.slice(n,ultimoIndice)
context.fillText(primaFrase, 750, 2850);
context.fillText(secondaFrase, 750, 2970);
else
context.fillText(bonus,750, 2850);
);
document.getElementById('txtFileUpload').addEventListener('change', upload, false);
function upload(evt)
var file = evt.target.files[0];
var reader = new FileReader();
reader.readAsText(file);
reader.onload = function (event)
var csvData = event.target.result;
Papa.parse(csvData,
complete: function (results)
console.log(results.data);
var numeroCarte=(results.data.length);
for(var i=0; i<numeroCarte; i++)
$( ".cartaSingola" ).prepend( "<canvas class='cardCanvas' id='myCanvas"+i+"' width='2500' height='3500'></canvas>" );
creaCartaFinale(results,i);
download_image(i);
);
;
//THIS FUNCTION DOES NOT WORK, JUST GIVES BACK A BLANK FILE
function download_image(i)
var canvas = document.getElementById("myCanvas"+i);
image = canvas.toDataURL("image/png").replace("image/png", "image/octet-stream");
var link = document.createElement('a');
link.download = "my-image.png";
link.href = image;
link.click();
);
/* .contenitoreCarte
height:88mm;
width:63mm;
*/
.cartabase
margin:15px;
height:88mm;
width:63mm;
.nomeCarta
position: relative;
top: -352px;
right: -102px;
width:45mm;
height:6mm;
text-align: center;
z-index:1;
.nomeCarta p
text-align: center;
width: 100%;
left: -32px;
position: relative;
.potereCarta
position: relative;
top: -352px;
right: -102px;
width:45mm;
height:6mm;
text-align: center;
.potereCarta p
text-align: center;
position: relative;
bottom: -194px;
width: 82%;
left: -6px;
word-wrap: break-word
.bonusCarta
position: relative;
top: -352px;
right: -102px;
width:45mm;
height:6mm;
text-align: center;
.bonusCarta p
text-align: center;
width: 82%;
left: -6px;
bottom: -195px;
position: relative;
word-wrap: break-word
.forzaCarta
position: relative;
top: -352px;
right: -102px;
width:45mm;
height:6mm;
text-align: center;
.forzaCarta p
text-align: center;
width: 100%;
left: -148px;
bottom: -119px;
position: relative;
.dannoCarta
position: relative;
top: -352px;
right: -100px;
width:45mm;
height:6mm;
text-align: center;
.dannoCarta p
text-align: center;
width: 100%;
left: -146px;
bottom: -139px;
position: relative;
.livelloCarta
/* width: 32mm; */
width: 42mm;
height: 7mm;
right: -36px;
top: -166px;
position: relative;
.clanCarta
height: 9mm;
width: 9mm;
right: -15px;
top: -278px;
position: relative;
z-index: 1;
.raritaCarta
height: 6mm;
width: 45mm;
right: -35px;
top: -296px;
position: relative;
.baseCarta
height: 88mm;
width: 63mm;
right: -7px;
top: -312px;
position: relative;
z-index: -99;
.riquadroCarta
height: 50mm;
width: 56mm;
right: -14px;
top: -473px;
position: relative;
.poteriCarta
height: 32mm;
width: 58mm;
right: -12px;
top: -470px;
position: relative;
z-index: -99;
.immaginiCarta
height: 92mm;
width: 68mm;
right: -3px;
top: -642px;
position: relative;
z-index: 1;
.cardCanvas
position: relative;
display: block;
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet"type="text/css" />
<link rel="stylesheet" href="Pagina.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="Pagina.js"></script>
<script src="papaparse.js"></script>
<script src="papaparse.min.js"></script>
<title>Card maker</title>
</head>
<body>
<input type="file" name="File Upload" id="txtFileUpload" accept=".csv" />
<div class="cartaSingola">
</div>
</body>
</html>
【问题讨论】:
您不能使用 javascript 编写文件(这将是一场彻底的安全噩梦) 非常肯定它会,但这意味着在我自己的电脑上离线运行一次,以创建一些有趣的卡片。由于代码是用 JS 编写的,并且在保存 jpeg 之前可以正常工作,所以我没有看到任何问题。 请查看***.com/questions/17311645/… 我认为您希望保持 MIME 类型不变。 【参考方案1】:考虑以下几点:
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
// draw cloud
context.beginPath();
context.moveTo(170, 80);
context.bezierCurveTo(130, 100, 130, 150, 230, 150);
context.bezierCurveTo(250, 180, 320, 180, 340, 150);
context.bezierCurveTo(420, 150, 420, 120, 390, 100);
context.bezierCurveTo(430, 40, 370, 30, 340, 50);
context.bezierCurveTo(320, 5, 250, 20, 250, 50);
context.bezierCurveTo(200, 5, 150, 20, 170, 80);
context.closePath();
context.lineWidth = 5;
context.fillStyle = '#8ED6FF';
context.fill();
context.strokeStyle = '#0000ff';
context.stroke();
function download_image(trg)
var canvas = document.getElementById(trg);
var dataUrl = canvas.toDataURL("image/png");
var link = document.createElement('a');
link.download = "my-image.png";
link.href = dataUrl.replace("image/png", "image/octet-stream");
console.log(link);
link.click();
download_image("myCanvas");
<canvas id="myCanvas" width="578" height="200" style="display:none;"></canvas>
无法用您的代码为您测试。
【讨论】:
不起作用,我上传了 CSV,图像已创建,但代码到达函数后,它会返回错误“找不到文件” @GianlucaFontana 经过一番研究后更新。 ***.com/questions/8126623/… 本帖的第二种解决方案是自动下载,但同样的问题是空白jpg。 我试图将回调的位置交换到该函数。如果我在 loadimages 调用中调用函数,嵌套在函数 creaCartaFinale 中,我会收到空白图像或消息“可能无法导出受污染的画布” @GianlucaFontana 无法复制。当我在答案中运行脚本时,我会下载并保存为 PNG 而不是 JPG。然后我可以在下载后正确打开它。你需要做一个最小的、可重现的例子:***.com/help/minimal-reproducible-example以上是关于如何自动下载画布图像?的主要内容,如果未能解决你的问题,请参考以下文章
Fabric Js - 是不是可以将图像对象自动缩放到画布上?