如何真正翻转HTML Canvas 使toBlob导出的Blob数据同步旋转180度
Canvas底层180度旋转实现方案(导出Blob/复制剪贴板生效)
所有方案均直接修改Canvas存储的原始像素数据,不存在仅视觉翻转、导出内容不匹配的问题,适配传真查看器场景下复制TIFF页到剪贴板的需求。
方案1:离屏快照+上下文变换重绘(推荐,性能最优)
该方案通过离屏画布暂存原始内容,通过2D上下文的坐标变换直接把旋转后的内容绘制回原画布,全程同步执行,无资源加载等待,大尺寸传真页处理速度快。
/** * 原地旋转Canvas内容180度,修改直接固化到画布底层像素 * @param {HTMLCanvasElement} canvas 目标画布元素 */ function rotateCanvas180(canvas) { const ctx = canvas.getContext('2d') const { width, height } = canvas // 创建同尺寸离屏画布,暂存当前画布的完整内容 const offscreen = document.createElement('canvas') offscreen.width = width offscreen.height = height const offscreenCtx = offscreen.getContext('2d') offscreenCtx.drawImage(canvas, 0, 0) // 清空原画布,通过坐标变换绘制旋转后的内容 ctx.clearRect(0, 0, width, height) ctx.save() ctx.translate(width / 2, height / 2) ctx.rotate(Math.PI) ctx.drawImage(offscreen, -width / 2, -height / 2) ctx.restore() // 函数执行完成后,画布底层像素已经是180度旋转后的状态 // 后续直接调用 canvas.toBlob() 即可拿到正确方向的Blob用于剪贴板写入 }
方案2:直接操作像素缓冲区(最底层可控)
该方案直接读取Canvas的ImageData像素数组,手动计算每个像素旋转180度后的位置,重写整个像素缓冲区,完全不依赖上下文绘制逻辑,效果100%可控,缺点是高分辨率大尺寸画布处理性能略低于方案1。
/** * 通过像素数组操作实现Canvas180度旋转,直接修改底层像素数据 * @param {HTMLCanvasElement} canvas 目标画布元素 */ function rotateCanvas180ByPixel(canvas) { const ctx = canvas.getContext('2d') const { width, height } = canvas // 读取画布全量像素数据 const sourceImgData = ctx.getImageData(0, 0, width, height) const sourcePixels = sourceImgData.data const rotatedPixels = new Uint8ClampedArray(sourcePixels.length) // 遍历每个像素,计算旋转后的对应位置 for (let y = 0; y < height; y++) { for (let x = 0; x < width; x++) { const targetX = width - 1 - x const targetY = height - 1 - y // 每个像素占4个字节:R、G、B、Alpha通道 const sourceIdx = (y * width + x) * 4 const targetIdx = (targetY * width + targetX) * 4 rotatedPixels[targetIdx] = sourcePixels[sourceIdx] rotatedPixels[targetIdx + 1] = sourcePixels[sourceIdx + 1] rotatedPixels[targetIdx + 2] = sourcePixels[sourceIdx + 2] rotatedPixels[targetIdx + 3] = sourcePixels[sourceIdx + 3] } } // 将旋转后的像素数据写回画布 const rotatedImgData = new ImageData(rotatedPixels, width, height) ctx.putImageData(rotatedImgData, 0, 0) // 执行完成后画布像素已完全替换,toBlob导出结果为正确方向 }
避坑说明:不要使用CSS
transform: rotate(180deg)或者仅在临时绘制时设置上下文rotate、不把结果固化到画布的写法,这类方案仅修改页面上的视觉显示效果,不会改动Canvas实际存储的像素数据,调用toBlob导出时自然不会携带旋转状态,就是之前遇到的显示和导出内容不一致的问题。
使用流程
- tiff.js将单页传真渲染到独立Canvas后,判断页面是否倒置
- 对倒置的页面调用上述任意一个旋转函数处理对应Canvas
- 处理完成后再调用
canvas.toBlob()获取Blob写入剪贴板,此时页面显示、导出Blob、剪贴板内容方向完全一致
内容的提问来源于stack exchange,提问作者UserZer0
相关产品推荐
相关产品推荐

