上传图片可剪辑 生成带二维码的图片 截屏成一张图片 cropperjs、html2canvas、canvas2image、qrCode

该文章主要介绍了在iOS系统中,由于版本差异可能导致照片旋转的问题,以及如何通过JavaScript实现图片上传、裁剪和生成海报的功能。文章提供了一个包含图片加载检查、二维码生成、图片旋转纠正和使用cropperjs插件进行图片裁剪的完整示例。同时,还涉及到ios13.5以上版本的图片旋转处理策略。
摘要由CSDN通过智能技术生成

项目中复制而出,如有多余代码删除即可

坑:ios系统不同版本相机拍出的照片有点会有旋转 和 拍照时拍摄去比例也有关

本文以ios 13.5 和 照片旋转数 为判断条件

 

            <div class="s-page-content" id="s-page-content">

                <div class="poster_content" id="poster_content" v-show="!isGeneratePosters">
                    <div class="content_top" :style="{'height' : posterImgHeight}">
                        <img class="posters_img select_none"
                            style="height:100%;" 
                            @load="isLoad"
                            :src="postersImg" alt="">

                        <div class="zzc" v-show="!isAddImg"></div>

                        <div class="add_img" v-show="!isAddImg && !isShowUserImgUp">
                            <p @click="addImg" style="color:#fff">上传图片</p>
                            <input id="uploadImg" style="display:none" @change="getImgUrl" type="file" accept="image/jpeg, image/png" />
                        </div>

                    </div>
                    <div class="content_bottom">
                        <div class="text">
                            <!-- <img class="text_title" src="/refactor/public/image/active_posters_title.png" alt=""> -->
                            <p class="text_tips">111111<br>2222</p>
                        </div>
                        <div class="ewm">
                            <!-- 生成二维码 -->
                            <div id="QRCodeNone" style="display:none"></div>
                            <div id="qrcode"></div>
                            <p class="ewm_tips">111111<br>222222</p>
                        </div>
                    </div>
                </div>

                <!-- 存放生成出来的图片 -->
                <div id="canvas_img"></div> 
            </div>

            <div class="bottom_btn">
                <div @click="isImgLoadComplete" v-text="isGeneratePosters ? '图片已生成' : '生成图片'"></div>
            </div>

            <div class="img_loading" v-if="isShowImgLoading">
                <img src="/res/image/data_load.gif" alt="">
            </div>

            <!-- 图片剪辑框 -->
            <div class="s_image_intercept" v-show="isShowTailoring">
                <div class="intercept_content">
                    <div class="intercept_bgn">
                        <p @click="hideTailoring">取消</p>
                        <p @click="sureSava">确定</p>
                    </div>
                        
                    <div class="container">
                        <div class="img-container">
                            <img id="imgT" :src="imgUrl" ref="image" alt=""> 
                        </div>
                        <div class="afterCropper">
                            <img :src="afterImg" alt="">
                        </div>
                    </div>
                </div>
            </div>

 插件引用               vue自行引入

//图片截切插件 cropperjs 文档地址: https://fengyuanchen.github.io/cropper/

<script src="https://cdn.bootcdn.net/ajax/libs/exif-js/2.3.0/exif.js"></script>

<script type="text/javascript" src="/res/js/jquery-2.1.4.min.js"></script>

<script src="https://cdn.bootcdn.net/ajax/libs/cropperjs/1.5.11/cropper.min.js"></script>

//截屏插件

<script type="text/javascript" src="/res/js/html2canvas.js"></script>

<script type="text/javascript" src="/res/js/canvas2image.js"></script>

//生成二维码插件 不需要二维码则不需要

<script type="text/javascript" src="/res/js/qrCode.js"></script>

 变量

        isAddImg: false,
        postersImg: '/refactor/public/image/111.jpg',
        posterImgHeight: 'auto',

        isGeneratePosters: false, //是否生成图片
        isShowUserImgUp: false, //是否显示用户未上传图片
        isShowImgLoading: true,
        appCode: '',

        imgUrl: '/refactor/public/image/active_posters_home.png',
        myCropper: null,
        afterImg: '',
        isShowTailoring: false,

        mounted: function() {

            this.init();
        },
        methods: {
            init: function() {
                this.getEwm(); //获取二维码
                this.initCropper(); //初始话剪切框
            },
            getEwm() {
                var self = this;
                // var url = '';
                // axios.get(url).then(function(data) {
                   self.drawFollowEwm('你的二维码地址');
                // }).catch(function (error) {
                //     console.log(JSON.stringify(error));
                // });
            },
            drawFollowEwm(url) {
                new QRCode(document.getElementById('QRCodeNone'), url);
                
                var myCanvas = document.getElementsByTagName('canvas')[0];
                var img = this.convertCanvasToImage(myCanvas);
                $("#qrcode").append(img);

                var self = this;
                $('#qrcode img').load(function() {
                    self.isShowImgLoading = false;
                })
            },
            convertCanvasToImage(canvas) {
                var image = new Image();
                image.src = canvas.toDataURL("image/jpg");
                return image;
            },
            generateCanvas() {
                // 截屏
                var self = this;
                var content = document.getElementById("poster_content");
                var width = content.offsetWidth; //获取dom 宽度
                var height = content.offsetHeight;

                var scale = 4;
                var canvas = document.createElement("canvas");
                canvas.width = width * scale;
                canvas.height = height * scale;
                canvas.getContext("2d").scale(scale, scale);
                html2canvas(content, {
                    useCORS: true, //允许跨域
                    width: width, //dom 原始宽度
                    height: height,
                    scale: scale,
                    dpi: window.devicePixelRatio,
                    taintTest: false
                }).then((canvas) => {
                    var context = canvas.getContext('2d');
                    // 【重要】关闭抗锯齿
                    context.mozImageSmoothingEnabled = false;
                    context.webkitImageSmoothingEnabled = false;
                    context.msImageSmoothingEnabled = false;
                    context.imageSmoothingEnabled = false;

                    var img = Canvas2Image.convertToJPEG(canvas, canvas.width, canvas.height);
                    document.getElementById("canvas_img").appendChild(img);
                    self.isGeneratePosters = true;
                    setTimeout(function() {
                        self.isShowImgLoading = false;
                    }, 100);

                    $$.browsingHistory('auto_poster', 'activePosters', this.appCode);
                })
            },

            isImgLoadComplete() {
                if(!this.isAddImg) {
                    this.isShowUserImgUp = true;
                    return;
                }

                if(this.isGeneratePosters) {
                    return;
                }
                
                this.isShowImgLoading = true;
                document.getElementById('s-page-content').scrollTop = 0;
                
                this.inspectImgLoad();
            },
            inspectImgLoad() {
                // 检查图片是否全都加载完成
                var self = this;
                var imgdefereds = [];
                var imgs = $("#poster_content img");
                imgs.each(function () {
                    var dfd = $.Deferred();
                    $(this).bind('load', function () {
                        dfd.resolve();
                    }).bind('error', function () {
                        //图片加载错误,加入错误处理
                        // dfd.resolve();
                    })
                    if (this.complete) setTimeout(function () {
                        dfd.resolve();
                    }, 1000);
                    imgdefereds.push(dfd);
                })

                $.when.apply(null, imgdefereds).done(function () {
                    self.generateCanvas();
                    self.posterImgHeight =  $('.posters_img').width() * 1.5 + 'px';
                })
            },
            addImg() {
                $('#uploadImg').attr('type', 'file');
                $('#uploadImg').trigger('click');
            },
            getImgUrl() {
                var file = $('#uploadImg').get(0).files[0];
                var _this = this;
                _this.isShowImgLoading = true;
                EXIF.getData(file, function() { // file input[type=file]的文件

                    EXIF.getAllTags(this);
                    var orientation = EXIF.getTag(this, 'Orientation'); //图片的旋转角度 针对ios

                    var str = navigator.userAgent.toLowerCase(); 
                    var ver = str.match(/cpu iphone os (.*?) like mac os/);  //获取ios 系统版本
                    if(ver) {
                        var editionNum = parseFloat(ver[1].replace(/_/g, '.'));

                        // 注意: ios系统不同版本 横竖屏拍摄的照片会有旋转

                        if(editionNum > 13.5) { // 测试 大于13.5版本不需要旋转 非一定准确
                            _this.setImageUrl(_this.getObjectURL(file));
                            _this.isShowImgLoading = false;
                            return;
                        }
                    }



                    if(!orientation || 1 == orientation) {
                        if(_this.getObjectURL(file)) {
                            _this.setImageUrl(_this.getObjectURL(file));
                            _this.isShowImgLoading = false;
                        }
                        return;
                    }

                    // // 使用FileReader读取文件流,file为上传的文件流
                    const reader = new FileReader();
                    reader.readAsDataURL(file);
                    // /* eslint-disable func-names */
                    // // 箭头函数会改变this,所以这里不能用肩头函数
                    reader.onloadend = function () {

                        // this.result就是转化后的结果
                        const result = this.result;
                        // 将base64添加到图片标签上
                        const img = new Image();
                        img.src = result;
                        img.onload = function () {
                        // 这里添加旋转图片的代码
                            _this.getRotateImg(img, orientation, function(data) {
                                _this.setImageUrl(data);
                                _this.isShowImgLoading = false;
                            });
                        };
                    };
                });
            },
            getRotateImg(img, or, callback) {
                const canvas = document.createElement('canvas');
                const ctx = canvas.getContext('2d');
                // 图片原始大小
                const width = img.width;
                const height = img.height;
                canvas.width = width;
                canvas.height = height;
                ctx.drawImage(img, 0, 0, width, height);

                switch (or) {
                    case 6: // 顺时针旋转90度
                        this.rotateImg(img, 'right', canvas, null, callback);
                        break;
                    case 8: // 逆时针旋转90度
                        this.rotateImg(img, 'left', canvas, null, callback);
                        break;
                    case 3: // 顺时针旋转180度
                        this.rotateImg(img, 'right', canvas, 2, callback);
                        break;
                    default:
                        break;
                }
            },
            rotateImg (img, dir = 'right', canvas, s, callback) {

                s = s ? s : 1;
                const MIN_STEP = 0;
                const MAX_STEP = 3;

                const width = canvas.width || img.width;
                const height = canvas.height || img.height;
                let step = 0;

                if (dir === 'right') {
                    step += s;
                    step > MAX_STEP && (step = MIN_STEP);
                } else {
                    step -= s;
                    step < MIN_STEP && (step = MAX_STEP);
                }

                const degree = step * 90 * Math.PI / 180;
                const ctx = canvas.getContext('2d');

                switch (step) {
                    case 1:
                        canvas.width = height;
                        canvas.height = width;
                        ctx.rotate(degree);
                        ctx.drawImage(img, 0, -height, width, height);
                        callback(canvas.toDataURL("image/jpeg", 0.8));
                        break;
                    case 2:
                        canvas.width = width;
                        canvas.height = height;
                        ctx.rotate(degree);
                        ctx.drawImage(img, -width, -height, width, height);
                        callback(canvas.toDataURL("image/jpeg", 0.8));
                        break;
                    case 3:
                        canvas.width = height;
                        canvas.height = width;
                        ctx.rotate(degree);
                        ctx.drawImage(img, -width, 0, width, height);
                        callback(canvas.toDataURL("image/jpeg", 0.8));
                        break;
                    default:
                        canvas.width = width;
                        canvas.height = height;
                        ctx.drawImage(img, 0, 0, width, height);
                        callback(canvas.toDataURL("image/jpeg", 0.8));
                        break;
                }
            },
            getObjectURL(file) {
                var url = null;   
                if (window.createObjectURL!=undefined) {  
                    url = window.createObjectURL(file) ;  
                } else if (window.URL!=undefined) { // mozilla(firefox)  
                    url = window.URL.createObjectURL(file) ;  
                } else if (window.webkitURL!=undefined) { // webkit or chrome  
                    url = window.webkitURL.createObjectURL(file) ;  
                }  
                return url ;  
            },
            isLoad() {
                this.posterImgHeight =  $('.posters_img').width() * 1.5 + 'px';
            },
            initCropper() {
                var self = this;
                this.myCropper = new Cropper(this.$refs.image, {
                    aspectRatio: 1 / 1.5,
                    viewMode: 1,
                    dragMode: 'move',
                    initialAspectRatio: 1,
                    background: false,

                    autoCropArea: 0.9,
                    zoomOnWheel: false,
                    center: true,
                    movable: true,
                    cropBoxMovable: false,
                })
            },
            setImageUrl(url) {
                $('#uploadImg').attr('type', 'text')
                this.isShowTailoring = true;
                this.myCropper.replace(url, false);
            },
            sureSava() {
                // 截切框 保存的图片
                this.isShowTailoring = false;
                this.postersImg = this.myCropper.getCroppedCanvas({
                    imageSmoothingQuality: 'high'
                }).toDataURL('image/jpeg')

                this.isAddImg = true;
            },
            hideTailoring() {
                this.isShowTailoring = false;
            }
        }

希望对你有帮助!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值