小程序webview嵌入H5项目完美实现图片上传至阿里云OSS,上传前实现图片压缩,角度校正。

小程序webview嵌入H5项目完美实现图片上传至阿里云OSS,上传前实现图片压缩,角度校正。

VUE项目用的插件是vant,开始是想用vant的上传图片插件,可是他在选择图片的时候非常慢,用的是打开相册不像在微信公众里面选择图片那种样式。

后面是用微信SDK选择图片的方法chooseImage,但是微信小程序webview嵌入H5里面的SDK只支持选择图片不支持wx.uploadFile

所以只能自己用axios,但是axios是已经封装统一请求接口了,里面有很多头参数以及默认自带的['Content-Type'] = 'application/x-www-form-urlencoded',所以总是上传不了。

后面干脆使用JQUERY 来来上传就成功了。值得注意的是压缩图片的JS代码较多,花了不少时间。

实现思路:

api 是请求接口的请注意,即封装的 axios

IOS角度旋转问题用到的 exif.js

/**
 * Minified by jsDelivr using UglifyJS v3.3.25.
 * Original file: /npm/[email protected]/exif.js
 * 
 * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
 */
(function(){var d=!1,l=function(e){return e instanceof l?e:this instanceof l?void(this.EXIFwrapped=e):new l(e)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=l),exports.EXIF=l):this.EXIF=l;var u=l.Tags={36864:"ExifVersion",40960:"FlashpixVersion",40961:"ColorSpace",40962:"PixelXDimension",40963:"PixelYDimension",37121:"ComponentsConfiguration",37122:"CompressedBitsPerPixel",37500:"MakerNote",37510:"UserComment",40964:"RelatedSoundFile",36867:"DateTimeOriginal",36868:"DateTimeDigitized",37520:"SubsecTime",37521:"SubsecTimeOriginal",37522:"SubsecTimeDigitized",33434:"ExposureTime",33437:"FNumber",34850:"ExposureProgram",34852:"SpectralSensitivity",34855:"ISOSpeedRatings",34856:"OECF",37377:"ShutterSpeedValue",37378:"ApertureValue",37379:"BrightnessValue",37380:"ExposureBias",37381:"MaxApertureValue",37382:"SubjectDistance",37383:"MeteringMode",37384:"LightSource",37385:"Flash",37396:"SubjectArea",37386:"FocalLength",41483:"FlashEnergy",41484:"SpatialFrequencyResponse",41486:"FocalPlaneXResolution",41487:"FocalPlaneYResolution",41488:"FocalPlaneResolutionUnit",41492:"SubjectLocation",41493:"ExposureIndex",41495:"SensingMethod",41728:"FileSource",41729:"SceneType",41730:"CFAPattern",41985:"CustomRendered",41986:"ExposureMode",41987:"WhiteBalance",41988:"DigitalZoomRation",41989:"FocalLengthIn35mmFilm",41990:"SceneCaptureType",41991:"GainControl",41992:"Contrast",41993:"Saturation",41994:"Sharpness",41995:"DeviceSettingDescription",41996:"SubjectDistanceRange",40965:"InteroperabilityIFDPointer",42016:"ImageUniqueID"},c=l.TiffTags={256:"ImageWidth",257:"ImageHeight",34665:"ExifIFDPointer",34853:"GPSInfoIFDPointer",40965:"InteroperabilityIFDPointer",258:"BitsPerSample",259:"Compression",262:"PhotometricInterpretation",274:"Orientation",277:"SamplesPerPixel",284:"PlanarConfiguration",530:"YCbCrSubSampling",531:"YCbCrPositioning",282:"XResolution",283:"YResolution",296:"ResolutionUnit",273:"StripOffsets",278:"RowsPerStrip",279:"StripByteCounts",513:"JPEGInterchangeFormat",514:"JPEGInterchangeFormatLength",301:"TransferFunction",318:"WhitePoint",319:"PrimaryChromaticities",529:"YCbCrCoefficients",532:"ReferenceBlackWhite",306:"DateTime",270:"ImageDescription",271:"Make",272:"Model",305:"Software",315:"Artist",33432:"Copyright"},f=l.GPSTags={0:"GPSVersionID",1:"GPSLatitudeRef",2:"GPSLatitude",3:"GPSLongitudeRef",4:"GPSLongitude",5:"GPSAltitudeRef",6:"GPSAltitude",7:"GPSTimeStamp",8:"GPSSatellites",9:"GPSStatus",10:"GPSMeasureMode",11:"GPSDOP",12:"GPSSpeedRef",13:"GPSSpeed",14:"GPSTrackRef",15:"GPSTrack",16:"GPSImgDirectionRef",17:"GPSImgDirection",18:"GPSMapDatum",19:"GPSDestLatitudeRef",20:"GPSDestLatitude",21:"GPSDestLongitudeRef",22:"GPSDestLongitude",23:"GPSDestBearingRef",24:"GPSDestBearing",25:"GPSDestDistanceRef",26:"GPSDestDistance",27:"GPSProcessingMethod",28:"GPSAreaInformation",29:"GPSDateStamp",30:"GPSDifferential"},g=l.IFD1Tags={256:"ImageWidth",257:"ImageHeight",258:"BitsPerSample",259:"Compression",262:"PhotometricInterpretation",273:"StripOffsets",274:"Orientation",277:"SamplesPerPixel",278:"RowsPerStrip",279:"StripByteCounts",282:"XResolution",283:"YResolution",284:"PlanarConfiguration",296:"ResolutionUnit",513:"JpegIFOffset",514:"JpegIFByteCount",529:"YCbCrCoefficients",530:"YCbCrSubSampling",531:"YCbCrPositioning",532:"ReferenceBlackWhite"},m=l.StringValues={ExposureProgram:{0:"Not defined",1:"Manual",2:"Normal program",3:"Aperture priority",4:"Shutter priority",5:"Creative program",6:"Action program",7:"Portrait mode",8:"Landscape mode"},MeteringMode:{0:"Unknown",1:"Average",2:"CenterWeightedAverage",3:"Spot",4:"MultiSpot",5:"Pattern",6:"Partial",255:"Other"},LightSource:{0:"Unknown",1:"Daylight",2:"Fluorescent",3:"Tungsten (incandescent light)",4:"Flash",9:"Fine weather",10:"Cloudy weather",11:"Shade",12:"Daylight fluorescent (D 5700 - 7100K)",13:"Day white fluorescent (N 4600 - 5400K)",14:"Cool white fluorescent (W 3900 - 4500K)",15:"White fluorescent (WW 3200 - 3700K)",17:"Standard light A",18:"Standard light B",19:"Standard light C",20:"D55",21:"D65",22:"D75",23:"D50",24:"ISO studio tungsten",255:"Other"},Flash:{0:"Flash did not fire",1:"Flash fired",5:"Strobe return light not detected",7:"Strobe return light detected",9:"Flash fired, compulsory flash mode",13:"Flash fired, compulsory flash mode, return light not detected",15:"Flash fired, compulsory flash mode, return light detected",16:"Flash did not fire, compulsory flash mode",24:"Flash did not fire, auto mode",25:"Flash fired, auto mode",29:"Flash fired, auto mode, return light not detected",31:"Flash fired, auto mode, return light detected",32:"No flash function",65:"Flash fired, red-eye reduction mode",69:"Flash fired, red-eye reduction mode, return light not detected",71:"Flash fired, red-eye reduction mode, return light detected",73:"Flash fired, compulsory flash mode, red-eye reduction mode",77:"Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected",79:"Flash fired, compulsory flash mode, red-eye reduction mode, return light detected",89:"Flash fired, auto mode, red-eye reduction mode",93:"Flash fired, auto mode, return light not detected, red-eye reduction mode",95:"Flash fired, auto mode, return light detected, red-eye reduction mode"},SensingMethod:{1:"Not defined",2:"One-chip color area sensor",3:"Two-chip color area sensor",4:"Three-chip color area sensor",5:"Color sequential area sensor",7:"Trilinear sensor",8:"Color sequential linear sensor"},SceneCaptureType:{0:"Standard",1:"Landscape",2:"Portrait",3:"Night scene"},SceneType:{1:"Directly photographed"},CustomRendered:{0:"Normal process",1:"Custom process"},WhiteBalance:{0:"Auto white balance",1:"Manual white balance"},GainControl:{0:"None",1:"Low gain up",2:"High gain up",3:"Low gain down",4:"High gain down"},Contrast:{0:"Normal",1:"Soft",2:"Hard"},Saturation:{0:"Normal",1:"Low saturation",2:"High saturation"},Sharpness:{0:"Normal",1:"Soft",2:"Hard"},SubjectDistanceRange:{0:"Unknown",1:"Macro",2:"Close view",3:"Distant view"},FileSource:{3:"DSC"},Components:{0:"",1:"Y",2:"Cb",3:"Cr",4:"R",5:"G",6:"B"}};function i(e){return!!e.exifdata}function r(i,o){function t(e){var t=p(e);i.exifdata=t||{};var n=function(e){var t=new DataView(e);d&&console.log("Got file of length "+e.byteLength);if(255!=t.getUint8(0)||216!=t.getUint8(1))return d&&console.log("Not a valid JPEG"),!1;var n=2,r=e.byteLength;for(;n")+8,u=(s=s.substring(s.indexOf("e.byteLength)return{};var u=P(e,t,t+l,g,r);if(u.Compression)switch(u.Compression){case 6:if(u.JpegIFOffset&&u.JpegIFByteCount){var c=t+u.JpegIFOffset,d=u.JpegIFByteCount;u.blob=new Blob([new Uint8Array(e.buffer,c,d)],{type:"image/jpeg"})}break;case 1:console.log("Thumbnail image format is TIFF, which is not implemented.");break;default:console.log("Unknown thumbnail image format '%s'",u.Compression)}else 2==u.PhotometricInterpretation&&console.log("Thumbnail image format is RGB, which is not implemented.");return u}(e,s,l,n),r}function b(e){var t={};if(1==e.nodeType){if(0

 

1、首先初始化微信SDK   wxInit.js

/**微信初始化***/
const wxInit = async(callback) = >{
    var url = location.href.split('#')[0];
    const json = await api.getSgture({
        q: {
            url: url
        },
        loading: false
    });
    if (json.returnCode == 0) {
        wx.config({
            debug: false,
            appId: json.result.appid,
            timestamp: json.result.timestamp,
            nonceStr: json.result.noncestr,
            signature: json.result.sgture,
            jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData', 'chooseImage', 'previewImage']
        });
        wx.ready(function() {
            callback();
        });
    }
}

export default{ wxInit }

2、图片压缩上传JS ,上传用的JQUERY,我发现用axios 做上传老是报跨域问题,果断放弃,用JQUERY方便

import wx from 'weixin-js-sdk';
import { Toast }
from 'vant';
import api from '@/api/api';
import $ from "jquery";

//公从号选择图片转换为base64
function wxGetLocalImgData(localId, callback) {
    wx.getLocalImgData({
        localId: localId,
        // 图片的localID
        success: res = >{
            let name = localId.substr(23, localId.length);
            var localData = res.localData;
            if (localData.indexOf('data:image') != 0) {
                localData = 'data:image/jpeg;base64,' + localData;
            }
            localData = localData.replace(/\r|\n/g, '').replace('data:image/jgp', 'data:image/jpeg');
            let base64 = localData.toString().split(',')[1];
            base64ToBlob({
                b64data: base64,
                name: name + '.jpg',
                contentType: 'image/jpg'
            }).then(blob = >{
                callback(blob);
            });
        }
    })
}

//BlobUrl转blob数据  
function objectURLToBlob(url, callback) {
    var http = new XMLHttpRequest();
    http.open("GET", url, true);
    http.responseType = "blob";
    http.onload = function(e) {
        if (this.status == 200 || this.status === 0) {
            callback(this.response)
        }
    };
    http.send()
}

/**H5图片压缩 返回base64 */
function dealImage(path, file, obj, callback) {
    var img = new Image();
    img.src = path;
    img.onload = function() {
        var that = this;
        let imgMaxWidth = 1024; //图片最大宽
        let imgMaxHeight = 1440; //图片最大高
        let imgw = that.width;
        let imgh = that.height;
        let canvasW = imgw;
        let canvasH = imgh;
        if (imgw > imgh && imgw > imgMaxWidth) {
            canvasW = imgMaxWidth;
            canvasH = parseInt(imgMaxWidth * (imgh / imgw));
        } else if (imgw < imgh && imgh > imgMaxHeight) {
            canvasH = imgMaxHeight;
            canvasW = parseInt(imgMaxHeight * (imgw / imgh));
        } else if (imgw == imgh && imgw > imgMaxWidth) {
            canvasW = imgMaxWidth;
            canvasH = imgMaxWidth;
        }
        //生成canvas
        var canvas = document.createElement('canvas');
        var ctx = canvas.getContext('2d');
        canvas.width = canvasW;
        canvas.height = canvasH;
        let EXIF = require('@/util/exif-js.js');
        EXIF.getData(file,
        function() {
            let Orientation = EXIF.getTag(this, 'Orientation');
            if (typeof(Orientation) == 'undefined') {
                ctx.drawImage(that, 0, 0, canvasW, canvasH);
            } else {
                let w = canvasW,
                h = canvasH;
                switch (Orientation) {
                case 6:
                    //需要顺时针(向右)90度旋转
                    canvas.height = w;
                    canvas.width = h;
                    ctx.rotate(Math.PI / 180 * 90);
                    ctx.drawImage(that, 0, -h, w, h);
                    break;

                case 8:
                    //需要逆时针(向左)90度旋转	
                    canvas.height = w;
                    canvas.width = h;
                    ctx.rotate(3 * Math.PI / 2);
                    ctx.drawImage(that, -w, 0, w, h);
                    break;

                case 3:
                    //需要180度旋转 转两次
                    ctx.rotate(Math.PI);
                    ctx.drawImage(that, -w, -h, w, h);
                    break;

                default:
                    ctx.drawImage(that, 0, 0, w, h);
                    break;
                }
            }
            var base64 = canvas.toDataURL('image/jpeg', 1);
            callback(base64);
        })
    }
}

/****base64转Blob***/
function base64ToBlob({
    b64data = '',
    name = '',
    contentType = '',
    sliceSize = 512
} = {}) {
    return new Promise((resolve, reject) = >{
        // 使用 atob() 方法将数据解码
        let byteCharacters = atob(b64data);
        let byteArrays = [];
        for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
            let slice = byteCharacters.slice(offset, offset + sliceSize);
            let byteNumbers = [];
            for (let i = 0; i < slice.length; i++) {
                byteNumbers.push(slice.charCodeAt(i));
            }
            // 8 位无符号整数值的类型化数组。内容将初始化为 0。
            // 如果无法分配请求数目的字节,则将引发异常。
            byteArrays.push(new Uint8Array(byteNumbers));
        }
        let result = new Blob(byteArrays, {
            type: contentType
        }) result = Object.assign(result, {
            // 这里一定要处理一下 URL.createObjectURL
            preview: URL.createObjectURL(result),
            name: name
        });
        resolve(result)
    })
}

/** base64转file
		* filename图片的名字,dataurl是base64地址
		*/
function dataURLtoFile(dataurl, filename) {
    var arr = dataurl.split(','),
    mime = arr[0].match(/:(.*?);/)[1],
    bstr = atob(arr[1]),
    n = bstr.length,
    u8arr = new Uint8Array(n);
    while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
    }
    return new File([u8arr], filename, {
        type: mime
    });
}

//h5上传图片处理  res图片资源, callback返回函数
function h5uploadDo(url, callback) {
    var that = this;
    let i = url.lastIndexOf('/');
    let name = url.substr(i + 1, url.length);
    objectURLToBlob(url,
    function(blob) {
        let file = new window.File([blob], name + '.jpg', {
            type: 'jpg'
        });
        let reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onload = function(e) {
            console.log(file, 1111);
            dealImage(this.result, file, {
                width: 1440
            },
            function(base) {
                let file2 = dataURLtoFile(base, name);
                let arr = [];
                arr.push({
                    name: name + '.jpg',
                    path: file2,
                    size: 500
                });
                callback(arr);
            });
        };
    });
}

//上传图片
const uploadImg = async(id, arr, type, callback) = >{
    var that = this const json = await api.getOssPolicy({
        m: 'post',
        q: {
            id: id,
            fileType: type,
            originalFileInfoArr: JSON.stringify(arr)
        }
    });
    if (json.returnCode == 0) {
        var AuthMsg = json.result
        var imgExit = arr[0].name.split('.')[1];
        var ossKey = AuthMsg.dir + AuthMsg.uploadNameList[0] + '.' + imgExit;
        var imgurl = AuthMsg.host + '/' + ossKey;
        Toast.loading("上传中...");
        // 添加签名信息
        var ossData = new FormData();
        ossData.append('OSSAccessKeyId', AuthMsg.accessKeyId);
        ossData.append('policy', AuthMsg.policy);
        ossData.append('Signature', AuthMsg.postSignature);
        ossData.append('key', ossKey);
        ossData.append('callback', AuthMsg.callback);
        ossData.append('file', arr[0].path);
        ossData.append('success_action_status', 200);
        $.ajax({
            url: AuthMsg.host,
            data: ossData,
            processData: false,
            contentType: false,
            type: 'POST',
            success: function(res) {
                Toast.clear();
                callback(imgurl);
            },
            error: function(err) {
                Toast.clear();
                console.log(err);
            }
        })
    }
}

export default {
        wxGetLocalImgData,
        h5uploadDo,
        uploadImg
    }

3、在上传页中使用微信SDK和上传JS



import wx from 'weixin-js-sdk';
import wxInit from '@/util/wxInit';
import compress from '@/util/compress';
export
default {       
        data() {
            return {
                form: {
                   img:'',                   
                }
            }
        },

        mounted() {           
            wxInit.wxInit(); //微信sdk初始化
           
        },

        methods: {

            //选择图片
            selectImg() {
                var that = this;
                this.isup = true;
                wx.chooseImage({
                    count: 1,
                    sizeType: ['original'],
                    success: function(res) {
                        let localIds = res.localIds[0];
                        compress.wxGetLocalImgData(localIds,
                        function(blob) {
                            let url = blob.preview;
                            that.h5uploadDo(url);
                        })
                    },
                })
            },

            //图片压缩
            h5uploadDo(blob) {
                var that = this;
                compress.h5uploadDo(blob,
                function(res) {
                    that.setImgsrc(res);
                })
            },

            setImgsrc(arr) {
                var that = this;
                compress.uploadImg(136, arr, 'userQrcode',function(path) {
                   that.form.img= path
                })
            },
        }
    } < /script>

注: jquery 需要自己安装,vant也需要安装

npm install jquery --save

npm i vant -S

 

 

你可能感兴趣的:(JQUERY,+,JS,+,CSS,小程序webview,上传图片)