- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我最近使用 canvas 将图像转换为 webp,使用:
const dataUrl = canvas.toDataURL('image/webp');
但是对于某些图像,这会花费很多时间,例如 400 毫秒。
我收到了来自 Chrome 的警告,因为它阻止了 UI。
我想使用 Offscreen Canvas 在后台执行该转换。
但是:
1) 我不知道应该使用哪个 Offscreen Canvas : a] 新的 OffscreenCanvas() b] canvas.transferControlToOffscreen()
2) 我在图像对象 (img.src = url) 中加载本地镜像 url 以获取本地镜像的宽度和高度。但我不明白如何将 Image 对象转移到屏幕外的 Canvas,以便能够在 worker 中完成:
ctx.drawImage(img, 0, 0)
因为如果我不传输图像,worker 不知道 img。
最佳答案
您正面临一个 XY and even -Z problem在这里,但每个人都可能有一个有用的答案,所以让我们深入研究。
X。 不要使用 canvas API 进行图像格式转换。 Canvas API 是有损的,无论你做什么,你都会丢失原始图像中的信息,即使你传递无损图像, Canvas 上绘制的图像也不会与原始图像相同。
如果你传递一个已经有损的格式,比如 JPEG,它甚至会添加原始图像中没有的信息:压缩伪影现在是原始位图的一部分,导出算法会将这些视为它应该保留的信息,使你的文件可能比你给它的 JPEG 文件大。
不知道你的用例,很难给你完美的建议,但一般来说,使版本中的不同格式最接近原始图像,一旦它在浏览器中绘制,你至少已经晚了三步。
现在,如果您对此图像进行一些处理,您可能确实想要导出结果。
但是你可能不需要这里的 Web Worker。
是。在您的描述中占用最大阻塞时间的应该是同步 toDataURL()
打电话。
您应该始终使用异步且性能更高的 toBlob()
,而不是 API 中的这个历史错误。方法。在 99% 的情况下,你根本不需要数据 URL,几乎所有你想用数据 URL 做的事情都应该直接用 Blob 来完成。
使用这种方法,剩下的唯一繁重的同步操作就是在 Canvas 上绘画,除非您正在缩小一些巨大的图像,否则这不应该花费 400 毫秒。
但是由于 createImageBitmap,您无论如何都可以在最新的 Canvas 上让它变得更好方法,它允许您异步准备图像,以便完成图像解码,而所有需要完成的实际上只是一个放置像素操作:
large.onclick = e => process('https://upload.wikimedia.org/wikipedia/commons/c/cf/Black_hole_-_Messier_87.jpg');
medium.onclick = e => process('https://upload.wikimedia.org/wikipedia/commons/thumb/c/cf/Black_hole_-_Messier_87.jpg/1280px-Black_hole_-_Messier_87.jpg');
function process(url) {
convertToWebp(url)
.then(prepareDownload)
.catch(console.error);
}
async function convertToWebp(url) {
if(!supportWebpExport())
console.warn("your browser doesn't support webp export, will default to png");
let img = await loadImage(url);
if(typeof window.createImageBitmap === 'function') {
img = await createImageBitmap(img);
}
const ctx = get2DContext(img.width, img.height);
console.time('only sync part');
ctx.drawImage(img, 0,0);
console.timeEnd('only sync part');
return new Promise((res, rej) => {
ctx.canvas.toBlob( blob => {
if(!blob) rej(ctx.canvas);
res(blob);
}, 'image/webp');
});
}
// some helpers
function loadImage(url) {
return new Promise((res, rej) => {
const img = new Image();
img.crossOrigin = 'anonymous';
img.src = url;
img.onload = e => res(img);
img.onerror = rej;
});
}
function get2DContext(width = 300, height=150) {
return Object.assign(
document.createElement('canvas'),
{width, height}
).getContext('2d');
}
function prepareDownload(blob) {
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = 'image.' + blob.type.replace('image/', '');
a.textContent = 'download';
document.body.append(a);
}
function supportWebpExport() {
return get2DContext(1,1).canvas
.toDataURL('image/webp')
.indexOf('image/webp') > -1;
}
<button id="large">convert large image (7,416 × 4,320 pixels)</button>
<button id="medium">convert medium image (1,280 × 746 pixels)</button>
Z。要从 Web Worker 在 OffscreenCanvas 上绘制图像,您将需要上面提到的 createImageBitmap
。实际上,此方法生成的 ImageBitmap 对象是唯一的 图像源 值 drawImage()和 texImage2D() (*) can accept 在 Workers 中可用(所有其他都是 DOM 元素)。
这个ImageBitmap是transferable ,所以你可以从主线程生成它,然后将它发送给你的 Worker 而没有内存成本:
main.js
const img = new Image();
img.onload = e => {
createImageBitmap(img).then(bmp => {
// transfer it to your worker
worker.postMessage({
image: bmp // the key to retrieve it in `event.data`
},
[bmp] // transfer it
);
};
img.src = url;
另一种解决方案是直接从 Worker 获取图像数据,并从获取的 Blob 生成 ImageBitmap 对象:
worker.js
const blob = await fetch(url).then(r => r.blob());
const img = await createImageBitmap(blob);
ctx.drawImage(img,0,0);
请注意,如果您在主页面中将原始图像作为 Blob(例如,来自 <input type="file">),那么甚至不要直接使用 HTMLImageElement 或获取方式发送此 Blob 并从中生成 ImageBitmap。
*texImage2D 实际上接受更多的源图像格式,例如 TypedArrays 和 ImageData 对象,但是这些 TypedArrays 应该代表像素数据,就像 ImageData 一样,并且为了这个像素数据,您可能需要已经使用其他图像源格式之一在某处绘制图像。
关于Javascript加载Image到Offscreen Canvas,进行webp转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55892083/
看到 WebP 图片惊人的缩小(比无损 + alpha 图片的“pngcrushed”PNG 小约 28%),我们希望将 WebP 图片提供给支持 WebP 的浏览器。 如果客户端浏览器支持 WebP
我正在尝试使用 imagemin-webp 而不是使用 将多个 PNG 和 JPG 文件转换为 WebP cwebp 一次转换一个,但由于某种原因它不起作用。 到目前为止我所做的一切: 1- 我安装了
如何将一堆png或webp图片转成webp动画? 我试过了: convert mytiles.png -crop 100x100 +repage tmp.webp 但我只是得到一堆 webp 图像而不
我有这张图片(我在 SGS 9 plus 上拍摄的照片):Uncompressed JPG image .它的大小为 4032 x 3024,重量为 大约 3MB .我用 TinyJPG Compre
此命令将 PNG 序列转换为 JPG 序列:ffmpeg -i in/%8d.png out/%8d.jpg但是,当对 WEBP 使用相同的命令时:ffmpeg -i in/%8d.png out/%
有什么方法可以使用 filepond 将任何图像转换为 webp? 这是我的代码: import vueFilePond, { setOptions } from 'vue-filepond' //
我正在使用 标记以设置具有 WebP 支持的响应式图像。 我正在提取同时具有 .web 的桌面图像和移动图像 URL和 .jpg文件。 对于每种媒体,我给出 .webp版本和 .jpg版本。 我期望的
我的最终目标是检测浏览器是否能够显示 webp 图像。如果是,则将页面上的所有图像替换为其 webp 等效项(位于同一目录中,名称相同,只是扩展名不同) 目前我有一个脚本可以成功检测浏览器是否能够显示
我一直在为网站处理图像,发现 .webp 格式比 .jpeg 或 .png 更紧凑> 在 Docs 上找到更多信息. 现在我有一个包含近 25 张图像的文件夹,我想将所有图像转换为 .webp 格式。
我试图让我的网站更快,但发现将 jpg 和 png 转换为 webp 可能会有所不同,所以我想复制主题目录中的所有图像,包括不同文件夹中子目录中的图像,但保持原始目录流. 在谷歌上搜索后,我在这个网站
我有一个从原始 AR Stickers APK 中提取的动画 webp 文件我想在我的应用程序中显示,以便在 ARCore 中加入。看起来我可以轻松地将 webp 文件的第一帧加载到 ImageVie
我正在看官方WebP lossless bitstream spec.我有一种感觉,该文件缺少一些解释。 让我描述一下规范的一些片段: 1。简介-清晰 2。 Riff header - 清晰 3。转换
我在互联网上搜索了很多,但在网上找不到合适的例子或完整的教程,可以完整教授。所以大家请给我一些好的例子。 我已经在很多地方或网站上尝试过 WEBP 代码,例如与 modernizer 一起使用、检查浏
我查看了 Azure 中的以下文档 ( https://docs.azure.cn/en-us/cdn/cdn-image-processing ),不确定我是否正确阅读。我的问题是,我希望提供从 c
是否有任何工具或脚本可以批量转换动画 webp 图像? 我想从我的动画 webp 图像创建动画缩略图: 调整图像大小 降低质量(有损压缩) 降低帧率 我尝试了 ImageMagick 之类的工具,但它
我想做的事: 我想使用 Flutter 的 CameraController 录制视频,该视频的持续时间与动画 webp 相同。在我的屏幕上方,动画 webp 正在播放,下方有一个 CameraPre
我正在使用如下代码: 我希望的是,当某些版本的 Safari 浏览器不支持 Webp 图像格式时,根据媒体查询回退到以下来源,而不是直接回退到 "
我的 Django 项目应用程序中有上传图像的服务,我需要将所有图像转换为 webp,以优化前端对这些文件的进一步处理。 _convert_to_webp 方法草案: # imports from p
我已经使用以下代码更新了 WordPress 以允许 WebP 上传, function webp_upload_mimes( $existing_mimes ) { $existing_mi
很难找到一个可以查看 WEBP 图像的应用程序。因此,当您将其下载到硬盘时,将其下载为更常见的格式(例如 JPEG 或 PNG)可能会更方便。 那么有没有一种简单的方法可以将 WEBP 保存为更好的文
我是一名优秀的程序员,十分优秀!