この問題は、画像ファイルをアップロードする際に、背景のサイズが 2MB に制限されることが原因で発生しますが、写真を撮るためにカメラをオンにすると、ユーザー エクスペリエンスと機能要件に影響を与えないように、毎分 2MB を超えます。フロントエンドはサイズを圧縮してからバックステージにアップロードする必要があります。
アイデア分析いろいろ調べた結果、画像を圧縮できるのはcanvasだけであることがわかりました。
原理は大まかに次のとおりです。 1. まず画像のファイルをbaseURLに変換します。 2. ファイルを受け取る画像タグを作成し、画像の幅、高さ、比率を取得します。 3. キャンバスを作成し、キャンバスのサイズを設定します。 4. キャンバスに絵を描きます。 5. キャンバスを圧縮し、新しい BaseURL を取得します。 6. BaseURL をファイルに変換します。
前提の機能ファイルファイルをbase64に変換します/*** @param {バイナリ ファイル ストリーム} file * @param {コールバック関数、base64 を返す} fn */function changeFileToBaseURL(file,fn){ // 読み取りファイル オブジェクトを作成します var fileReader = new FileReader(); //ファイルが定義されていない場合は、null を返します。 if(file == unknown) return fn(null); // ファイル file を読み取り、結果は Base64 ビット fileReader.readAsDataURL(file); fileReader.onload = function(){ // Base64 を読み取ります var imgBase64Data = fn(imgBase64Data); } }Base64 をファイル ストリームに変換する
/** * Base64 をファイルに変換 * @param {baseURL} dataurl * @param {ファイル名} filename * @return {ファイル バイナリ ストリーム}*/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], ファイル名, {type:mime});圧縮方式
/*** キャンバス圧縮画像* @param {パラメータ obj} param * @param {ファイル バイナリ ストリーム} param.file が必要* @param {ターゲット圧縮サイズ} param.targetSize は初期割り当て -1 を渡しません* @param {output画像の幅} param.width は初期割り当て値 -1 を渡さず、比例拡大縮小の高さも渡しません* @param {出力画像名} param.fileName は初期割り当て画像を渡しません* @param {圧縮画像度} param.quality は初期割り当て値 0.92 を渡しません。値の範囲 0~1* @param {コールバック関数} param.succ 必須 */function pressImg(param){ //コールバック関数がない場合は実行されません if(param && param.succ){ //Ifファイルが定義されていない場合、null を返します if(param.file == unknown) return param.succ(null); //パラメータに初期値を付加します param.targetSize = param.hasOwnProperty(targetSize)? param.targetSize : -1; param.width = param.hasOwnProperty(width) ? param.fileName = param.hasOwnProperty(fileName) ? param.quality = param.hasOwnProperty(品質) ? param.quality : 0.92; // ファイルの種類を取得します。 = param.file.type; // console.log(fileType) //image/jpeg if(fileType.indexOf(image) == -1){ console.log('画像ファイルを選択してください^_^'); return param.succ(null); } //現在のサイズがターゲットサイズより小さい場合は、直接出力 var size = param.file.size if(param.targetSize > size){ return param.succ(param.file) ); } / /ファイル file を読み取ると、結果は Base64 になります。changeFileToBaseURL(param.file,function(base64){ if(base64){ var image = new Image(); image.src = Base64; image.onload = function(){ // Getアスペクト比 varscale = this.width / this.height; // console.log(scale) // キャンバスを作成します var Canvas = document.createElement('canvas'); // コンテキストを取得します。 var context = Canvas.getContext('2d'); // width が -1 の場合、デフォルトの元の画像の幅を取得します。 Canvas.width = param.width == -1? width : param.width; //width が -1 の場合、デフォルトの元の画像の高さは、canvas.height = param.width == -1 になります。 parseInt(param.width /scale); //画像をキャンバスに描画します context.drawImage(image, 0, 0, Canvas.width, Canvas.height); //画像を圧縮して新しいbase64Urlを取得します var newImageData = Canvas .toDataURL(fileType,param.quality); //base64 をファイル ストリームに変換します var resultFile = dataURLtoFile(newImageData,param.fileName); //targetSize に制限があり、圧縮画像サイズがターゲット サイズより大きい場合はエラーが表示されます if(param.targetSize != -1 && param.targetSize < resultFile.size ){ console .log(画像のアップロードサイズが大きすぎます。再アップロードしてください^_^); }else{ //ファイルストリームを返します param.succ(resultFile); } } });メソッドの使用法
ファイルのサイズはバイト単位なので、必要なサイズをバイトに変換する必要があります。 1 バイトは 1B、1KB = 1024B、1MB = 1024 * 1024B
<入力タイプ=ファイルID=ファイルImgクラス=ファイルImg/>
//画像ファイルアップロード取得 url$(#fileImg).on('change',function(){ pressImg({ file:this.files[0], targetSize:2 * 1024 * 1024, 品質:0.5, width:600 , succ:function(resultFile){ //null でない場合、圧縮は成功します if(resultFile){ //TODO } } })});問題の概要画像圧縮レベル
画像の圧縮度は判断が難しいため、何度も試して、要求者の要件に応じて調整できます。 ターゲット画像のサイズと解像度を変更すると、画像の圧縮度が変わる可能性があります。
もともと、画像サイズが期待を満たすまで画像を圧縮する再帰的なプロセスを実行したいと考えていました。後でわかったこと
iosが写真を撮るためにシステムカメラを呼び出すと、カメラは反時計回りに90度回転するためです。 画像を圧縮してバックグラウンドに送ったところ、画像のexif情報の撮影方向が失われ、iOSでアップロードした画像が反時計回りに90度回転してしまいました。 Android はこの問題にまったく気づいていません。
現時点では、base64をファイル化する際に紛失したのではないかという疑いがあります。 確認後に追加の手順がここで提供されます。
@version1.0-2019-8-2-「キャンバスを使用して画像サイズを圧縮する」を作成
©burning_ユン・チーチー
以上がこの記事の全内容です。皆様の学習のお役に立てれば幸いです。また、VeVb Wulin Network をご支援いただければ幸いです。