JavaScript

JavaScriptお勉強

iPhoneやiPadなど、iOSスマートデバイスで撮った写真をリサイズしてサーバにアップしなければならないので。。。

カメラの起動

  • カメラの起動は
    <input type="file" id="cam">

    によりファイル選択かカメラ起動かを選択できるようになる。iOS6以降でサポート。

カメラ撮影 (またはファイル選択) 後の処理

  • カメラでの撮影またはファイルの選択の後の処理はJavaScriptで記述する。
    var cam = document.getElementById("cam");
    cam.addEventListener("change", cam_changeHandler, false);
  • 選択された画像はinputエレメントの“files”という配列に入るらしい。
    var cam = document.getElementById("cam");
    cam.files[0]; // [0]で最初のファイル(または唯一のファイル)にアクセスできる

    配列の中身はFileオブジェクトということらしい。

  • 中身をイメージのソースURLに読み込むには FileReader なるオブジェクトをインスタンス化し そのインスタンスのreadAsDataURL(file)というメソッドを使い、読み込み結果はonloadイベント後にインスタンスのresultプロパティを参照するらしい。
    var reader = new FileReader();
    reader.addEventListener("onload", reader_onloadHandler);
    reader.readAsDataURL(file);
     
    function reader_onloadHandler(event)
    {
        var img = new Image();
        img.addEventListener("onload", img_onloadHandler);
        img.src = event.target.result;
    }
     
    function img_onloadHandler(event)
    {
        // イメージのリサイズなど
    }

    この他にも、イメージの読み込みには以下の方法があるらしい。何れも結果はresultプロパティに入る。

    • ファイル/ブロブデータをバイナリストリングで取得する FileReader.readAsBinaryString(Blob|File)
    • ファイル/ブロブデータをテキスト文字列として取得する FileReader.readAsText(Blob|File, opt_encoding)
    • ファイル/ブロブデータを ArrayBuffer オブジェクトとして取得する FileReader.readAsArrayBuffer(Blob|File)

イメージをリサイズ

  • イメージをリサイズするのには、JavaScript Image Resizerが効率が良いという。使い方は
    var resizer = new Resize(originalWidth, originalHeight, targetWidth, targetHeight, blendAlpha, interpolationPass, useWebWorker, function (buffer) {
        drawResizedImage(targetCanvas, buffer); //リサイズ後のコールバック処理
    });
    var canvas = document.createElement("canvas");
    canvas.width = originalWidth;
    canvas.height = originalHeight;
    var context = canvas.getContext("2d");
    context.drawImage(img, 0, 0, originalWidth, originalHeight);
    var dataToScale = ctx.getImageData(0, 0, originalWidth, originalHeight).data;
    resizer.resize(dataToScale);

    という感じ。(どんな感じ?)コンストラクタのそれぞれの引数は、

    • originalWidth: 元画像の幅
    • originalHeight: 元画像の高さ
    • targetWidth : リサイズ後の幅
    • targetHeight : リサイズ後の高さ
    • blendAlpha : なんのこっちゃ
    • interpolationPass : もう判らん。。。
    • useWebWorker : WebWorkerを使うかどうか。ブラウザ依存なので一律 window.Worker をぶっこんでおけばいいかな。。。
    • resizeCallback : リサイズ後にコールバックする関数を指定する
      • このコールバック関数は buffer という引数を受け取る
      • このコールバック関数で表示するキャンバスの内容をアップデートする
  • resize インスタンスメソッドの引数は、キャンバスに描画したイメージのデータを。。。
  • 先にCanvasの使い方が判らないとお話にならないことが判る orz

Canvasお勉強

  • CanvasはJavaScriptでお絵かきするための土台という感じの認識でいいのでは?
  • 正式には HTMLCanvasElement というらしい。
  • 詳しくはここではあるが。。。
  • Canvasの生成(HTMLで)
    <canvas id="canvas1" width="120" height="160" style="border:1px solid lightgray"/>
  • Canvasの生成(scriptで)
    document.createElement("canvas");
  • Canvasのプロパティ : id, width, height, style くらいか?
  • Canvasのメソッド
    • getContext(contextId)
      • contextId は今のところ “2d” しか見たこと無い
      • “2d” のときに(今回主に)使うメソッド (くわしくはここ)
        • drawImage() : Canvasの上にイメージを貼り付ける
        • createImageData() : ImageDataオブジェクトを作る 返されるオブジェクトのすべてのピクセルは透明な黒となる
        • getImageData() : canvas から指定範囲の ImageData オブジェクトを取得する
        • putImageData() : canvas に指定の ImageData オブジェクトのデータを描画する
    • toDataURL()
      • キャンバスに描画されている内容をDataURLスキームで画像データをbase64エンコードした値を取得できる
      • 引数無しだとPNG、引数に'image/jpeg'や画質?0.1-1.0を指定できる ただしブラウザによって引数のタイプがサポートされていない場合もある
        var img = canvas.toDataURL('image/jpeg', 0.9)
      • この値を<input type=“hidden”>なんかでサーバに送って、PHPでファイル化するサンプルコード (ここのまるパクリ)
        //canvasデータがPOSTで送信されてきた場合
        $canvas = $_POST["canvas_data"];
         
        //ヘッダに「data:image/png;base64,」が付いているので、それは外す
        $canvas = preg_replace("/data:image/png;base64,/i","",$canvas);
         
        //残りのデータはbase64エンコードされているので、デコードする
        $canvas = base64_decode($canvas);
         
        //まだ文字列の状態なので、画像リソース化
        $image = imagecreatefromstring($canvas);
         
        //画像として保存(ディレクトリは任意)
        imagepng($image ,./);
  • ImageDataプロパティ
    • width, height : オブジェクトのデータの実際の寸法を返す 単位はデバイスのピクセル
    • data : RGBA の順番のデータを含んだ 1 次元配列を返す それぞれの値は 0 ~ 255 の範囲となる

コールバック処理内でのリサイズ後の画像を再描画する

  • ここまで判れば、あとは理屈通りに進められる
    function drawResizedImage(targetCanvas, buffer)
    {
        var context = targetCanvas.getContext("2d");
        var imageData = context.createImageData(targetCanvas.width, targetCanvas.height);
        var data = imageData.data;
        var length = data.length;
        for (var i = 0; i < length; ++i) {
            data[i] = buffer[i] & 0xFF;
        }
        context.putImageData(imageData, 0, 0);
    }

横長画像を縦長に回転

  • iPod touchでPortrait写真を撮った場合、ブラウザにはLandscapeで表示されてしまうため、これを回転したい。
  • Canvasのcontextのrotateを使って回転できるらしいが、回転の軸が(x, y) = (0, 0)になってしまうため、context.transrate(width/2, height/2) というメソッドを回転前に叫ぶといいらしい。
  • 詳細はここ (面倒なのでサンプルコードは省略)

JavaScriptでthisがさす物

  • コンテキストによって異なる
  • 基本的にはオブジェクト単位
    • 関数の中にオブジェクトを定義するとそのオブジェクトの中の this は関数内の this とは別のものとなる
  • bindによって強制的にコンテキストを変更することもできる
  • apply や call にコンテキストを指定できるのも、JavaScript の柔軟性のひとつ
  • ソースの表示