layui upload预览图片旋转90度是因为手机竖拍时exif中orientation值为6(顺时针90°),而layui直接使用未经exif校正的base64数据预览;解决方法是在before钩子中用filereader.readasarraybuffer读取文件,通过exif.js获取orientation,再用canvas按对应规则(如宽高互换、rotate+偏移drawimage)重绘并todataurl输出修正后的图片。
为什么layui upload预览时图片会旋转90度
因为手机(尤其是iphone和部分安卓机型)竖屏拍照时,相机传感器记录的是原始画面,但把方向信息写在exif的orientation字段里——比如6表示“顺时针旋转90度”。layui的preview回调直接用了result(即filereader.readasdataurl()生成的base64),没读exif,也没做canvas旋转校正,所以预览图就歪了。
Layui upload中用EXIF获取Orientation并修正预览
必须在before钩子里拦截文件,用EXIF.getData()读取方向,再用canvas重绘。不能只靠preview回调里的result。
-
EXIF.js需提前引入(建议用精简版,全量版30KB太重) -
before函数里要手动调obj.preview(),否则preview回调不触发 - 拿到
Orientation后,必须用FileReader.readAsArrayBuffer()(不是readAsDataURL)才能让EXIF.getData()正确解析 - 旋转逻辑要覆盖
1(正常)、3(180°)、6(顺时针90°)、8(逆时针90°)四种常见值
示例关键片段:
before: function(obj) {
obj.preview(function(index, file, result) {
const reader = new FileReader();
reader.onload = function(e) {
EXIF.getData(e.target.result, function() {
const orient = EXIF.getTag(this, 'Orientation') || 1;
if (orient === 1) {
$('#demo1').attr('src', result);
} else {
rotateBase64Img(result, orient, function(fixedSrc) {
$('#demo1').attr('src', fixedSrc);
});
}
});
};
reader.readAsArrayBuffer(file); // 注意:这里必须是ArrayBuffer
});
}
rotateBase64Img函数怎么写才不出错
核心是canvas的drawImage坐标偏移和ctx.rotate()配合——光rotate不行,不调整起始点会导致图像被画到画布外。
-
case 6(顺时针90°):canvas宽高互换,ctx.rotate(Math.PI / 2),然后drawImage(img, 0, -img.height, img.width, img.height) -
case 8(逆时针90°):同样宽高互换,ctx.rotate(3 * Math.PI / 2),drawImage(img, -img.width, 0, img.width, img.height) -
case 3(180°):宽高不变,ctx.rotate(Math.PI),drawImage(img, -img.width, -img.height, img.width, img.height) - 所有情况最后都用
canvas.toDataURL('image/jpeg', 0.8)输出,避免base64膨胀
别漏掉安卓5.0+某些三星/小米机型的预览异常
这些机型在input[type=file]选图后,浏览器自己就把预览图转正了(比如自动按EXIF旋转),但Layui的preview回调给的还是原始base64——结果就是“本地预览正常,上传后反而歪了”。这时候得在done阶段再校验一次,或统一走canvas重绘流程,别信result。
真正麻烦的不是旋转本身,而是不同设备对EXIF的读取时机和默认渲染行为不一致——iOS Safari、Chrome Android、旧版UC,表现全不一样。绕开它最稳的方式,是所有图片都走一遍canvas重绘,而不是条件判断。











