サーバーにアップロードする前にJavaScriptでクライアント側の画像のサイズを変更する


147

JavaScriptを使用してクライアント側で画像のサイズを変更する方法を探しています(幅と高さを変更するだけでなく、実際にサイズ変更します)。
Flashで実行できることはわかっていますが、可能な限り回避したいと思います。

ウェブ上のどこかにオープンソースのアルゴリズムはありますか?


これに対する答えを知りたい人のために、あなたはこれを行うことができますが、画像処理のためにいくつかのajax呼び出しを行う必要があります。
多面体

1
「作る必要がありますか?」結局のところ、サーバーでそれを解決し、AJAX呼び出しを介して透過的にデータを取得できます。しかし、すべての試みはそれをクライアント側で行うことであり、ジェレミーが指摘するように、それは行うことができます。これは良い例だと思います:github.com/rossturner/HTML5-ImageUploader
Bart

2
Dropzone.jsは最新バージョンで、アップロード前のクライアント側の画像サイズ変更をサポートしています。
user1666456 2017

回答:


111

これを行う要点は次のとおりです。https//gist.github.com/dcollien/312bce1270a5f511bf4a

(es6バージョン、およびスクリプトタグに含めることができる.jsバージョン)

次のように使用できます。

<input type="file" id="select">
<img id="preview">
<script>
document.getElementById('select').onchange = function(evt) {
    ImageTools.resize(this.files[0], {
        width: 320, // maximum width
        height: 240 // maximum height
    }, function(blob, didItResize) {
        // didItResize will be true if it managed to resize it, otherwise false (and will return the original file as 'blob')
        document.getElementById('preview').src = window.URL.createObjectURL(blob);
        // you can also now upload this blob using an XHR.
    });
};
</script>

それは私が管理できる限り多くのブラウザでそれが動作することを確認するためのサポート検出とポリフィルの束を含みます。

(GIF画像も無視されます-アニメーション化されている場合)


2
私はあなたがこれについて十分な賞賛を受け取っていないように感じます-私はそれが素晴らしく機能し、超簡単だと思います。共有してくれてありがとう!
Matt、

4
うーん..これでうまくいきましたが、正しいサイズで出力されたものの、(サイズ変更に加えて)画像の品質も(深刻なピクセル化の形で)大幅に失われていることがわかりました。
ルーベンマルティネスジュニア

1
こんにちは、私はこのように使用するスニペットが必要です。これは非常に良いと思いますが.. function(blob、didItResize){//それがサイズ変更できた場合はtrue、それ以外の場合はfalse(元の「blob」としてのファイル)document.getElementById( 'preview')。src = window.URL.createObjectURL(blob); // XHRを使用してこのblobをアップロードすることもできます。ここに問題があります。フォームを送信するだけで、この画像をフォームで送信するにはどうすればよいですか。つまり、送信ボタンによってトリガーされる投稿リクエストのようなものです。通常の方法です。要旨をありがとう!
iedmrc

3
品質が低下した(再サンプリングされた)場合は、キャンバスコンテキストを更新しimageSmoothingEnabledてtrue`とimageSmoothingQualityに設定しhighます。typescriptですではそのようなブロックルックス: const ctx = canvas.getContext('2d'); ctx.imageSmoothingEnabled = true; (ctx as any).imageSmoothingQuality = 'high'; ctx.drawImage(image, 0, 0, width, height);
ショーン・パーキンス

1
これをnpmパッケージにする可能性はありますか?超素晴らしいだろう!
erksch

62

これに対する答えは「はい」です。HTML5では、canvas要素を使用してクライアント側で画像のサイズを変更できます。新しいデータを取得してサーバーに送信することもできます。このチュートリアルを参照してください:

http://hacks.mozilla.org/2011/01/how-to-develop-a-html5-image-uploader/


28
これはリンクのみの回答なので、コメントにする必要があります。
神保

2
canvas.mozGetAsFile( "foo.png"); は非推奨の機能です
mili

12

アップロードする前にサイズを変更していた場合は、 http://www.plupload.com/

それはあなたのために想像できる方法ですべての魔法をします。

残念ながら、HTML5のサイズ変更はMozillaブラウザーでのみサポートされていますが、他のブラウザーをFlashおよびSilverlightにリダイレクトできます。

私はそれを試してみましたが、それは私のアンドロイドで動作しました!

私はフラッシュでhttp://swfupload.org/を使用していました、それは非常にうまく機能しますが、サイズ変更サイズは非常に小さいです。(制限を覚えることはできません)、フラッシュが利用できない場合、html4に戻りません。


44
ユーザーが10 MBの写真をアップロードしようとしたときに、クライアント側でサイズを変更すると、はるかに小さな写真としてのみ保存されるので便利です。この方法を使用すると、はるかに速くアップロードされます。
カイル

ここでも同じシナリオで、ファイルを入力し、ユーザーがスマートフォンでカメラを使用して画像をスナップすると、最新のスマートフォンでは約10 mbになります。とにかくサーバー側でサイズを変更し、それよりもはるかに小さいバージョンのみを保存している場合は、事前にクライアントでサイズ変更を行うことで、多くのセルラーデータと読み込み時間を節約できます。
アレックス

1
pluploadはAGPLなので注意してください。
Alex

11

http://nodeca.github.io/pica/demo/

最新のブラウザでは、キャンバスを使用して画像データをロード/保存できます。ただし、クライアントで画像のサイズを変更する場合は、いくつかの点に注意する必要があります。

  1. チャネルあたりのビット数は8ビットのみです(jpegのダイナミックレンジは約12ビットです)。プロの写真をアップロードしない場合は、問題ありません。
  2. サイズ変更アルゴリズムに注意してください。ほとんどのクライアント側のリサイザは簡単な数学を使用しており、結果はそれよりも悪いです。
  3. 縮小された画像をシャープにする必要がある場合があります。
  4. オリジナルのメタデータ(exifなど)を再利用する場合は、カラープロファイル情報を削除することを忘れないでください。画像をキャンバスにロードするときに適用されるからです。

6

おそらくcanvasタグを使用します(ただし、移植性はありません)。キャンバス画像を回転する方法についてのブログがここにあります。回転できれば、サイズを変更できると思います。多分それは出発点になることができます。

このライブラリも参照してください。


2
非常に役立つ例。これらのリンクが壊れた場合に備えて、回答に1つまたは2つのスニペットを追加することができます。
Trevor

4

画像をサーバーにアップロードする前に、クライアント側の画像処理にJavaScript画像処理フレームワークを使用できます。

以下では、MarvinJを使用して、次のページの例に基づいて実行可能なコードを作成しました。 「サーバーにアップロードする前にクライアント側で画像を処理する」

基本的には、Marvin.scale(...)メソッドを使用して画像のサイズを変更します。次に、画像をblobとしてアップロードします(メソッドimage.toBlob()を使用)。サーバーは、受信した画像のURLを提供して応答します。

/***********************************************
 * GLOBAL VARS
 **********************************************/
var image = new MarvinImage();

/***********************************************
 * FILE CHOOSER AND UPLOAD
 **********************************************/
 $('#fileUpload').change(function (event) {
	form = new FormData();
	form.append('name', event.target.files[0].name);
	
	reader = new FileReader();
	reader.readAsDataURL(event.target.files[0]);
	
	reader.onload = function(){
		image.load(reader.result, imageLoaded);
	};
	
});

function resizeAndSendToServer(){
  $("#divServerResponse").html("uploading...");
	$.ajax({
		method: 'POST',
		url: 'https://www.marvinj.org/backoffice/imageUpload.php',
		data: form,
		enctype: 'multipart/form-data',
		contentType: false,
		processData: false,
		
	   
		success: function (resp) {
       $("#divServerResponse").html("SERVER RESPONSE (NEW IMAGE):<br/><img src='"+resp+"' style='max-width:400px'></img>");
		},
		error: function (data) {
			console.log("error:"+error);
			console.log(data);
		},
		
	});
};

/***********************************************
 * IMAGE MANIPULATION
 **********************************************/
function imageLoaded(){
  Marvin.scale(image.clone(), image, 120);
  form.append("blob", image.toBlob());
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://www.marvinj.org/releases/marvinj-0.8.js"></script>
<form id="form" action='/backoffice/imageUpload.php' style='margin:auto;' method='post' enctype='multipart/form-data'>
				<input type='file' id='fileUpload' class='upload' name='userfile'/>
</form><br/>
<button type="button" onclick="resizeAndSendToServer()">Resize and Send to Server</button><br/><br/>
<div id="divServerResponse">
</div>


これはすごいですね。
pimbrouwers

2

はい、最新のブラウザではこれは完全に実行可能です。具体的には、任意の数のキャンバスの変更を行ったバイナリファイルとしてファイルをアップロードすることもできます。

http://jsfiddle.net/bo40drmv/

(この答えはここで受け入れられた答えの改善です

PHPでの結果の送信をキャッチするプロセスを覚えておいてください。

//File destination
$destination = "/folder/cropped_image.png";
//Get uploaded image file it's temporary name
$image_tmp_name = $_FILES["cropped_image"]["tmp_name"][0];
//Move temporary file to final destination
move_uploaded_file($image_tmp_name, $destination);

Vitalyのポイントが心配な場合は、作業中のjfiddleでトリミングやサイズ変更を試してみてください。


0

私の経験では、この例は、サイズ変更された画像をアップロードするための最良のソリューションでした:https : //zocada.com/compress-resize-images-javascript-browser/

HTML5 Canvas機能を使用します。

コードは次のように「シンプル」です。

compress(e) {
    const fileName = e.target.files[0].name;
    const reader = new FileReader();
    reader.readAsDataURL(e.target.files[0]);
    reader.onload = event => {
        const img = new Image();
        img.src = event.target.result;
        img.onload = () => {
                const elem = document.createElement('canvas');
                const width = Math.min(800, img.width);
                const scaleFactor = width / img.width;
                elem.width = width;
                elem.height = img.height * scaleFactor;

                const ctx = elem.getContext('2d');
                // img.width and img.height will contain the original dimensions
                ctx.drawImage(img, 0, 0, width, img.height * scaleFactor);
                ctx.canvas.toBlob((blob) => {
                    const file = new File([blob], fileName, {
                        type: 'image/jpeg',
                        lastModified: Date.now()
                    });
                }, 'image/jpeg', 1);
            },
            reader.onerror = error => console.log(error);
    };
}

このオプションには欠点が1つだけあり、EXIFデータを無視するため、画像の回転に関連しています。私が現在取り組んでいるのはどれですか。それが終わったら更新します。

もう1つの欠点は、IE / Edgeのサポートが不足していることです。上記のリンクに情報がありますが。両方の問題について。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.