自分のコードに問題があるのか、それとも現在の HTML5 ファイル API の実装に問題があるのかを調べようとしています。
以下のコードは動作します。このバグは、画像を一度ロードした後にプロセスを繰り返すと発生します。
2 回目にファイルを選択すると、画像ブロブが読み込まれ、ちらつきが発生して画像が消えます。その後の選択は、通常は正常に機能します (ファイルが大きい場合、動作が不安定になることがあります)。同じファイル選択に対してプロセスを繰り返すと、通常は機能します (修正として)。
どんな助けでも大歓迎です。
使用する JavaScript ライブラリ
JQuery 1.7.1
JQuery ツール 1.2.6
JCrop 0.9.9
手順 - まとめ
ユーザーは、従来の
<input type="file" />
ダイアログを介してファイルを選択します。入力に対して onchange ハンドラーが実行され、ファイルが選択されているかどうかがチェックされます。選択されている場合は、MIME タイプが image/jpeg または image/png であり、選択されたファイルのサイズが 250KB 未満であることを確認します。この検証が失敗すると、選択がリセットされます。
この時点で、アップロードするファイル (画像) は有効です。次に、ブラウザーが File API CreateObjectURL をサポートしているかどうかを確認します
if (typeof window.URL == 'undefined') return;
(サポートしていない場合は、次の手順をスキップします)。画像ブロブを現在の画像プレビュー (現在の画像を表示するために使用されるもの) と、jcrop トリミング機能を備えた jquery ツールのオーバーレイに追加される動的に生成された画像要素に読み込みます。
次に、ユーザーは jcrop を介して画像をトリミングし、オーバーレイを閉じて、アップロードする画像のトリミングされたプレビューを確認します (ブラウザーが CreateObjectURL をサポートし、ユーザーが画像をトリミングした場合のみ)。
コード
HTML
<div style="height: 100px; overflow: hidden; width: 100px; margin-bottom: 5px;">
<img id="PhotoPreview" alt="Photo" src="/Content/no-photo.png" />
</div>
<input type="file" id="Photo" name="Photo" onchange="photoChanged(this.files)" />
<input type="hidden" id="PhotoCrop" name="PhotoCrop" value="" />
JavaScript window.URL = window.URL || window.webkitURL;
function photoChanged(files) {
if (!files.length) return;
var file = files[0];
if (file.type != 'image/jpeg' && file.type != 'image/png') {
alert('The photo must be in PNG or JPEG format');
$("#Photo").val('');
return;
}
var fileSizeLimit = 250;
var fileSize = file.size / 1024;
if (fileSize > fileSizeLimit) {
var fileSizeString = fileSize > 1024 ? (fileSize / 1024).toFixed(2) + "MB" : (fileSize).toFixed(2) + "KB";
alert("The photo file size is too large, maximum size is " + fileSizeLimit
+ "KB. This photos' file size is: " + fileSizeString);
$("#Photo").val('');
return;
}
if (typeof window.URL == 'undefined') return;
var preview = document.getElementById('PhotoPreview');
$(preview).removeClass('profile-photo');
preview.src = window.URL.createObjectURL(file);
preview.onload = function () {
var img = new Image();
$("#PhotoOverlay div").empty().append(img);
window.URL.revokeObjectURL(this.src);
img.src = window.URL.createObjectURL(file);
img.onload = function () {
window.URL.revokeObjectURL(this.src);
$(this).Jcrop({
onSelect: onImageCropSelect,
aspectRatio:
310 / 240,
minSize: [100, 100],
setSelect: [0, 0, 100, 100]
});
$("#PhotoOverlay")
.css({ width: this.width + 'px', : 'auto'})
.overlay()
.load();
};
};
}
function onImageCropSelect(e) {
$("#PhotoCrop").val(e.x + ',' + e.y + ',' + .x2 + ',' + e.y2);
var rx = 100 / e.w;
var ry = 100 / e.h;
var height = $("#PhotoOverlay div img").height();
var width = $("#PhotoOverlay div img").width();
jQuery('#PhotoPreview').css({
width: Math.round(rx * width) + 'px',
height: Math.round(ry * height) + 'px',
marginLeft: '-' + Math.round(rx * e.x) + 'px',
marginTop: '-' + Math.round(ry * e.y) + 'px'
});
}
$(function () {
$("#PhotoOverlay").overlay({
mask: {
color: '#ebecff',
loadSpeed: 200,
opacity: 0.9
}
});
});
コードを自由に使用してください (ここで受け取ったヘルプに対する私の貢献)。
アップデート
JCrop の使用に関する同様の問題 (画像の読み込み後に消える) に関して、stackoverflow に関する別の質問に遭遇しました。私は現在、JCrop が犯人であることに賭けています。
また、 img.onload が実行されたときに画像が常に「準備完了」であるとは限らないことも読みました。そのため、奇妙な動作と setTimeout を使用した .actualWidth/.actualHeight への追加チェックにより、問題が解決する可能性があります。私はそれを調査します。
アップデート
私は、CreateObjectURL を使用する代わりに FileReader と readAsDataUrl を使用し、マージンベースのoverflow:hidden ソリューションの代わりに CANVAS を使用してプレビューを描画する概念実証を行っています。改良が必要なので、ここにコードを投稿します。