つまり、「フロントエンドバイナリで楽しむ」テストを読んで学習する
上の最初の画像は、フロントエンドでの画像変更のプロセスに関するものです
1.ローカル画像->画像プレビューを選択します
フローチャートからわかるように、通常、画像をプレビューする方法は2つあります。1つはローカルから画像を取得してプレビューする方法、もう1つはインターネットから画像プレビューをダウンロードする方法です。
- FileReader API
FileReader APIをサポートするブラウザーでは、変更されたAPIを使用して、ローカル画像プレビュー機能の実現を容易にすることもできます。
上の図からわかるように、APIは互換性があり、通常どおり使用できます。テストコード
<div>
<h3>选择本地图片 -> 图片预览</h3>
<input type="file" accept="image/*" onchange="loadFile(event)">
<img id="previewLocalImg" />
</div>
<script>
const loadFile = function(event) {
const reader = new FileReader()
reader.onload = function() {
const output = document.querySelector('#previewLocalImg')
output.src = reader.result
}
console.log(event.target.files)
reader.readAsDataURL(event.target.files[0])
}
</script>
上記の例では、FileReaderオブジェクトを作成し、オブジェクトのonload対応イベントハンドラーをバインドしてから、FileReaderオブジェクトのreadAsDataURL()メソッドを呼び出して、ローカルイメージに対応するFileオブジェクトをデータURLに変換しました。
ファイルが読み込まれると、バインドされたonloadイベント処理関数がトリガーされます。処理関数内では、取得したデータURLデータがimgのsrc属性に割り当てられ、画像のローカルプレビューを実現します。
赤いボックスでは、src属性値がbase64エンコード後の文字列であることがわかります。
この属性値は実際にはデータURLと呼ばれ、プレフィックス(data :)、データ型を示すMIMEタイプ、テキストでない場合はオプションのbase64タグ、およびデータ自体の4つの部分で構成されます。
data:[<mediatype>][;base64],<data>
mediatypeは、PNG画像ファイルの「image / png」などのMIMEタイプの文字列です。省略した場合、デフォルト値はtext / plain; charset = US-ASCIIです。データがテキストタイプの場合は、テキストを直接埋め込むことができます(ドキュメントタイプに応じて、適切なエンティティ文字またはエスケープ文字を使用します)。バイナリデータの場合は、埋め込む前にデータをbase64エンコードできます。
MIME(Multipurpose Internet Mail Extensions)多目的インターネットメール拡張子タイプは、特定の拡張子を持つファイルをアプリケーションが開くように設定する方法です。拡張子を持つファイルにアクセスすると、ブラウザは指定されたアプリケーションを自動的に使用します。開いた。これは主に、クライアント定義のファイル名やメディアファイルを開く方法を指定するために使用されます。
一般的なMIMEタイプは、ハイパーテキストマークアップ言語text.html text / html、PNG image.png image / png、通常のtext.txt text / plainなどです。
Webプロジェクトの開発プロセスでは、HTTPリクエストの数を減らし、いくつかの小さなアイコンに対応するために、通常、データURLの形式でHTMLまたはCSSファイルに埋め込むことを検討します。「ただし、画像が大きく、画像のカラーレベルが高い場合、base64でエンコードされた画像の文字列が非常に大きくなり、HTMLのサイズが大幅に増加するため、この方法は適していません。ページ、したがって読み込み速度に影響します。」
base64は単なるデータエンコード方式であり、目的はデータの安全な送信を保証することであることに注意してください。ただし、標準のbase64エンコーディングは追加情報なしでデコードでき、完全に元に戻すことができます。したがって、プライベートデータの送信が含まれる場合、base64エンコーディングを直接使用することはできませんが、特別な対称または非対称暗号化アルゴリズムを使用する必要があります。
2.オンラインで写真をダウンロード->写真のプレビュー
ローカルから写真を取得するだけでなく、fetch APIを使用してインターネットから写真を取得し、写真をプレビューすることもできます。もちろん、インターネット上で通常アクセスできる画像アドレスの場合、アドレスをimg要素に直接割り当てることができ、フェッチAPIを回避する必要はありません。画像データの復号化など、画像を表示するときに画像に対して特別な処理を実行する必要がある場合は、Web WorkerのフェッチAPIを使用して画像データを取得し、復号化操作を実行することを検討できます。
簡単にするために、特別なシナリオは考慮していません。まず、フェッチAPIの互換性を見てみましょう。
次に、フェッチAPIを使用してインターネットから画像を取得します。具体的なコードは次のとおりです。
<div>
<h3>获取远程图片预览示例</h3>
<img id="previewInternetImg" />
</div>
<script>
const image = document.querySelector("#previewInternetImg");
fetch("https://wx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTLZpzZqvib4bzlMqE3wibILYcSn23OFBaMDs4fNNpib6BxV3dyZDzbtLJLq5BPQfCoTv4zicXeHMuxNnw/132")
.then((response) => response.blob())
.then((blob) => {
const objectURL = URL.createObjectURL(blob);
image.src = objectURL;
});
</script>
上記の例では、フェッチAPIを使用してインターネットから画像を取得します。リクエストが成功したら、レスポンスオブジェクト(Response)をBlobオブジェクトに変換し、URL.createObjectURLメソッドを使用してオブジェクトURLを作成し、割り当てます。画像の表示を実現するために、img要素のプロパティのsrcにそれを追加します。
図からわかるように、srcの属性値も文字列の文字列です。これは正確には何ですか。?
blob:null/ea2557df-67ce-4cfb-9cf2-4de8b4527633
上記の特別な文字列を「オブジェクトURL」と呼びます。これは、前に紹介したデータURLよりもはるかに簡潔です。
オブジェクトURLは疑似プロトコルであり、BlobURLとも呼ばれます。これにより、BlobまたはFileオブジェクトを画像のURLソース、バイナリデータをダウンロードするためのリンクなどとして使用できます。ブラウザでは、URL.createObjectURLメソッドを使用してBlob URLを作成します。このURLは、Blobオブジェクトを受け取り、その一意のURLを次の形式で作成します。
blob:<origin>/<uuid>
ブラウザは、URL.createObjectURLによって生成された各URLの「URL→Blob」マッピングを保存します。したがって、このようなURLは短くなりますが、blobにアクセスできます。生成されたURLは、現在のドキュメントが開いている場合にのみ有効です。ただし、アクセスしたBlob URLが存在しない場合は、ブラウザーから404エラーが表示されます。
上記のBlobURLは見栄えが良いですが、実際には副作用もあります。URL→Blobマッピングは保存されますが、Blob自体はまだメモリに存在し、ブラウザはそれを解放できません。ドキュメントがアンロードされるとマッピングが自動的にクリアされるため、Blobオブジェクトはその後解放されます。ただし、アプリケーションの寿命が長い場合は、すぐには発生しません。したがって、Blob URLを作成すると、Blobが不要になった場合でも、Blobはメモリに残ります。
この問題に対応して、URL.revokeObjectURL(url)メソッドを呼び出して内部マッピングから参照を削除し、それによってblobを削除して(他の参照がない場合)、メモリを解放することができます。
3.画像のグレースケール
画像をグレースケールするには、画像のピクセルデータを操作する必要があります。
1.getImageData方法
CanvasRenderingContext2Dによって提供されるgetImageDataを使用して、画像のピクセルデータを取得できます。ここで、getImageData()は、キャンバス領域の非表示のピクセルデータを記述するImageDataオブジェクトを返します。この領域は、開始点が(sx、sy)の長方形で表されます。 )と幅sw、高さはshです。getImageDataメソッドの構文は次のとおりです。
ctx.getImageData(sx, sy, sw, sh);
対応するパラメーターの説明は次のとおりです。
sx:抽出する画像データの長方形領域の左上隅のx座標。
sy:抽出する画像データの長方形領域の左上隅のy座標。
sw:抽出される画像データの長方形の領域の幅。
sh:抽出される画像データの長方形の領域の高さ。
2.putImageData 方法
画像のピクセルデータを取得した後、グレー化や色の反転など、取得したピクセルデータを処理できます。処理が完了したら、ページに処理効果を表示するには、CanvasRenderingContext2D-putImageDataによって提供される別のAPIを使用する必要があります。
このAPIは、Canvas 2DAPIが既存のImageDataオブジェクトからビットマップにデータを描画するためのメソッドです。描画された長方形が提供されている場合、長方形のピクセルのみが描画されます。この方法は、キャンバス変換マトリックスの影響を受けません。putImageDataメソッドの構文は次のとおりです。
void ctx.putImageData(imagedata, dx, dy);
void ctx.putImageData(imagedata, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight);
対応するパラメーターの説明は次のとおりです。
imageData:ImageData、ピクセル値を含む配列オブジェクト。
dx:ターゲットキャンバス内のソース画像データの位置オフセット(x軸方向のオフセット)。
dy:ターゲットキャンバス内のソース画像データの位置オフセット(y軸方向のオフセット)。
dirtyX(オプション):ソース画像データの長方形領域の左上隅の位置。デフォルトは、画像データ全体の左上隅(x座標)です。
dirtyY(オプション):ソース画像データの長方形領域の左上隅の位置。デフォルトは、画像データ全体の左上隅(y座標)です。
dirtyWidth(オプション):ソース画像データの長方形領域の幅。デフォルトは画像データの幅です。
dirtyHeight(オプション):ソース画像データの長方形領域の高さ。デフォルトは画像データの高さです。
3.画像のグレースケール処理
<div>
<h3>图片灰度化处理</h3>
<div>
<button id="grayscalebtn">灰度化</button>
<div style="display: flex;">
<div style="flex: 50%;">
<p>预览容器</p>
<img id="previewGreyImg" width="230" height="230" style="border: 2px dashed blue;" />
</div>
<div style="flex: 50%;">
<p>Canvas容器</p>
<canvas id="canvas" width="230" height="230" style="border: 2px dashed grey;"></canvas>
</div>
</div>
</div>
</div>
<script>
const image = document.querySelector("#previewGreyImg");
const canvas = document.querySelector("#canvas");
fetch("https://wx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTLZpzZqvib4bzlMqE3wibILYcSn23OFBaMDs4fNNpib6BxV3dyZDzbtLJLq5BPQfCoTv4zicXeHMuxNnw/132")
.then((response) => response.blob())
.then((blob) => {
const objectURL = URL.createObjectURL(blob);
image.src = objectURL;
image.onload = () => {
draw();
};
});
function draw() {
const ctx = canvas.getContext("2d");
ctx.drawImage(image, 0, 0, 230, 230);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
const grayscale = function () {
for (let i = 0; i < data.length; i += 4) {
const avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
data[i] = avg; // red
data[i + 1] = avg; // green
data[i + 2] = avg; // blue
}
ctx.putImageData(imageData, 0, 0);
};
const grayscalebtn = document.querySelector("#grayscalebtn");
grayscalebtn.addEventListener("click", grayscale);
}
</script>
上記の例では、最初にインターネットから画像をダウンロードし、次にローカルでプレビューし、次にdraw()メソッドを呼び出して、取得した画像をページのCanvasコンテナに描画し、グレースケールボタンのリスナーイベントをバインドします。同時に。
ユーザーがグレースケールボタンをクリックすると、グレースケール処理関数がトリガーされます。関数内で、ctx.getImageData()メソッドを介して取得された画像ピクセルがグレースケールされます。処理が完了したら、ctx.putImageData()メソッドを使用して処理されたピクセルデータをCanvasに更新します。
上記のコードが正常に実行された後、最終的なグレースケール効果を次の図に示します。
4.画像圧縮
場合によっては、ローカル画像をアップロードするときに、画像をある程度圧縮してからサーバーに送信することで、送信されるデータの量を減らすことができます。フロントエンドで画像圧縮を実現するために、Canvasオブジェクトによって提供されるtoDataURL()メソッドを使用できます。このメソッドは、typeとencoderOptionsの2つのオプションパラメーターを受け取ります。
typeは画像形式を表し、デフォルトはimage / pngです。EncoderOptionsは、画像の品質を示すために使用されます。指定された画像形式がimage / jpegまたはimage / webpの場合、画像の品質は0から1まで選択できます。値の範囲を超えると、デフォルト値の0.92が使用され、他のパラメーターは無視されます。
以前にグレー表示された画像を圧縮する方法を見てみましょう。
<h3>图片灰度化处理</h3>
<button id="grayscalebtn">灰度化</button>
<button id="compressbtn">图片压缩</button>
<div style="display: flex;">
<div style="flex: 33.3%;">
<p>预览容器</p>
<img id="previewGreyImg" width="230" height="230" style="border: 2px dashed blue;" />
</div>
<div style="flex: 33.3%;">
<p>Canvas容器</p>
<canvas id="canvas" width="230" height="230" style="border: 2px dashed grey;">
</canvas>
</div>
<div style="flex: 33.3%;">
<p>压缩预览容器</p>
<img id="compressPrevContainer" width="230" height="230" style="border: 2px dashed green;" />
</div>
</div>
<script>
const image = document.querySelector("#previewGreyImg");
const canvas = document.querySelector("#canvas");
fetch("https://wx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTLZpzZqvib4bzlMqE3wibILYcSn23OFBaMDs4fNNpib6BxV3dyZDzbtLJLq5BPQfCoTv4zicXeHMuxNnw/132")
.then((response) => response.blob())
.then((blob) => {
const objectURL = URL.createObjectURL(blob);
image.src = objectURL;
image.onload = () => {
draw();
};
});
function draw() {
const ctx = canvas.getContext("2d");
ctx.drawImage(image, 0, 0, 230, 230);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
const grayscale = function () {
for (let i = 0; i < data.length; i += 4) {
const avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
data[i] = avg; // red
data[i + 1] = avg; // green
data[i + 2] = avg; // blue
}
ctx.putImageData(imageData, 0, 0);
};
const grayscalebtn = document.querySelector("#grayscalebtn");
grayscalebtn.addEventListener("click", grayscale);
}
const compressbtn = document.querySelector("#compressbtn");
const compressImage = document.querySelector("#compressPrevContainer");
compressbtn.addEventListener("click", compress);
function compress(quality = 80, mimeType = "image/webp") {
const imageDataURL = canvas.toDataURL(mimeType, quality / 100);
compressImage.src = imageDataURL;
}
</script>
実際、toDataURL()メソッドに加えて、CanvasオブジェクトはtoBlob()メソッドも提供します。メソッドの構文は次のとおりです。
canvas.toBlob(callback, mimeType, qualityArgument)
toDataURL()メソッドと比較すると、toBlob()メソッドは非同期であるため、追加のコールバックパラメーターがあります。このコールバックメソッドのデフォルトの最初のパラメーターは、変換されたblobファイル情報です。
5.画像のアップロード
圧縮された画像に対応するデータURLデータを取得した後、データをサーバーに直接送信できます。