画像とサムネイルのダウンローダー。 新しい標準、古い問題

まえがき



みなさんこんにちは。 少し前に、フラッシュイメージダウンローダーの作成に関する記事を書きました 。 そこで、ローダーはhtml5 File APIを使用して実装することもできると述べました。 数晩と-乾杯-私はそれをやった。 今度は、私が使用したトリック、それが機能するブラウザ、および使用する価値があるかどうかを説明します。

要件を簡単に思い出しましょう。バッチアップロード、サムネイル作成(およびサーバーへのアップロード)、および許容可能なインターフェイスをサポートするイメージダウンローダーを実装する必要があります。



私の記事では、まだ完全には開発されていない標準の現在の実装を使用していることをよく理解しているため、現時点で関連するブラウザーをリストします。

  1. Firefox 8
  2. Chrome 15
  3. Opera 11.60ベータ
  4. Safari 5.1.1
  5. Internet Explorer 9


悲しいことについて。 IE 9の場合、File APIの実装はありませんので、考慮しません(ブラウザー)。 さあ、行きましょう。



外観



太古の昔から、タスクはファイル選択ダイアログを開くためのスタイリッシュなボタンを作成することでした。 したがって、暴力的な松葉杖が使用されました。 たとえば、一般的な解決策は、入力を透明にし、美しい歌姫の上に吊るすことです。 つまり、すべてが入力とそのサイズに依存します。 上記のブラウザはすべて、異なるソリューションをサポートしています。 それらでは、プログラムでクリック入力を生成できます。 しかし、実際には、ファイル選択ダイアログを呼び出します。 また、入力自体は簡単に非表示にできます。

<input id="input_file" type="file" multiple style="position:absolute; top:-999px; visibility:hidden"/> <div id="button" style="background-color: blue; width: 100px; height:40px;"></div>
      
      





 <script type="text/javascript"> var input = document.querySelector("#input_file"); var btn = document.querySelector("#button"); btn.onclick = function () { input.click(); }; </script>
      
      





このメソッドを使用すると、コントロールとしての入力を忘れることができますが、これは非常に便利です。



ブラウザへのファイルのダウンロードについて



たとえば、画像のサイズを変更するなど、ファイルデータを操作するには、このデータを取得する必要があります。 これにはFileReaderが必要です。 サムネイルを作成するには、Canvasを使用して、そこにファイルデータをロードします。 これは、データをbase64として表す場合に可能です。



 var files; var reader = new FileReader(); var cv = document.createElement("canvas"); var cvContext = cv.getContext("2d"); input.onchange = function () { files = input.files; reader.readAsDataURL(files[0]); }; reader.onload = function (e) { var im = new Image(); im.onload = function (e) { cv.width = 100; cv.height = 100; cvContext.drawImage(im, 0, 0, 100, 100); //       canvas         } im.src = reader.result; };
      
      





これまでのところ、すべてが非常に透明です。 ただし、ブラウザへのデータのダウンロードはSafariではサポートされていないとすぐに言う必要があります。 最も興味深いのは、サーバーにはファイルをアップロードできますが、ブラウザーにはアップロードできないことです。 FileReaderもURLもサポートされていません。 ただし、このタスクには1つの解決策がありますが、正直に言って使用しません。 後でこれに戻ります。



サムネイルの受信とサーバーへの送信について



だから。 元の画像があります。 キャンバスにサムネイルがあります。 すべてを取得し、グループ化し、サーバーに送信する必要があります。 どちらが簡単ですか? ここで問題が発生します。 この段階では、ブラウザの動作はまったく異なります。 皆のためのソリューションを考えてみましょう。 もちろん、単純なものから複雑なものまで。



Firefox


ここではすべてが簡単です。 CanvasにはmozGetAsFileメソッドがあり、その名前はそれ自身を表しています。 FirefoxはFormDataもサポートしています。 これは、ファイル用のコンテナがあることを意味します。 XMLHttpRequestはこのデータをサーバーに簡単に送信し、そこでサーバーはそれを取得できます。 ダウンロードプロセスは、upload.onprogressを使用して監視できます。



 var blobData = cv.mozGetAsFile(name, files[0].type); var form = new FormData(); form.append("Filedata0", files[0]); form.append("Filedata1", blobData); var xhr = new XMLHttpRequest(); xhr.open("POST", "load.php", true); xhr.onload = function () { console.log(this.response); } xhr.upload.onprogress = function (e) { console.log(e.position / e.totalSize) * 100; } xhr.send(form);
      
      







マイナスは1つだけです。 mozGetAsFileメソッドでは、アップロードされた画像の品質を選択できません。



クロム


ここには、mozGetAsFileが見えません。 base64で画像を取得することが可能です(これはtoDataURLメソッドによって行われます)。 しかし、それは私には合わず、私はまだ画像をブロブに持ち込みました。 コード内のコメント:

 var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder; //    base64,     ( 0  1) var sBase64 = canva.toDataURL(type, 1); var aBase64 = sBase64.split(','); //  var sData = atob(aBase64[1]); var aBufferView = new Uint8Array(sData.length); // ArrayBuffer    for (var i = 0; i < aBufferView.length; i++) { aBufferView[i] = sData.charCodeAt(i); } //   BlobBuilder   blob var builder = new BlobBuilder(); builder.append(aBufferView.buffer); var blobData = builder.getBlob(type);
      
      







これらのデータはすでにFormDataに書き込まれ、firefoxと同じ方法で送信できます。



オペラ


ここには大きな問題があります。 Chromeと同じ方法でサムネイルを取得してArrayBufferに変換できますが、どのように送信しますか? OperaはFormDataとBlobBuilderをサポートしていません。 また、XMLHttpRequestは、テキスト以外のArrayBufferのみを送信できます。 ここでは、フラッシュにブートローダーを作成する経験が役立ちます。 データを使用してフォームのタイトルを生成し、ArrayBufferに書き込んで送信する必要があります。

 var sBase64 = canva.toDataURL(type, 1); var aBase64 = sBase64.split(','); var sData = atob(aBase64[1]); var aBufferView = new Uint8Array(sData.length); for (var i = 0; i < aBufferView.length; i++) { aBufferView[i] = sData.charCodeAt(i); } var fBuilder = new FormBuilder(); fBuilder.addFile(aBufferView); var form = fBuilder.getForm(); var xhr = new XMLHttpRequest(); xhr.open("POST", "load.php", true); xhr.onload = function () { alert(this.response); } xhr.setRequestHeader('Content-type', 'multipart/form-data; boundary=' + fBuilder.BOUND); xhr.send(form); function FormBuilder() { this.getBoundary = function () { var _boundary = ""; for (var i = 0; i < 0x20; i++) { _boundary += String.fromCharCode(97 + Math.random() * 25); } return _boundary; } this.addFile = function (name, buffer) { var sHeader = this.ADDB + this.BOUND; sHeader += this.ENTER; sHeader += 'Content-Disposition: form-data; name="Filedata' + this.index + '"; filename="' + name + '"'; sHeader += this.ENTER; sHeader += 'Content-Type: application/octet-stream'; sHeader += this.ENTER; sHeader += this.ENTER; this.index++; this.header = this.sumBuffers(this.header, this.StrToBuffer(sHeader), buffer, this.EnterBuffer); } this.addParam = function (name, value) { var sHeader = this.ADDB + this.BOUND; sHeader += this.ENTER; sHeader += 'Content-Disposition: form-data; name="'+ name + '"'; sHeader += this.ENTER; sHeader += this.ENTER; sHeader += value; sHeader += this.ENTER; this.header = this.sumBuffers(this.header, this.StrToBuffer(sHeader)); } this.getForm = function () { var sHeader = this.ENTER; sHeader += this.ENTER; sHeader += (this.ADDB + this.BOUND + this.ADDB); var aHeader = this.StrToBuffer(sHeader); return this.sumBuffers(this.header, aHeader).buffer; } this.StrToBuffer = function (str) { var buffer = new Uint8Array(str.length); for (var i = 0; i < buffer.length; i++) { buffer[i] = str.charCodeAt(i); } return buffer; } this.sumBuffers = function () { var sumLength = 0, position = 0, aSumHeader; for (var i = 0; i < arguments.length; i++) { sumLength += arguments[i].length; } aSumHeader = new Uint8Array(sumLength); for (var i = 0; i < arguments.length; i++) { aSumHeader.set(arguments[i], position); position += arguments[i].length; } return aSumHeader; } this.BOUND = this.getBoundary(); this.ENTER = "\r\n"; this.EnterBuffer = this.StrToBuffer(this.ENTER); this.ADDB = "--"; this.index = 0; this.header = new Uint8Array(0); }
      
      







これは、最初の記事のクラスのactionscriptからjavascriptへの無料翻訳です。 これにより、基本的にFormDataをエミュレートします。 ちなみに、Chromeではうまく機能します。 しかし、Firefoxは誓います-彼はArrayBufferを渡す方法を知りません。

Operaに戻ります。 すべては機能しますが、ダウンロードを追跡することはできません。Operaのonprogressはサポートされていません(Flash URLLoaderのように)。



サファリ


Safariでは、ファイルデータにアクセスできないため、実際には何もできないと既に述べました。 ただし、html5で機能的なイメージダウンローダーを作成し、Safariをサポートすることに決めた場合は、疑似解決策があります。 実際、ファイルデータにはアクセスできませんが、サーバーにアップロードできます。 そして、サーバー上では何でもできます。 アイデアは単純です。ファイルを受信して​​保存した後、ファイルを(base64の形式で、またはCanvasへの後続のアップロードとのリンクだけで)転送します。 そして、上記で提案されたオプションのいずれかを実装してみてください。 当然、この方法は良くありませんが、どうしても必要な場合はできます。



おわりに



前述の結論は非常に簡単です。 まず、File APIは明らかにまだ熟成されていません。 ブラウザは仕様の内容を何らかの形でサポートしようとしていますが、標準はまだ議論と改良の段階にあります。 それにもかかわらず、私たちには、紙だけでなく問題を解決するためのかなり強力なツールがあります。

この記事が誰かの役に立つことを願っています。





私は小さなデモを持ちますが、機能は最小限ですが、どのように機能するかを示しています。

はい、その他。 この例の最小サーバーコードは次のとおりです。



 foreach($_FILES as $key => $value){ $filename = substr_replace($key, '.', -4, 1); move_uploaded_file($value['tmp_name'], $filename); } echo 'complete';
      
      







すべてのヴィラと機能を備えた完全なブートローダーが必要な場合は、記述してください。 たぶん私は。

そしてもちろん、Operaのバージョンが11.60ベータ版であることを忘れないでください。



All Articles