HTML 5は携帯電話のアルバムを呼び出して画像を選択して圧縮して、input[file]のデフォルトのスタイルを修正します
21879 ワード
最近ではHTML 5プロジェクトで画像をアップロードする機能が使われていますが、今ではHTML 5のフロントエンドのページでも携帯電話のアルバムやカメラにアクセスできますが、携帯電話で撮った画像はすぐに何Mもアップロードされます.このように何枚かの画像をアップロードすると、ユーザーは街を罵るので、クライアントで画像を圧縮してからアップロードすることができ、ユーザーのトラフィックを節約することができます.では、フロントエンドはどのように画像を圧縮しますか?画像圧縮を実現するにはcanvasが必要です.さあ、やりましょう.
次のコードはReactで記述されています.
Input fileを使用してカメラのアルバムを呼び出す
上記のinput fileをクリックすると、ポップアップウィンドウを呼び出し、カメラやアルバムから画像を取得できます.デフォルトのinput fileスタイルはブスすぎて、違和感があるので、まずスタイルを美化しましょう.ここでは2つの方法をお勧めします.
方法1:
この方法はinput[file]のopacityを0、labelのfor属性をinput[file]のIDに設定することで、labelをクリックするとinput fileをクリックするのと同じ効果ですが、input fileは全く見えません.
方法2:
この方法はinput displayをnoneに設定し,他の要素をクリックしてinputのclickイベントをトリガーする.
canvasを使用して画像を圧縮する
1、選択した画像を取得する
ファイルドメインがどのように開かれているかにかかわらず、changeイベントで選択したファイルや撮影した写真を取得できます.
2、FileReaderで画像をbase 64画像符号化に変換する
onChangeで画像を取得した後、FileReaderオブジェクトを作成する必要があります.readAsDataURLを呼び出して、data:image/jpegなどのファイルをbase 64画像符号化に変換する必要があります.base 64......このフォーマット.ファイルの読み取りが完了するとonloadメソッドがトリガーされます.onloadメソッドではe.targetを使用できます.resultはbase 64の符号化を取得するために使用され、読み出しに失敗した場合、この値はnullである.onloadは非同期の方法で、Promiseとasync,awaitを通じて非同期を同期化することができ、あまりcallbackをネストすることはありません.
3、Imageオブジェクトを作成し、srcにfileReaderが読み取ったbase 64の結果を付与し、Imageのonloadメソッドで同様にピクチャ圧縮を処理する.
4、canvasで画像を圧縮する
JSを使って画像の圧縮効果を実現するのは、原理が簡単で、コアAPIはcanvasのdrawImage()を使う方法です.canvasのdrawImage()メソッドAPIは次のとおりです.
9つのパラメータがあるように見えますが、慌てずに3つのパラメータを見ることができます.
imgはピクチャオブジェクトであり,ページ上で取得したDOMオブジェクトであってもよいし,仮想DOM中のピクチャオブジェクトであってもよい.sx,sy,swidth,sheightはcanvasキャンバスに画像を配置するために領域を描き、sx,syは左上隅座標、swidth、sheightは領域サイズを指す.後の4つのパラメータが指定されていない場合、画像はこの領域内に引き伸ばされたり拡大されたりします.x,y,width,heightはcanvasキャンバスに画像が表示されるサイズと位置である.ここでwidth,heightの値がピクチャの元のサイズである場合,最終的な表現効果はピクチャがswidth,sheight領域内にクリップされることである.本稿の画像圧縮では,最後の4つのパラメータは使えず,前の5つのパラメータだけでよい.コアコード
canvas.toDataURL()メソッド
画像をbase 64フォーマット情報、純文字の画像表現に変換できます.ここで、mimeTypeはcanvasが導出したbase 64ピクチャのタイプを表し、デフォルトはpngフォーマット、すなわちデフォルト値は「image/png」であり、jpgフォーマット「image/jpeg」やwebpなどのフォーマットに指定することもできる.fileオブジェクトのfile.typeはファイルのmimeTypeタイプで、変換時にちょうどそのまま使えます(fileオブジェクトがあれば).qualityArgumentはエクスポートしたピクチャ品質を表し、jpgとwebp形式にエクスポートした場合にのみこのパラメータが効果的で、デフォルト値は0.92で、比較的合理的なピクチャ品質出力パラメータですが、通常は設定する必要はありません.
canvas.toBlob()メソッド
canvasをBlobファイルに変換することができ、通常はファイルアップロードに使用されます.バイナリなので、バックエンドにもっと友好的です.
toBlobメソッドは現在iOSではサポートされていません.
toDataURL()メソッドと比較して、toBlob()メソッドは非同期であるため、callbackパラメータが複数存在し、このcallbackコールバックメソッドのデフォルトの最初のパラメータは変換されたblobファイル情報であり、本稿demoのファイルアップロードはcanvasピクチャをバイナリに変換するblobファイルである.
完全なコードcom/zhangyi5628…
転載先:https://juejin.im/post/5c8cbee8f265da2dbb127a49
次のコードはReactで記述されています.
Input fileを使用してカメラのアルバムを呼び出す
<input type="file" multiple accept="image/*"/>
上記のinput fileをクリックすると、ポップアップウィンドウを呼び出し、カメラやアルバムから画像を取得できます.デフォルトのinput fileスタイルはブスすぎて、違和感があるので、まずスタイルを美化しましょう.ここでは2つの方法をお勧めします.
方法1:
"uploadFile" type="file" multiple accept="image/*"/>
<div className="btn-upload">
<label htmlFor="uploadFile"> label>
div>
この方法はinput[file]のopacityを0、labelのfor属性をinput[file]のIDに設定することで、labelをクリックするとinput fileをクリックするのと同じ効果ですが、input fileは全く見えません.
方法2:
"leftFile" type="file" multiple accept="image/*" style={{display: 'none'}}/>
<a className="btn" onClick={()=>{
this.refs.leftFile.click()
}}>Browsea>
この方法はinput displayをnoneに設定し,他の要素をクリックしてinputのclickイベントをトリガーする.
canvasを使用して画像を圧縮する
1、選択した画像を取得する
render() {
const {
prefixCls, className, children, style
} = this.props
const cls = classNames({
[prefixCls]: true,
[className]: className
})
return (
<div
className={cls}
style={style}
onClick={() => {
this.refs.inputFile.click()
}}>
<input ref="inputFile" type="file" multiple accept="image/*" onChange={this.onChange}/>
{ children } {/* */}
div>
)
}
ファイルドメインがどのように開かれているかにかかわらず、changeイベントで選択したファイルや撮影した写真を取得できます.
onChange = async (e) => {
const { onChange, compress } = this.props
let files = e.target.files
const len = files.length
let newFiles = []
for(let i = 0; i < len; i++) {
const result = await this.fileReader(files[i])
const data = await this.compress(result)
newFiles.push(data)
}
}
2、FileReaderで画像をbase 64画像符号化に変換する
onChangeで画像を取得した後、FileReaderオブジェクトを作成する必要があります.readAsDataURLを呼び出して、data:image/jpegなどのファイルをbase 64画像符号化に変換する必要があります.base 64......このフォーマット.ファイルの読み取りが完了するとonloadメソッドがトリガーされます.onloadメソッドではe.targetを使用できます.resultはbase 64の符号化を取得するために使用され、読み出しに失敗した場合、この値はnullである.onloadは非同期の方法で、Promiseとasync,awaitを通じて非同期を同期化することができ、あまりcallbackをネストすることはありません.
// base64
fileReader = (file) => {
return new Promise(function (resolve, reject) {
const reader = new FileReader();
reader.onload = (e) => {
resolve(e.target.result)
};
reader.onerror = reject
reader.readAsDataURL(file);
})
}
3、Imageオブジェクトを作成し、srcにfileReaderが読み取ったbase 64の結果を付与し、Imageのonloadメソッドで同様にピクチャ圧縮を処理する.
compress = (res) => {
return new Promise(function (resolve, reject) {
const img = new Image()
img.onload = function() {
//
resolve(blob) //
}
img.onerror = function() {
reject(new Error(' '))
}
img.src = res;
})
}
4、canvasで画像を圧縮する
JSを使って画像の圧縮効果を実現するのは、原理が簡単で、コアAPIはcanvasのdrawImage()を使う方法です.canvasのdrawImage()メソッドAPIは次のとおりです.
context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);
9つのパラメータがあるように見えますが、慌てずに3つのパラメータを見ることができます.
imgはピクチャオブジェクトであり,ページ上で取得したDOMオブジェクトであってもよいし,仮想DOM中のピクチャオブジェクトであってもよい.sx,sy,swidth,sheightはcanvasキャンバスに画像を配置するために領域を描き、sx,syは左上隅座標、swidth、sheightは領域サイズを指す.後の4つのパラメータが指定されていない場合、画像はこの領域内に引き伸ばされたり拡大されたりします.x,y,width,heightはcanvasキャンバスに画像が表示されるサイズと位置である.ここでwidth,heightの値がピクチャの元のサイズである場合,最終的な表現効果はピクチャがswidth,sheight領域内にクリップされることである.本稿の画像圧縮では,最後の4つのパラメータは使えず,前の5つのパラメータだけでよい.コアコード
let canvas = document.createElement('canvas');
let context = canvas.getContext('2d');
//
context.clearRect(0, 0, targetWidth, targetHeight);
//
context.drawImage(img, 0, 0, targetWidth, targetHeight);
// base64
const dataUrl = canvas.toDataURL(imageType);
canvas.toDataURL()メソッド
canvas.toDataURL(mimeType, qualityArgument)
画像をbase 64フォーマット情報、純文字の画像表現に変換できます.ここで、mimeTypeはcanvasが導出したbase 64ピクチャのタイプを表し、デフォルトはpngフォーマット、すなわちデフォルト値は「image/png」であり、jpgフォーマット「image/jpeg」やwebpなどのフォーマットに指定することもできる.fileオブジェクトのfile.typeはファイルのmimeTypeタイプで、変換時にちょうどそのまま使えます(fileオブジェクトがあれば).qualityArgumentはエクスポートしたピクチャ品質を表し、jpgとwebp形式にエクスポートした場合にのみこのパラメータが効果的で、デフォルト値は0.92で、比較的合理的なピクチャ品質出力パラメータですが、通常は設定する必要はありません.
canvas.toBlob()メソッド
canvas.toBlob(callback, mimeType, qualityArgument)
canvasをBlobファイルに変換することができ、通常はファイルアップロードに使用されます.バイナリなので、バックエンドにもっと友好的です.
toBlobメソッドは現在iOSではサポートされていません.
toDataURL()メソッドと比較して、toBlob()メソッドは非同期であるため、callbackパラメータが複数存在し、このcallbackコールバックメソッドのデフォルトの最初のパラメータは変換されたblobファイル情報であり、本稿demoのファイルアップロードはcanvasピクチャをバイナリに変換するblobファイルである.
完全なコードcom/zhangyi5628…
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import classNames from 'classnames'
import './index.less'
export default class InputImage extends Component {
constructor(props) {
super(props)
}
static defaultProps = {
prefixCls: 'yh-input-image',
compress: true,
className: '',
style: null,
onChange: ()=>{},
maxWidth: 400,
maxHeight: 400,
fileType: 'blob',
imageType: 'image/png'
}
static propTypes = {
prefixCls: PropTypes.string,
compress: PropTypes.bool,
className: PropTypes.string,
style: PropTypes.object,
onChange: PropTypes.func,
maxWidth: PropTypes.number,
maxHeight: PropTypes.number,
fileType: PropTypes.oneOf(['base64', 'blob']), //
imageType: PropTypes.string //
}
compress = (res) => {
// console.log('res:', res)
let { maxWidth, maxHeight, fileType, imageType } = this.props
// imageType = `image/${imageType}`
return new Promise(function (resolve, reject) {
const img = new Image()
img.onload = function() {
let originWidth = this.width, originHeight = this.height
let canvas = document.createElement('canvas');
let context = canvas.getContext('2d');
let targetWidth = originWidth, targetHeight = originHeight;
// 400x400
if (originWidth > maxWidth || originHeight > maxHeight) {
if (originWidth / originHeight > maxWidth / maxHeight) {
// ,
targetWidth = maxWidth;
targetHeight = Math.round(maxWidth * (originHeight / originWidth));
} else {
targetHeight = maxHeight;
targetWidth = Math.round(maxHeight * (originWidth / originHeight));
}
}
// canvas
canvas.width = targetWidth;
canvas.height = targetHeight;
//
context.clearRect(0, 0, targetWidth, targetHeight);
//
context.drawImage(img, 0, 0, targetWidth, targetHeight);
if (fileType === 'base64') {
// base64
const dataUrl = canvas.toDataURL(imageType);
resolve(dataUrl)
} else {
// canvas blob
if (canvas.toBlob) {
canvas.toBlob(function(blob) {
resolve(blob)
}, imageType)
} else { // ios toB
let data = canvas.toDataURL(imageType);
//dataURL “data:image/png;base64,****”, ,
data = data.split(',')[1];
data = window.atob(data);
let ia = new Uint8Array(data.length);
for (let i = 0; i < data.length; i++) {
ia[i] = data.charCodeAt(i);
}
//canvas.toDataURL image/png
let blob = new Blob([ia], {
type: imageType
});
resolve(blob)
}
}
}
img.onerror = function() {
reject(new Error(' '))
}
img.src = res;
});
}
// base64
fileReader = (file) => {
console.log('file:', file)
return new Promise(function (resolve, reject) {
const reader = new FileReader();
reader.onload = (e) => {
resolve(e.target.result)
};
reader.onerror = reject
reader.readAsDataURL(file);
})
}
onChange = async (e) => {
const { onChange, compress } = this.props
let files = e.target.files
const len = files.length
console.log('files:', files)
let newFiles = []
if (compress) {
for(let i = 0; i < len; i++) {
const result = await this.fileReader(files[i])
const data = await this.compress(result)
// console.log('data:', data)
newFiles.push(data)
}
}
console.log('newFiles:', newFiles)
onChange && onChange({
files,
newFiles
})
}
render() {
const {
prefixCls, className, children, style
} = this.props
const cls = classNames({
[prefixCls]: true,
[className]: className
})
return (
<div
className={cls}
style={style}
onClick={() => {
this.refs.inputFile.click()
}}>
<input ref="inputFile" type="file" multiple accept="image/*" onChange={this.onChange}/>
{ children } {/**/}
div>
)
}
}
転載先:https://juejin.im/post/5c8cbee8f265da2dbb127a49