简体   繁体   English

Canvas toDataUrl 在最新的 safari 中没有返回正确的图像

[英]Canvas toDataUrl not returning proper image on latest safari

I had this snippet used from Convert SVG to image (JPEG, PNG, etc.) in the browser在浏览器中Convert SVG to image (JPEG, PNG, etc.)使用了这个片段

It works fine in chrome but after the lastest safari update 15, the image generated is not proper.它在 chrome 中运行良好,但在最新的 safari 更新 15 之后,生成的图像不正确。

This is the chrome image https://pastebin.com/hcLAS51W这是 chrome 图像https://pastebin.com/hcLAS51W

This is the safari generated image https://pastebin.com/S7tEWQsQ这是 safari 生成的图片https://pastebin.com/S7tEWQsQ

 const base64Image = 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjkyLjk3NzUyODA4OTg4NzY0IDEyOSAzNzQuMDQ0OTQzODIwMjI0NyAxMTAiIGNsYXNzPSJQU1BERktpdC04czFzYmM1MTN0MzRxMzg4OTViNGJoM2p2biIgZm9jdXNhYmxlPSJmYWxzZSIgZGF0YS10ZXN0aWQ9Imluay1zdmciIHN0eWxlPSJsZWZ0OiAwcHg7IHRvcDogMHB4OyB3aWR0aDogMTAwJTsgaGVpZ2h0OiAxMDAlOyBvcGFjaXR5OiAxOyBvdmVyZmxvdzogaGlkZGVuOyI+PHJlY3QgeD0iOTcuOTc3NTI4MDg5ODg3NjQiIHk9IjEzNCIgd2lkdGg9IjM2NC4wNDQ5NDM4MjAyMjQ3IiBoZWlnaHQ9IjEwMCIgY2xhc3M9IlBTUERGS2l0LTc4NzFyZmh5eGI3cGRta3MxbjN4N2F2dnRhIiBzdHlsZT0iZmlsbDogdHJhbnNwYXJlbnQ7Ii8+PGcgc3R5bGU9ImZpbGw6IHRyYW5zcGFyZW50OyI+PGc+++PC9zdmc+'; const svg = window.atob(base64Image); svgToPng(svg,(imgData)=>{ const pngImage = document.createElement('img'); document.body.appendChild(pngImage); pngImage.src=imgData; }); function svgToPng(svg, callback) { const url = getSvgUrl(svg); svgUrlToPng(url, (imgData) => { callback(imgData); URL.revokeObjectURL(url); }); } function getSvgUrl(svg) { return URL.createObjectURL(new Blob([svg], { type: 'image/svg+xml' })); } function svgUrlToPng(svgUrl, callback) { const svgImage = document.createElement('img'); // imgPreview.style.position = 'absolute'; // imgPreview.style.top = '-9999px'; document.body.appendChild(svgImage); svgImage.onload = function () { const canvas = document.createElement('canvas'); canvas.width = svgImage.clientWidth; canvas.height = svgImage.clientHeight; const canvasCtx = canvas.getContext('2d'); canvasCtx.drawImage(svgImage, 0, 0); const imgData = canvas.toDataURL('image/png'); console.log(imgData, 'imgData') // This logged here gives different image in chrome and safari callback(imgData); // document.body.removeChild(imgPreview); }; svgImage.src = svgUrl; }

drawImage() with an SVG image that has no intrinsic width or height is an interop nightmare. drawImage()与没有固有宽度或高度的 SVG 图像是互操作的噩梦。
Currently the specs text does follow Chrome's behavior here, but given they are the only one to implement it, it's hard to call it a "standard".目前,规范文本确实遵循 Chrome 的行为,但鉴于它们是唯一实现它的人,很难称其为“标准”。

One of the problems here is that you are setting your canvas size based on the clientWidth and clientHeight properties of your <img> element.这里的问题之一是您根据<img>元素的clientWidthclientHeight属性设置画布大小。
This <img> element embeds an SVG image that doesn't have its own intrinsic width and height.这个<img>元素嵌入了一个没有自己固有宽度和高度的 SVG 图像。 The default width is thus interpreted as 100% .因此,默认width被解释为100%
So your <img> element will occupy whatever the size of the container ( <body> ) is, and you will set your canvas size to that body's size.因此,您的<img>元素将占用容器 ( <body> ) 的任何大小,并且您将画布大小设置为该主体的大小。

However, this sizing should only affect the <img> element, when its image is painted over a canvas, this <img> element should be (mostly) irrelevant.然而,这个尺寸应该只影响<img>元素,当它的图像被绘制在画布上时,这个<img>元素应该(大部分)无关紧要。

What does matter though in this particular case of an image with no intrinsic width or height is the size of the output canvas.尽管在没有固有宽度或高度的图像的这种特殊情况下,重要的是输出画布的大小。 In this case, the current specs texts ask to use the CSS default sizing algorithm to determine the image's size, which basically says to use the intrinsic width and height if defined, or if the image has a defined intrinsic aspect-ratio (eg viewBox), multiply the available value by this ratio, and if neither are present, use a default size.在这种情况下, 当前的规范文本要求使用CSS 默认大小算法来确定图像的大小,这基本上是说如果定义了固有宽度和高度,或者图像是否具有定义的固有纵横比(例如 viewBox) ,将可用值乘以该比率,如果两者都不存在,则使用默认大小。
And this default size is determined by the output canvas size.而这个默认大小是由输出画布大小决定的。

Here, the <svg> doesn't have neither a width nor an height , but it does have an intrinsic ratio (110/374.0449438202247), so the width will be set to the canvas width and the height will be set to this width x the ratio.在这里, <svg>既没有width也没有height ,但它有一个内在比率(110/374.0449438202247),所以width将设置为画布宽度,高度将设置为此宽度 x比例。

So the correctly calculated size of the image to be used by drawImage should be dependent on the canvas size and thus on the screen size of your user, which I personally find very disturbing.因此,正确计算的drawImage使用的图像大小应该取决于画布大小,从而取决于用户的屏幕大小,我个人觉得这非常令人不安。 This is what Chrome does.这就是 Chrome 所做的。
Safari on the other hand uses the values in the viewBox representing the width and height .另一方面,Safari 使用viewBox的值来表示widthheight This kind of makes sense, but is problematic with various practice (eg it's quite common to use a viewBox of 0 0 1 1 for easier absolute positioning in the SVG).这种是有道理的,但在各种实践中都有问题(例如,使用0 0 1 1的 viewBox 在 SVG 中更容易进行绝对定位是很常见的)。

Firefox simply won't draw your image in this case.在这种情况下,Firefox 根本不会绘制您的图像。

You can avoid this discrepancy by not appending your <img> , by setting your canvas width and height based on the <img> .naturalWidth and .naturalHeight , and by setting your root <svg> element's width and height to absolute values (ie not % ).您可以通过不附加<img> 、根据<img> .naturalWidth.naturalHeight设置画布宽度和高度以及将根<svg>元素的widthheight为绝对值来避免这种差异(即不是% )。
This will give you the most cross-browser experience, and the most predictable one (since with Chrome's behavior, all your user will have different sizes of images).这将为您提供最跨浏览器的体验,也是最可预测的体验(由于 Chrome 的行为,您的所有用户都将拥有不同大小的图像)。

 const svg = `<svg width="374" height="110" ${/* We force width absolute width and height */""} xmlns="http://www.w3.org/2000/svg" viewBox="92.97752808988764 129 374.0449438202247 110" class="PSPDFKit-8s1sbc513t34q38895b4bh3jvn" focusable="false" data-testid="ink-svg" style="left: 0px; top: 0px; width: 100%; height: 100%; opacity: 1; overflow: hidden;"> <rect x="97.97752808988764" y="134" width="364.0449438202247" height="100" class="PSPDFKit-7871rfhyxb7pdmks1n3x7avvta" style="fill: transparent;"/> <g style="fill: transparent;"> <g> <path class="PSPDFKit-47r5zxptykhjqpzqdue9acphtz PSPDFKit-448ncr5muhrpc8p8yvady51emc PSPDFKit-Smooth-Lines" d="M 212.7638508020482,166.04059441826746 C 183.6,160.7 154.5,155.4 135.6,152.3 C 116.7,149.1 107.9,148.2 104.0,149.9 C 100.2,151.5 101.1,155.9 103.3,160.7 C 105.5,165.6 108.9,170.9 116.4,176.2 C 123.9,181.5 135.6,186.8 142.9,187.1 C 150.2,187.3 153.1,182.5 155.5,177.6 C 157.9,172.8 159.9,168.0 161.1,165.3 C 162.3,162.7 162.8,162.2 165.7,165.8 C 168.6,169.4 173.9,177.2 180.7,185.4 C 187.5,193.6 195.8,202.3 202.1,207.6 C 208.4,212.9 212.8,214.9 218.3,215.6 C 223.9,216.3 230.7,215.8 235.6,212.9 C 240.4,210.0 243.3,204.7 246.3,197.2 C 249.2,189.7 252.1,180.1 253.5,175.0 C 255.0,169.9 255.0,169.4 255.2,169.2 C 255.5,168.9 256.0,168.9 256.9,169.4 C 257.9,169.9 259.4,170.9 261.5,171.8 C 263.7,172.8 266.6,173.8 269.8,174.3 C 272.9,174.7 276.3,174.7 279.3,174.0 C 282.2,173.3 284.6,171.8 286.5,169.9 C 288.5,168.0 289.9,165.6 290.9,161.2 C 291.9,156.9 292.4,150.6 290.2,146.0 C 288.0,141.4 283.1,138.5 277.8,137.0 C 272.5,135.6 266.6,135.6 263.5,135.6 C 260.3,135.6 259.8,135.6 259.4,136.1 C 258.9,136.6 258.4,137.5 261.3,140.9 C 264.2,144.3 270.5,150.1 283.9,156.1 C 297.2,162.2 317.6,168.5 329.5,171.6 C 341.4,174.7 344.8,174.7 350.8,174.3 C 356.9,173.8 365.7,172.8 370.3,172.1 C 374.9,171.4 375.4,170.9 375.6,172.3 C 375.8,173.8 375.8,177.2 375.8,182.7 C 375.8,188.3 375.8,196.0 375.6,203.5 C 375.4,211.0 374.9,218.2 374.9,223.1 C 374.9,227.9 375.4,230.3 379.7,231.5 C 384.1,232.7 392.3,232.7 400.6,232.2 C 408.8,231.8 417.1,230.8 425.6,229.6 C 434.1,228.4 442.8,226.9 448.6,226.0 C 454.5,225.0 457.4,224.5 460.3,224.0" data-testid="ink-path" style="stroke: rgb(0, 0, 0); stroke-width: 4px; pointer-events: none;"/> <path class="PSPDFKit-47r5zxptykhjqpzqdue9acphtz PSPDFKit-448ncr5muhrpc8p8yvady51emc PSPDFKit-Smooth-Lines" stroke="transparent" d="M 212.7638508020482,166.04059441826746 C 183.6,160.7 154.5,155.4 135.6,152.3 C 116.7,149.1 107.9,148.2 104.0,149.9 C 100.2,151.5 101.1,155.9 103.3,160.7 C 105.5,165.6 108.9,170.9 116.4,176.2 C 123.9,181.5 135.6,186.8 142.9,187.1 C 150.2,187.3 153.1,182.5 155.5,177.6 C 157.9,172.8 159.9,168.0 161.1,165.3 C 162.3,162.7 162.8,162.2 165.7,165.8 C 168.6,169.4 173.9,177.2 180.7,185.4 C 187.5,193.6 195.8,202.3 202.1,207.6 C 208.4,212.9 212.8,214.9 218.3,215.6 C 223.9,216.3 230.7,215.8 235.6,212.9 C 240.4,210.0 243.3,204.7 246.3,197.2 C 249.2,189.7 252.1,180.1 253.5,175.0 C 255.0,169.9 255.0,169.4 255.2,169.2 C 255.5,168.9 256.0,168.9 256.9,169.4 C 257.9,169.9 259.4,170.9 261.5,171.8 C 263.7,172.8 266.6,173.8 269.8,174.3 C 272.9,174.7 276.3,174.7 279.3,174.0 C 282.2,173.3 284.6,171.8 286.5,169.9 C 288.5,168.0 289.9,165.6 290.9,161.2 C 291.9,156.9 292.4,150.6 290.2,146.0 C 288.0,141.4 283.1,138.5 277.8,137.0 C 272.5,135.6 266.6,135.6 263.5,135.6 C 260.3,135.6 259.8,135.6 259.4,136.1 C 258.9,136.6 258.4,137.5 261.3,140.9 C 264.2,144.3 270.5,150.1 283.9,156.1 C 297.2,162.2 317.6,168.5 329.5,171.6 C 341.4,174.7 344.8,174.7 350.8,174.3 C 356.9,173.8 365.7,172.8 370.3,172.1 C 374.9,171.4 375.4,170.9 375.6,172.3 C 375.8,173.8 375.8,177.2 375.8,182.7 C 375.8,188.3 375.8,196.0 375.6,203.5 C 375.4,211.0 374.9,218.2 374.9,223.1 C 374.9,227.9 375.4,230.3 379.7,231.5 C 384.1,232.7 392.3,232.7 400.6,232.2 C 408.8,231.8 417.1,230.8 425.6,229.6 C 434.1,228.4 442.8,226.9 448.6,226.0 C 454.5,225.0 457.4,224.5 460.3,224.0" data-testid="clickable-path" style="stroke-width: 5px;"/> </g> </g> </svg>`; svgToPng(svg, (imgData) => { const pngImage = document.createElement('img'); pngImage.src = imgData; }); function svgToPng(svg, callback) { const url = getSvgUrl(svg); svgUrlToPng(url, (imgData) => { callback(imgData); URL.revokeObjectURL(url); }); } function getSvgUrl(svg) { return URL.createObjectURL(new Blob([svg], { type: 'image/svg+xml' })); } function svgUrlToPng(svgUrl, callback) { const svgImage = document.createElement('img'); // do not append the <img> svgImage.onload = function() { const canvas = document.createElement('canvas'); canvas.width = svgImage.naturalWidth; canvas.height = svgImage.naturalHeight; const canvasCtx = canvas.getContext('2d'); canvasCtx.drawImage(svgImage, 0, 0); // show the <canvas> to debug document.body.append(canvas); const imgData = canvas.toDataURL('image/png'); callback(imgData); }; svgImage.src = svgUrl; }
 canvas { background: chocolate; }

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

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