簡體   English   中英

如何在畫布上繪制多個圖像並將畫布另存為png圖像

[英]How to draw multiple images on canvas and save the canvas as png image

您好,我嘗試在畫布上繪制多個圖像,然后使用html2canvas和canvas2image將其另存為png。

問題在於僅繪制了最后一張圖像,而當我下載該圖像時,它並沒有隨該圖像一起下載。

我正在使用for循環來遍歷圖像,然后獲取src值和要繪制的偏移量。 但是我想我在這里丟失了一些東西,因為只有最后一張圖像正在渲染,但沒有保存在文件中。

下面是我用來在畫布上渲染圖像的內容:

 $(function() { $("#btnSave").click(function() { html2canvas($("#widget"), { onrendered: function(canvas) { var context = canvas.getContext("2d"); // returns the 2d context object var images = document.getElementsByClassName('simg'); //Find actual position with parent cotainer var offsetsContainer = document.getElementsByClassName('imagesholder')[0].getBoundingClientRect(); for (var i = 0; i < images.length; i++) { var img = new Image() //creates a variable for a new image var offsets = images[i].getBoundingClientRect(); var imgTop = offsets.top; var imgLeft = offsets.left; imageLeft = parseInt(imgLeft) - parseInt(offsetsContainer.left); imageTop = parseInt(imgTop) - parseInt(offsetsContainer.top); img.src = images[i].src; // specifies the location of the image img.onload = function() { context.drawImage(img, imageLeft, imageTop);// draws the image at the specified x and y location } } // Convert and download as image theCanvas = canvas; document.body.appendChild(canvas); // Convert and download as image Canvas2Image.saveAsPNG(canvas); $("#img-out").append(canvas); } }); }); }); 
 body { font-family: "Lucida Grande", "Lucida Sans", Arial, sans-serif; font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; } .dataset { float: left; vertical-align: top; } .widget{ display: inline-block; background-color: white; font-size: 14px !important; line-height: 20px !important; margin: 5px; vertical-align: top; color: #333; border-radius: 5px; margin: 10px; padding-bottom: 20px; border: 1px solid lightgray; border-radius:5px; -webkit-border-radius: 5px; display: inline-block; page-break-after: always; } .widget .header p { padding: 10px; border-bottom: 1px solid lightgrey; max-width: 360px; } .widget .header .title { font-weight: bold; vertical-align: middle; min-height: 36px; padding: 5px 10px 5px 10px; } .widget .header:hover { background-color: #f4f4f4; } .widget .header .title.selected { border-color: cornflowerblue; background-color: #EEF; } .widget .content { padding: 5px; overflow-y: auto; max-height: 400px; } .autolayout { display: inline-block; } .element { width: 360px; } .compact .content { display: table; width: 100%; } .compact .row { display: table-row; width: 100%; } .compact .cell { display: table-cell; } .compact .row.selected { background-color: #eee; } .toolbar { display: block; vertical-align: top; margin: 10px; } .toolbar .basis { min-width: 100px; } .btn { /*min-width: 60px;*/ } .cell.value { overflow: hidden; text-wrap: none; white-space: nowrap; text-overflow: ellipsis; text-align: right; padding-right: 10px; } .cell.freq { width: 60px; } .cell.glyph { vertical-align: middle; width: 100px; } .element { } .element table { table-layout: fixed; width: 100%; } .element td { padding: 0px; } .element .selectable:hover { background-color: #f4f4f4; } .element .stat { text-align: right; padding-right: 20px; font-weigth: bold; color: darkgray; } .element .bar { height: 18px; display: inline-block; float: left; } .bar-both { background-color: #0a67a3 !important; } .bar-fg { background-color: #3e97d1 !important; } .bar-bg { background-color: #ddd !important; } .selected .bar-fg { background-color: #FC0; } .selected .bar-both { background-color:#FA0; } tr.selected { background-color: #eee; } .crosstab .selectable:hover { background-color: #f4f4f4; } .crosstab tr.selected { background-color: #eee; } .crosstab .header p { max-width: 600px; } .crosstab td { padding: 0 5px 0 5px; text-align: right; } .crosstab td.value { min-width: 60px; max-width: 240px; text-align: left; } .crosstab .cell { vertical-align: top; } .crosstab th.cell { max-width: 120px; overflow: hidden; white-space: normal; text-overflow: ellipsis; text-align: right; padding-right: 10px; vertical-align: bottom; } .crosstab .n { color: darkgray; } .fieldlist { } .constraints { min-width:300px; padding: 10px; border-radius:5px; -webkit-border-radius: 5px; } .constraints table { width: 100%; } .sidenote { max-width:300px; padding: 0 10px 0px 10px; display: inline-block; vertical-align: top; } .headnote { max-width: 600px; padding: 10px; margin: 10px; display: inline-block; } .info-block { /*border: 1px solid lightgrey;*/ background-color: #eee; vertical-align: top; margin: 10px; padding: 10px; display: block; /*box-shadow: 0 0 0 0px #9bc0cf, 0 0 0 3px #e0ebf0;*/ } .menu-item { } .menu-item-value { text-align: right; float: right; } .gradient-blue { background: #b8e1fc; background: -moz-linear-gradient(top, #b8e1fc 0%, #a9d2f3 10%, #90bae4 25%, #90bcea 37%, #90bff0 50%, #6ba8e5 51%, #a2daf5 83%, #bdf3fd 100%); /* FF3.6+ */ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #b8e1fc), color-stop(10%, #a9d2f3), color-stop(25%, #90bae4), color-stop(37%, #90bcea), color-stop(50%, #90bff0), color-stop(51%, #6ba8e5), color-stop(83%, #a2daf5), color-stop(100%, #bdf3fd)); /* Chrome,Safari4+ */ background: -webkit-linear-gradient(top, #b8e1fc 0%, #a9d2f3 10%, #90bae4 25%, #90bcea 37%, #90bff0 50%, #6ba8e5 51%, #a2daf5 83%, #bdf3fd 100%); /* Chrome10+,Safari5.1+ */ background: -o-linear-gradient(top, #b8e1fc 0%, #a9d2f3 10%, #90bae4 25%, #90bcea 37%, #90bff0 50%, #6ba8e5 51%, #a2daf5 83%, #bdf3fd 100%); /* Opera 11.10+ */ background: -ms-linear-gradient(top, #b8e1fc 0%, #a9d2f3 10%, #90bae4 25%, #90bcea 37%, #90bff0 50%, #6ba8e5 51%, #a2daf5 83%, #bdf3fd 100%); /* IE10+ */ background: linear-gradient(to bottom, #b8e1fc 0%, #a9d2f3 10%, #90bae4 25%, #90bcea 37%, #90bff0 50%, #6ba8e5 51%, #a2daf5 83%, #bdf3fd 100%); /* W3C */ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#b8e1fc', endColorstr='#bdf3fd', GradientType=0); /* IE6-8 */ } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/canvas2image@1.0.5/canvas2image.min.js"></script> <script src="https://github.com/niklasvh/html2canvas/releases/download/0.4.1/html2canvas.js"></script> <div id="widget" class="widget" field="AGE" roundby="20" description="Patient age, in years"> <div class="header"> <h3> Testing header </h3> </div> <div class="imagesholder"> <img src="https://lorempixel.com/output/technics-qc-100-50-2.jpg" class="simg"/> <img src="https://lorempixel.com/output/technics-qc-100-50-8.jpg" class="simg"/> <img src="https://lorempixel.com/output/technics-qc-100-50-3.jpg" class="simg"/> </div> <div class="element ng-scope"> <div class="content"> <table> <colgroup> <col/> <col width="60x"/> <col width="100px"/> </colgroup> <thead> <tr> <th class="cell value">Value</th> <th class="cell freq">Freq</th> <th class="cell value"></th> </tr> </thead> <tbody> <tr class="selectable"> <td class="cell value"><span tooltip="0 to 19">0 to 19</span></td> <td class="cell freq">17.2%</td> <td class="cell glyph"> <span class="bar bar-both" style="width: 17.234468937875754%;"></span> <span class="bar bar-fg" style="width: 0%;"></span> <span class="bar bar-bg" style="width: 0%;"></span> </td> </tr> <tr class="selectable"> <td class="cell value"><span tooltip="20 to 39">20 to 39</span></td> <td class="cell freq">18.0%</td> <td class="cell glyph"> <span class="bar bar-both" style="width: 18.03607214428858%;"></span> <span class="bar bar-fg" style="width: 0%;"></span> <span class="bar bar-bg" style="width: 0%;"></span> </td> </tr> <tr data-key="40" class="selectable"> <td class="cell value"><span tooltip="40 to 59">40 to 59</span></td> <td class="cell freq ng-binding">34.3%</td> <td class="cell glyph"> <span class="bar bar-both" style="width: 34.2685370741483%;"></span> <span class="bar bar-fg" style="width: 0%;"></span> <span class="bar bar-bg" style="width: 0%;"></span> </td> </tr> <tr class="selectable"> <td class="cell value"><span tooltip="60 to 79">60 to 79</span></td> <td class="cell freq ng-binding">24.0%</td> <td class="cell glyph"> <span class="bar bar-both" style="width: 24.04809619238477%;"></span> <span class="bar bar-fg" style="width: 0%;"></span> <span class="bar bar-bg" style="width: 0%;"></span> </td> </tr> <tr data-key="80" class="selectable"> <td class="cell value"><span tooltip="80 to 99">80 to 99</span></td> <td class="cell freq">6.4%</td> <td class="cell glyph"> <span class="bar bar-both" style="width: 6.4128256513026045%;"></span> <span class="bar bar-fg" style="width: 0%;"></span> <span class="bar bar-bg" style="width: 0%;"></span> </td> </tr> <tr> <td class="stat">Mean</td> <td >46.1</td> </tr> </tbody> </table> </div> </div> </div> <br/> <input type="button" id="btnSave" value="Save PNG"/> <div id="img-out"></div> 

您的代碼有幾個問題。

如果圖像位於同一域上,或者如果您要從顯式檢索圖像的Web服務器允許其使用特殊的響應標頭(CORS),則只允許將圖像繪制到畫布上。

為了克服這個問題,我們可以通過代理(例如https://yacdn.org/serve/ )提供圖像,也可以將圖像元素的crossOrigin屬性設置為“匿名”。

在點擊處理程序內,您將遍歷圖像元素並立即調用saveAsPNG函數。 那時,圖像還沒有繪制到畫布上! 您需要捕獲每個圖像的onload事件,並在最后一個圖像加載和繪制完成后立即調用saveAsPNG()。

最后一件事-在onload處理程序中,您要使用變量imageLeftimageTop定位每個圖像。 這意味着圖像的位置將始終是數組中最后一張圖像的值。 最好使每個圖像實例本身具有兩個單獨的變量,例如img.imageLeft = x。

這是一個例子:

 $(function() { $("#btnSave").click(function() { html2canvas($("#widget"), { onrendered: function(canvas) { var context = canvas.getContext("2d"); // returns the 2d context object var images = document.getElementsByClassName('simg'); //Find actual position with parent cotainer var counter = 0; var offsetsContainer = document.getElementsByClassName('imagesholder')[0].getBoundingClientRect(); for (var i = 0; i < images.length; i++) { var img = new Image() //creates a variable for a new image img.crossOrigin = "Anonymous"; var offsets = images[i].getBoundingClientRect(); var imgTop = offsets.top; var imgLeft = offsets.left; imageLeft = parseInt(imgLeft) - parseInt(offsetsContainer.left); imageTop = parseInt(imgTop) - parseInt(offsetsContainer.top); img.imageLeft = imageLeft; img.imageTop = imageTop; // specifies the location of the image img.onload = function(e) { context.drawImage(e.target, e.target.imageLeft, e.target.imageTop); // draws the image at the specified x and y location counter++; if (counter == images.length) { Canvas2Image.saveAsPNG(canvas); } } img.src = images[i].src; } } }); }); }); 
 body { font-family: "Lucida Grande", "Lucida Sans", Arial, sans-serif; font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; } .dataset { float: left; vertical-align: top; } .widget { display: inline-block; background-color: white; font-size: 14px !important; line-height: 20px !important; margin: 5px; vertical-align: top; color: #333; border-radius: 5px; margin: 10px; padding-bottom: 20px; border: 1px solid lightgray; border-radius: 5px; -webkit-border-radius: 5px; display: inline-block; page-break-after: always; } .widget .header p { padding: 10px; border-bottom: 1px solid lightgrey; max-width: 360px; } .widget .header .title { font-weight: bold; vertical-align: middle; min-height: 36px; padding: 5px 10px 5px 10px; } .widget .header:hover { background-color: #f4f4f4; } .widget .header .title.selected { border-color: cornflowerblue; background-color: #EEF; } .widget .content { padding: 5px; overflow-y: auto; max-height: 400px; } .autolayout { display: inline-block; } .element { width: 360px; } .compact .content { display: table; width: 100%; } .compact .row { display: table-row; width: 100%; } .compact .cell { display: table-cell; } .compact .row.selected { background-color: #eee; } .toolbar { display: block; vertical-align: top; margin: 10px; } .toolbar .basis { min-width: 100px; } .btn { /*min-width: 60px;*/ } .cell.value { overflow: hidden; text-wrap: none; white-space: nowrap; text-overflow: ellipsis; text-align: right; padding-right: 10px; } .cell.freq { width: 60px; } .cell.glyph { vertical-align: middle; width: 100px; } .element {} .element table { table-layout: fixed; width: 100%; } .element td { padding: 0px; } .element .selectable:hover { background-color: #f4f4f4; } .element .stat { text-align: right; padding-right: 20px; font-weigth: bold; color: darkgray; } .element .bar { height: 18px; display: inline-block; float: left; } .bar-both { background-color: #0a67a3 !important; } .bar-fg { background-color: #3e97d1 !important; } .bar-bg { background-color: #ddd !important; } .selected .bar-fg { background-color: #FC0; } .selected .bar-both { background-color: #FA0; } tr.selected { background-color: #eee; } .crosstab .selectable:hover { background-color: #f4f4f4; } .crosstab tr.selected { background-color: #eee; } .crosstab .header p { max-width: 600px; } .crosstab td { padding: 0 5px 0 5px; text-align: right; } .crosstab td.value { min-width: 60px; max-width: 240px; text-align: left; } .crosstab .cell { vertical-align: top; } .crosstab th.cell { max-width: 120px; overflow: hidden; white-space: normal; text-overflow: ellipsis; text-align: right; padding-right: 10px; vertical-align: bottom; } .crosstab .n { color: darkgray; } .fieldlist {} .constraints { min-width: 300px; padding: 10px; border-radius: 5px; -webkit-border-radius: 5px; } .constraints table { width: 100%; } .sidenote { max-width: 300px; padding: 0 10px 0px 10px; display: inline-block; vertical-align: top; } .headnote { max-width: 600px; padding: 10px; margin: 10px; display: inline-block; } .info-block { /*border: 1px solid lightgrey;*/ background-color: #eee; vertical-align: top; margin: 10px; padding: 10px; display: block; /*box-shadow: 0 0 0 0px #9bc0cf, 0 0 0 3px #e0ebf0;*/ } .menu-item {} .menu-item-value { text-align: right; float: right; } .gradient-blue { background: #b8e1fc; background: -moz-linear-gradient(top, #b8e1fc 0%, #a9d2f3 10%, #90bae4 25%, #90bcea 37%, #90bff0 50%, #6ba8e5 51%, #a2daf5 83%, #bdf3fd 100%); /* FF3.6+ */ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #b8e1fc), color-stop(10%, #a9d2f3), color-stop(25%, #90bae4), color-stop(37%, #90bcea), color-stop(50%, #90bff0), color-stop(51%, #6ba8e5), color-stop(83%, #a2daf5), color-stop(100%, #bdf3fd)); /* Chrome,Safari4+ */ background: -webkit-linear-gradient(top, #b8e1fc 0%, #a9d2f3 10%, #90bae4 25%, #90bcea 37%, #90bff0 50%, #6ba8e5 51%, #a2daf5 83%, #bdf3fd 100%); /* Chrome10+,Safari5.1+ */ background: -o-linear-gradient(top, #b8e1fc 0%, #a9d2f3 10%, #90bae4 25%, #90bcea 37%, #90bff0 50%, #6ba8e5 51%, #a2daf5 83%, #bdf3fd 100%); /* Opera 11.10+ */ background: -ms-linear-gradient(top, #b8e1fc 0%, #a9d2f3 10%, #90bae4 25%, #90bcea 37%, #90bff0 50%, #6ba8e5 51%, #a2daf5 83%, #bdf3fd 100%); /* IE10+ */ background: linear-gradient(to bottom, #b8e1fc 0%, #a9d2f3 10%, #90bae4 25%, #90bcea 37%, #90bff0 50%, #6ba8e5 51%, #a2daf5 83%, #bdf3fd 100%); /* W3C */ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#b8e1fc', endColorstr='#bdf3fd', GradientType=0); /* IE6-8 */ } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/canvas2image@1.0.5/canvas2image.min.js"></script> <script src="https://github.com/niklasvh/html2canvas/releases/download/0.4.1/html2canvas.js"></script> <div id="widget" class="widget" field="AGE" roundby="20" description="Patient age, in years"> <div class="header"> <h3> Testing header </h3> </div> <div class="imagesholder"> <img src="https://yacdn.org/serve/https://lorempixel.com/output/technics-qc-100-50-2.jpg" class="simg" /> <img src="https://yacdn.org/serve/https://lorempixel.com/output/technics-qc-100-50-8.jpg" class="simg" /> <img src="https://yacdn.org/serve/https://lorempixel.com/output/technics-qc-100-50-3.jpg" class="simg" /> </div> <div class="element ng-scope"> <div class="content"> <table> <colgroup> <col/> <col width="60x" /> <col width="100px" /> </colgroup> <thead> <tr> <th class="cell value">Value</th> <th class="cell freq">Freq</th> <th class="cell value"></th> </tr> </thead> <tbody> <tr class="selectable"> <td class="cell value"><span tooltip="0 to 19">0 to 19</span></td> <td class="cell freq">17.2%</td> <td class="cell glyph"> <span class="bar bar-both" style="width: 17.234468937875754%;"></span> <span class="bar bar-fg" style="width: 0%;"></span> <span class="bar bar-bg" style="width: 0%;"></span> </td> </tr> <tr class="selectable"> <td class="cell value"><span tooltip="20 to 39">20 to 39</span></td> <td class="cell freq">18.0%</td> <td class="cell glyph"> <span class="bar bar-both" style="width: 18.03607214428858%;"></span> <span class="bar bar-fg" style="width: 0%;"></span> <span class="bar bar-bg" style="width: 0%;"></span> </td> </tr> <tr data-key="40" class="selectable"> <td class="cell value"><span tooltip="40 to 59">40 to 59</span></td> <td class="cell freq ng-binding">34.3%</td> <td class="cell glyph"> <span class="bar bar-both" style="width: 34.2685370741483%;"></span> <span class="bar bar-fg" style="width: 0%;"></span> <span class="bar bar-bg" style="width: 0%;"></span> </td> </tr> <tr class="selectable"> <td class="cell value"><span tooltip="60 to 79">60 to 79</span></td> <td class="cell freq ng-binding">24.0%</td> <td class="cell glyph"> <span class="bar bar-both" style="width: 24.04809619238477%;"></span> <span class="bar bar-fg" style="width: 0%;"></span> <span class="bar bar-bg" style="width: 0%;"></span> </td> </tr> <tr data-key="80" class="selectable"> <td class="cell value"><span tooltip="80 to 99">80 to 99</span></td> <td class="cell freq">6.4%</td> <td class="cell glyph"> <span class="bar bar-both" style="width: 6.4128256513026045%;"></span> <span class="bar bar-fg" style="width: 0%;"></span> <span class="bar bar-bg" style="width: 0%;"></span> </td> </tr> <tr> <td class="stat">Mean</td> <td>46.1</td> </tr> </tbody> </table> </div> </div> </div> <br/> <input type="button" id="btnSave" value="Save PNG" /> <div id="img-out"></div> 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM