图片尺寸异常求助:21600×10800经Canvas读取变10800×5400
问题原因与解决方法
核心原因
你遇到的问题本质是浏览器加载图片时,会根据图片的DPI设置或设备像素比自动调整Image对象的显示尺寸,导致THREE.ImageLoader加载后的image.width和image.height已经是原始文件像素的一半,后续Canvas操作自然沿用了这个缩小后的尺寸。
具体触发场景:
- 图片DPI设置为192(是浏览器默认基准96DPI的2倍),浏览器为保证图片在屏幕上的实际显示大小符合DPI定义,会将Image元素的显示尺寸缩放为原始像素的1/2。
- 高DPI屏幕下,浏览器自动适配设备像素比,对图片显示尺寸进行缩放,导致Image对象的宽高不等于文件原始像素。
解决方法
1. 调整图片DPI为标准值
用图像编辑工具(如Photoshop、GIMP)打开图片,导出时将DPI设置为96(浏览器默认基准),这样浏览器会直接以文件的原始像素作为Image对象的width/height,无需额外处理。
2. 读取图片真实像素尺寸
通过解析图片的EXIF信息获取原始像素尺寸,替代Image对象的width/height。示例代码(针对JPG的简易实现):
async function getImageRealSize(url) { const response = await fetch(url); const arrayBuffer = await response.arrayBuffer(); const dataView = new DataView(arrayBuffer); // 查找JPG的SOF0标记,提取原始宽高 let offset = 2; while (offset < dataView.byteLength) { const marker = dataView.getUint16(offset); if (marker === 0xFFC0) { // SOF0标记 const height = dataView.getUint16(offset + 5); const width = dataView.getUint16(offset + 7); return { width, height }; } offset += 2 + dataView.getUint16(offset + 2); } return null; } // 使用示例 const realSize = await getImageRealSize('./resources/image0.jpg'); const image = await new THREE.ImageLoader().loadAsync('./resources/image0.jpg'); // 基于真实尺寸创建Canvas并绘制 let canvas = new OffscreenCanvas(realSize.width, realSize.height); let context = canvas.getContext('2d'); context.drawImage(image, 0, 0, realSize.width, realSize.height); const data = context.getImageData(0, 0, realSize.width, realSize.height);
3. 手动修正缩放比例(仅适用于已知固定缩放场景)
如果确定图片的缩放比例固定为2(如本例),可直接将Image对象的宽高乘以2恢复原始尺寸:
const image = await new THREE.ImageLoader().loadAsync('./resources/image0.jpg'); const realWidth = image.width * 2; const realHeight = image.height * 2; const map = { data: (() => { let canvas = new OffscreenCanvas(realWidth, realHeight); let context = canvas.getContext('2d'); context.drawImage(image, 0, 0, realWidth, realHeight); return context.getImageData(0, 0, realWidth, realHeight); })(), width: realWidth, height: realHeight };
内容的提问来源于stack exchange,提问作者Spiri
相关产品推荐
相关产品推荐

