o2team / H5Skills

移动端开发技巧集合
831 stars 80 forks source link

使用 exif.js 和 html2canvas 遇到的问题 #22

Open ONE-SUNDAY opened 7 years ago

ONE-SUNDAY commented 7 years ago

使用到的库

将拍摄的图像绘制到 Canvas 后,图像方向不对

在微信中使用 <input type="file" multiple accept="image/*"> 传入照片后,绘制到 Canvas 中时会发现绘制的图像方向不对(手 Q 端貌似不会存在这个问题),这时需要使用 exif.js 来解决。

Exif.js 提供了 JavaScript 读取图像的原始数据的功能扩展,例如:拍照方向、相机设备型号、拍摄时间、ISO 感光度、GPS 地理位置等数据。

<input class="uploadBtn" type="file" multiple accept="image/*">
document.querySelector(".uploadBtn").addEventListener("change", previewImgFile, false);

function previewImgFile() {

    var _files = files || event.target.files;
    var _index = index || 0;
    var reader = new FileReader();

    reader.onload = function(event) {

        var image = new Image();
            image.src = event.target.result;

        var orientation;

        image.onload = function() {

            EXIF.getData(image, function() { // 获取图像的数据

                EXIF.getAllTags(this); // 获取图像的全部数据,值以对象的方式返回
                orientation = EXIF.getTag(this, "Orientation"); // 获取图像的拍摄方向

                var rotateCanvas = document.createElement("canvas"),
                    rotateCtx = rotateCanvas.getContext("2d");

                // 针对图像方向进行处理
                switch (orientation) {

                    case 1 :
                        rotateCanvas.width = image.width;
                        rotateCanvas.height = image.height;
                        rotateCtx.drawImage(image, 0, 0, image.width, image.height);
                        break;
                    case 6 : // 顺时针 90 度
                        rotateCanvas.width = image.height;
                        rotateCanvas.height = image.width;
                        rotateCtx.translate(0, 0);
                        rotateCtx.rotate(90 * Math.PI / 180);
                        rotateCtx.drawImage(image, 0, -image.height, image.width, image.height);
                        break;
                    case 8 :
                        rotateCanvas.width = image.height;
                        rotateCanvas.height = image.width;
                        rotateCtx.translate(0, 0);
                        rotateCtx.rotate(-90 * Math.PI / 180);
                        rotateCtx.drawImage(image, -image.width, 0, image.width, image.height);
                        break;
                    case 3 : // 180 度
                        rotateCanvas.width = image.width;
                        rotateCanvas.height = image.height;
                        rotateCtx.translate(0, 0);
                        rotateCtx.rotate(Math.PI);
                        rotateCtx.drawImage(image, -image.width, -image.height, image.width, image.height);
                        break;
                    default :
                        rotateCanvas.width = image.width;
                        rotateCanvas.height = image.height;
                        rotateCtx.drawImage(image, 0, 0, image.width, image.height);

                }

                var rotateBase64 = rotateCanvas.toDataURL("image/jpeg", 0.5);

            });

        }

    }

    reader.readAsDataURL(_files[_index]);

}

html2canvas 使用过程中遇到的问题

1、图片模糊

默认生成的 Canvas 是 1 倍图,在移动端 Retina 屏幕下显示模糊,可以通过 2 倍图的方式解决:

var stageWidth = $(".stage").width(),
    stageHeight = $(".stage").height();

var retinaCanvas = document.createElement("canvas");
retinaCanvas.width = stageWidth * 2;
retinaCanvas.height = stageHeight * 2;
retinaCanvas.style.width = stageWidth + "px";
retinaCanvas.style.height = stageHeight + "px";

var ctx = retinaCanvas.getContext("2d");
ctx.scale(2, 2);

html2canvas(document.querySelector(".stage"), {
    canvas: retinaCanvas,
    onrendered: function(canvas) {
        var base64 = canvas.toDataURL(); // 返回 base64
    }
});

2、图片偏移

html2canvas 是解析 DOM 元素实际的样式来生成图片,如果对元素位置进行调整,例如设置了 topleft 或者 margin-topmargin-left 的样式会导致生成的图片偏移。

ctx.transform(-x, -y); // 计算一下偏移的值,通过 transform 方法来修正回去

3、ICON 模糊

即使是使用了 2 倍图,生成后的图片里的 ICON 还是模糊,可以用 SVG 的方式去代替图片 ICON。

4、不支持设置 border-radius 的元素

如果你需要在一个头像中设置 border-radius: 50% 在转为图片后,你会发现并不成功,解决方法在源码 html2canvas.js 中加入以下代码:

tlh = borderRadius[0][0],
tlv = borderRadius[0][1],
trh = borderRadius[1][0],
trv = borderRadius[1][1],
brh = borderRadius[2][0],
brv = borderRadius[2][1],
blh = borderRadius[3][0],
blv = borderRadius[3][1];

/* S 插入这段代码 */
var halfHeight = Math.floor(height / 2);

tlh = tlh > halfHeight ? halfHeight : tlh;
tlv = tlv > halfHeight ? halfHeight : tlv;
trh = trh > halfHeight ? halfHeight : trh;
trv = trv > halfHeight ? halfHeight : trv;
brh = brh > halfHeight ? halfHeight : brh;
brv = brv > halfHeight ? halfHeight : brv;
blh = blh > halfHeight ? halfHeight : blh;
blv = blv > halfHeight ? halfHeight : blv;
/* E 插入这段代码 */

var topWidth = width - trh,
    rightHeight = height - brv,
    bottomWidth = width - brh,
    leftHeight = height - blv;
afdr commented 5 years ago

图片偏移的应该是 ctx.translate(-x, -y);

Sniper-2 commented 5 years ago

优秀

sven713 commented 4 years ago

👍,碰到类似问题参考博主解决了