主にプログラミングに関して。Python, .NET Framework(C#), JavaScript, その他いくらか。
記事にあるサンプルやコードは要検証。使用に際しては責任を負いかねます

スポンサーサイト

                
tags:
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

JavaScript: Exifを保ったまま画像を縮小 Resize a Jpeg Image by JS Keeping EXIF: part 2[obsolete]

                
tags: JavaScript
NEXT: JavaScript: Resize JPEG images without losing Exif: part 3

JavaScript: Resize JPEG images without losing Exif
Demo

jpg.js
MinifyJpeg.js


 HTMLのinput要素からファイルを読み込むことができ、JPEGファイルもbase64エンコードされた文字列として取得できる。そしてこの取得できたJPEG画像をJavaScriptでリサイズするスクリプトをちらほら見つけることができる。そのほとんどすべてがImageインスタンスのオンロードイベント内でリサイズ処理を行っている。まどろっこしい。処理をなるべくイベント駆動に頼らず、記述したスクリプトが上から下に向かって順次実行されていくようにしたい。

 以前書いたExifを消さないJPEGの縮小スクリプトは、例に漏れず縮小前にJPEGのImageインスタンスへの読み込みを必要としていた。今回はそれを取っ払って、Imageインスタンスへの読み込みなしにJPEGの縮小ができるようにスクリプトを書き換えた。もちろんExifは消さない。書き換えによって、jpg.jsというライブラリ(当方での書き換えあり)に依存するようになった。
テスト済みブラウザは、FireFox, GoogleChrome, IE10(pre-release for win 7), Operaそれぞれの'13/01/25時点での最新版。

 JavaScriptでオリジナルの画像サイズを得るためにはImageインスタンスに読み込ませるのが一般的。このスクリプトではImageインスタンスを使うわけにいかなかったので、画像サイズをセグメントから読んだり。
 あとは縮小のためのフィルタを実装すればパーフェクトか。

old
    var img = new Image();
img.onload = function(){
minified = MinifyJpeg.minify(imageEncodedBase64, length);
enc = "data:image/jpeg;base64," + MinifyJpeg.encode64(minified);
html = '<img src="' + enc + '">';
}
img.src = image


new
    minified = MinifyJpeg.minify(imageEncodedBase64, length);
enc = "data:image/jpeg;base64," + MinifyJpeg.encode64(minified);
html = '<img src="' + enc + '">';


JPEGデコーダは以下で見つけた。これのおかげで時間の消費をかなり抑えることができた。
https://github.com/notmasteryet/jpgjs


デモのHTML(ジェネレータが使えればJavaScriptがもっとシンプルになるだろうに。ジェネレータはま現時点でFireFoxでしか使えない)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script src="http://blog-imgs-51.fc2.com/e/l/i/elicon/jpg.js"></script>
<script src="http://blog-imgs-51.fc2.com/e/l/i/elicon/MinifyJpeg.js"></script>
</head>
<body>
<div id="up">JPEG FILES ONLY<br></div>
<div id="shori"></div>
<script>
processedFiles = [];
fileArray = [];

function handleFileSelect(evt) {
var files = evt.target.files; // FileList object
fileArray = [];
for (var x=0; x<files.length ; x++)
{
fileArray.push(files[x]);
}
handleFiles();
}

function handleFiles()
{
while (1)
{
if (fileArray.length == 0)
{
postData(filesToPost, false);
filesToPost = [];
return;
}
else if (fileArray[0].type.match('image/jpeg.*'))
{
break;
}
else
{
fileArray.shift(0);
}
}
var f = fileArray.shift(0);
$("#keika").html("Left: " + (fileArray.length + 1))
var reader = new FileReader();

// Closure to capture the file information.
reader.onloadend = (function(theFile)
{
return function(e)
{
if (processedFiles.indexOf(theFile.name) < 0)
{
processedFiles.push(theFile.name);
var num = processedFiles.length;
$("#shori").prepend('<div id="load' + num + '">loading: ' + theFile.name + '</div>');
var minified = MinifyJpeg.minify(e.target.result, 200);
//postData(minified, theFile.name, num);

var enc = "data:image/jpeg;base64," + MinifyJpeg.encode64(minified);
var html = '<br><div id="s' + num + '"><img src="' + enc + '" width="150"><br>' +
'Uploaded: ' + theFile.name + '</div><br>';
$('#load' + num).html(html);
handleFiles();
}
else
{
handleFiles();
}
};
})(f);

// Read in the image file as a data URL.
reader.readAsDataURL(f);
}

function postData(data, name, i)
{
var oReq = new XMLHttpRequest();
oReq.open("POST", "/resize", false);
oReq.setRequestHeader('Content-Type', 'image\/jpeg');
oReq.onload = function (oEvent)
{
var enc = "data:image/jpeg;base64," + MinifyJpeg.encode64(data);
var html = '<br><div id="s' + i + '"><img src="' + enc + '" width="150"><br>' +
'Uploaded: ' + name + '</div><br>';
$('#load' + i).html(html);
handleFiles();
}

oReq.send(data.buffer);
}

if (typeof(FileReader) == "function")
{
var html = '<input type="file" id="files" class="form" name="files[]" multiple /><br>' +
'<div id="keika"><div>'
$('#up').append(html);
document.getElementById('files').addEventListener('change', handleFileSelect, false);
}
else
{
var html = '<form action="/up" method="post" enctype="multipart/form-data">' +
'<fieldset><legend>写真を追加</legend>' +
'<input type="file" name="photo[]" multiple/><br>' +
'<input type = "submit" value="写真を送る">' +
'</fieldset></form><br><br>';
$('#up').append("");
}
</script>
</body>
</html>


HTMLはHTML5Rocksを参考に書き換えていった。
Reading files
参考にしたスクリプトは実はよろしくない書き方をしていると思う。handleFileSelectのなかでfor文を使ってファイル処理を回している。これは一つのファイル処理が完了する前にどんどんファイルを読み込むオブジェクトを生成していくことになり、結果としていくつものファイル処理が並行して行われることになる。クライアントにサイズの大きいファイルを同時に多数選択されると、ブラウザがクラッシュしかねない。
クラッシュを避けるため、再帰を使って、一つのファイル処理後に次のファイル処理が呼ばれるように書き換えた。
            

コメントの投稿

非公開コメント

プロフィール

hMatoba

Author:hMatoba
Github

最新記事
リンク
作ったものなど
月別アーカイブ
カテゴリ
タグリスト

検索フォーム
Amazon
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。