140

TL;DR;

アップロードする前に、画像 (主に jpeg、png、gif) をブラウザ側で直接圧縮する方法はありますか? JavaScriptでこれができると確信していますが、それを実現する方法が見つかりません。


実装したい完全なシナリオは次のとおりです。

  • ユーザーが私のウェブサイトにアクセスし、input type="file"要素を介して画像を選択し、
  • この画像は JavaScript を介して取得され、正しいファイル形式、最大ファイル サイズなどの検証が行われます。
  • すべて問題なければ、画像のプレビューがページに表示されます。
  • ユーザーは、画像を 90°/-90° 回転する、事前に定義された比率に従ってトリミングするなどの基本的な操作を実行するか、別の画像をアップロードしてステップ 1 に戻ることができます。
  • ユーザーが満足すると、編集された画像が圧縮され、ローカルに「保存」されます (ファイルには保存されませんが、ブラウザのメモリ/ページに保存されます)。
  • ユーザーはフォームに名前、年齢などのデータを入力します。
  • ユーザーが「完了」ボタンをクリックすると、データと圧縮された画像を含むフォームがサーバーに送信されます (AJAX なし)。

最後のステップまでの完全なプロセスはクライアント側で行う必要があり、最新の Chrome と Firefox、Safari 5+ とIE 8+で互換性があるはずです。可能であれば、JavaScript のみを使用する必要があります (ただし、これは不可能であると確信しています)。

今は何もコーディングしていませんが、すでに考えています。ローカルでのファイルの読み込みはFile API経由で可能で、画像のプレビューと編集はCanvas要素を使用して行うことができますが、画像圧縮部分を行う方法が見つかりません

html5please.comcaniuse.comによると、これらのブラウザーをサポートすることは (IE のおかげで) 非常に困難ですが、FlashCanvasFileReaderなどのポリフィルを使用して行うことができます。

実はファイルサイズを小さくするのが目的なので、画像圧縮が解決策だと思います。しかし、アップロードされた画像が私のウェブサイトで毎回同じ場所に表示されることはわかっており、この表示領域のサイズ (例: 200x400) もわかっています。そのため、これらの寸法に合わせて画像のサイズを変更し、ファイル サイズを小さくすることができました。この手法の圧縮率がどうなるかわかりません。

どう思いますか ?何かアドバイスはありますか?JavaScript でブラウザ側の画像を圧縮する方法を知っていますか? 返信ありがとうございます。

4

12 に答える 12

215

要するに:

  • HTML5 FileReader API と .readAsArrayBuffer を使用してファイルを読み取る
  • ファイル データで Blob を作成し、window.URL.createObjectURL(blob)でその URL を取得します。
  • 新しい Image 要素を作成し、その src をファイル blob の URL に設定します
  • イメージをキャンバスに送信します。キャンバスのサイズが目的の出力サイズに設定されている
  • canvas.toDataURL("image/jpeg",0.7) を介してキャンバスから縮小されたデータを取得します (独自の出力形式と品質を設定します)。
  • 新しい非表示の入力を元のフォームに添付し、dataURI イメージを基本的に通常のテキストとして転送します
  • バックエンドで、dataURI を読み取り、Base64 からデコードして保存します

ソース:コード.

于 2013-02-03T13:24:11.183 に答える
20

@PsychoWoodsの答えは良いです。独自のソリューションを提供したいと思います。この Javascript 関数は、画像データ URL と幅を受け取り、それを新しい幅にスケーリングして、新しいデータ URL を返します。

// Take an image URL, downscale it to the given width, and return a new image URL.
function downscaleImage(dataUrl, newWidth, imageType, imageArguments) {
    "use strict";
    var image, oldWidth, oldHeight, newHeight, canvas, ctx, newDataUrl;

    // Provide default values
    imageType = imageType || "image/jpeg";
    imageArguments = imageArguments || 0.7;

    // Create a temporary image so that we can compute the height of the downscaled image.
    image = new Image();
    image.src = dataUrl;
    oldWidth = image.width;
    oldHeight = image.height;
    newHeight = Math.floor(oldHeight / oldWidth * newWidth)

    // Create a temporary canvas to draw the downscaled image on.
    canvas = document.createElement("canvas");
    canvas.width = newWidth;
    canvas.height = newHeight;

    // Draw the downscaled image on the canvas and return the new data URL.
    ctx = canvas.getContext("2d");
    ctx.drawImage(image, 0, 0, newWidth, newHeight);
    newDataUrl = canvas.toDataURL(imageType, imageArguments);
    return newDataUrl;
}

このコードは、データ URL があり、縮小された画像のデータ URL が必要な場所ならどこでも使用できます。

于 2016-09-27T22:31:48.473 に答える
3

編集: この回答に関する Mr Me のコメントによると、JPG/WebP 形式で圧縮が利用できるようになったようです ( https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURLを参照) 。 .

私の知る限り、キャンバスを使用して画像を圧縮することはできません。代わりに、サイズを変更できます。canvas.toDataURL を使用すると、使用する圧縮率を選択できません。あなたが望むことを正確に行うcanimageを見ることができます:https://github.com/nfroidure/CanImage/blob/master/chrome/canimage/content/canimage.js

実際、画像のサイズを小さくするために画像のサイズを変更するだけで十分なことがよくありますが、さらに進めたい場合は、新しく導入されたメソッド file.readAsArrayBuffer を使用して、画像データを含むバッファーを取得する必要があります。

次に、DataView を使用して、画像形式の仕様 ( http://en.wikipedia.org/wiki/JPEGまたはhttp://en.wikipedia.org/wiki/Portable_Network_Graphics ) に従ってコンテンツを読み取ります。

画像データの圧縮に対処するのは難しいでしょうが、試してみると最悪です。一方、PNG ヘッダーまたは JPEG exif データを削除して画像を小さくすることもできます。これは簡単に行うことができます。

別のバッファーに別の DataView を作成し、フィルター処理された画像コンテンツで埋める必要があります。次に、window.btoa を使用して画像コンテンツを DataURI にエンコードするだけです。

似たようなものを実装している場合はお知らせください。コードを調べるのは興味深いでしょう。

于 2013-05-26T15:48:30.243 に答える