質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.11%

(アップロード容量制限)モバイル端末での画像アップロードについて

受付中

回答 3

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 958

kans00229

score 25

php5.6
フレームワーク等は使用しておりません。

当方の知識不足で、稚拙な質問となっておりますので
ご了承ください。

html5の[input file]でファイルをサーバー側のフォルダに保存して
それをブラウザ上で表示させたいと考えております。

PCでは、アップロードされる画像ファイル等の容量制限にて
大きなファイルはアップロード出来ないようにしております。

しかし、モバイル端末で撮影された画像等の容量が大きいため
アップロードが出来ない状況です。ユーザーにモバイル端末でアップロード前に
容量を落としてもらう作業をさせたくないと考えています。

そこで、私なりに調べて見た結果、下記のようにBLOB型で指定した
サーバーのディレクトリに画像を保存してもしくは、データベースに入れる方法が
あり、サーバーのディレクトリに画像を保存することは出来ました。

ですが、そのBLOB型のデータをブラウザに出力する方法が解らないのが
現状です。

大変稚拙な質問であると思いますが、お力をお貸し下さい。

また、下記の仕組みを使わず、モバイル端末等で画像の容量等を
圧縮してアップロードする方法がございましたら、お教え頂けると
幸いです。

むしろ下記の方法以外の、手段をお教え頂けますと助かります。
宜しくお願い致します。

<form action="" method="post" id="imageForm">
    <img src="" id="preview" />
    <canvas id="canvas"></canvas>
    <input type="file" id="imageSelect" onChange="canvasDraw();" />
    <input type="button" onClick="imageUpload();" value="アップロード" />
</form>
//ここで出力
<img src="load.php">
    function canvasDraw() {
    var file = $("#imageSelect").prop("files")[0];

    //画像ファイルかチェック
    if (file["type"] != "image/jpeg" && file["type"] != "image/png" && file["type"] != "image/gif") {
        alert("画像ファイルを選択してください");
        $("#imageSelect").val(''); //選択したファイルをクリア

    } else {
        var fr = new FileReader();

        fr.onload = function() {
            //選択した画像を一旦imgタグに表示
            $("#preview").attr('src', fr.result);

            //imgタグに表示した画像をimageオブジェクトとして取得
            var image = new Image();
            image.src = $("#preview").attr('src');

            //縦横比を維持した縮小サイズを取得
            var w = 800;
            var ratio = w / image.width;
            var h = image.height * ratio;

            //canvasに描画
            var canvas = $("#canvas");
            var ctx = canvas[0].getContext('2d');
            $("#canvas").attr("width", w);
            $("#canvas").attr("height", h);
            ctx.drawImage(image, 0, 0, w, h);      
        };

        fr.readAsDataURL(file);
    }
}   

function imageUpload() {
    var form = $("#imageForm").get(0);
    var formData = new FormData(form);

    //画像処理してformDataに追加
    if ($("#canvas").length) {
        //canvasに描画したデータを取得
        var canvasImage = $("#canvas").get(0);

        //オリジナル容量(画質落としてない場合の容量)を取得
        var originalBinary = canvasImage.toDataURL("image/jpeg"); //画質落とさずバイナリ化
        var originalBlob = base64ToBlob(originalBinary); //オリジナル容量blobデータを取得
        console.log(originalBlob["size"]);

        //オリジナル容量blobデータをアップロード用blobに設定
        var uploadBlob = originalBlob;                    

        //オリジナル容量が2MB以上かチェック
        if(2000000 <= originalBlob["size"]) {
            //2MB以下に落とす
            var capacityRatio = 2000000 / originalBlob["size"];
            var processingBinary = canvasImage.toDataURL("image/jpeg", capacityRatio); //画質落としてバイナリ化
            uploadBlob = base64ToBlob(processingBinary); //画質落としたblobデータをアップロード用blobに設定
            console.log(capacityRatio);                        
            console.log(uploadBlob["size"]);
        }

        //アップロード用blobをformDataに追加
        formData.append("selectImage", uploadBlob);
    }

    //formDataをPOSTで送信
    $.ajax({
        async: false,
        type: "POST",
        url: "http://*******.com/image",
        data: formData,
        dataType: "text",
        cache: false,
        contentType: false,
        processData: false,
        error: function (XMLHttpRequest) {
            console.log(XMLHttpRequest);
            alert("アップロードに失敗しました");
        },
        success: function (res) {
            if(res !== "OK") {
                console.log(res);
                alert("アップロードに失敗しました");
            } else {
                alert("アップロードに成功しました");
            }
        }
    });
}

// 引数のBase64の文字列をBlob形式にする
function base64ToBlob(base64) {
    var base64Data = base64.split(',')[1], // Data URLからBase64のデータ部分のみを取得
          data = window.atob(base64Data), // base64形式の文字列をデコード
          buff = new ArrayBuffer(data.length),
          arr = new Uint8Array(buff),
          blob,
          i,
          dataLen;
    // blobの生成
    for (i = 0, dataLen = data.length; i < dataLen; i++) {
        arr[i] = data.charCodeAt(i);
    }
    blob = new Blob([arr], {type: 'image/jpeg'});
    return blob;
}    
//出力用 load.php
$datas['image'] = '****.blob'
header("Content-Type: image/jpeg");
readfile($datas['image']);
exit();
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • m6u

    2017/11/17 13:11

    指定画像を分割せずHTTPアップロードするなら、PCやモバイル関係なくwebサーバー設定上のPOSTサイズ制限に引っかかると思うので、まったく別な方法でやりたい、という意味でしょうか?

    キャンセル

  • kans00229

    2017/11/17 13:52

    m6u様 返信有難うございます。別の方法もしくは、BLOB型の出力ができればそちらでもよいと考えております。私の知識が浅いため、一般的にどのようにされているのかが検討がつかない状況です。お力をお貸し頂ければと存じます。

    キャンセル

回答 3

+1

モバイル端末等で画像の容量等を圧縮してアップロードする方法
こちらですが、javaScriptで画像容量を削減することが可能です。
ユーザーにとってもサーバーにとってもモバイル端末で通信容量制限が厳しい昨今、通信容量が削減されるのは良いことだと思いますので、アップロード前に画像を小さくすることはメリットが大きいと思います。

下記のURLが参考になるかと思います。
http://matz.hatenablog.jp/entry/2017/03/26/014615

一部抜粋

<form action="" method="post" id="imageForm">
    <img src="" id="preview" />
    <canvas id="canvas"></canvas>
    <input type="file" id="imageSelect" onChange="canvasDraw();" />
    <input type="button" onClick="imageUpload();" value="アップロード" />
</form>
function canvasDraw() {
    var file = $("#imageSelect").prop("files")[0];

    //画像ファイルかチェック
    if (file["type"] != "image/jpeg" && file["type"] != "image/png" && file["type"] != "image/gif") {
        alert("画像ファイルを選択してください");
        $("#imageSelect").val(''); //選択したファイルをクリア

    } else {
        var fr = new FileReader();

        fr.onload = function() {
            //選択した画像を一旦imgタグに表示
            $("#preview").attr('src', fr.result);

            //imgタグに表示した画像をimageオブジェクトとして取得
            var image = new Image();
            image.src = $("#preview").attr('src');

            //縦横比を維持した縮小サイズを取得
            var w = 800;
            var ratio = w / image.width;
            var h = image.height * ratio;

            //canvasに描画
            var canvas = $("#canvas");
            var ctx = canvas[0].getContext('2d');
            $("#canvas").attr("width", w);
            $("#canvas").attr("height", h);
            ctx.drawImage(image, 0, 0, w, h);      
        };

        fr.readAsDataURL(file);
    }
}  
function imageUpload() {
    var form = $("#imageForm").get(0);
    var formData = new FormData(form);

    //画像処理してformDataに追加
    if ($("#canvas").length) {
        //canvasに描画したデータを取得
        var canvasImage = $("#canvas").get(0);

        //オリジナル容量(画質落としてない場合の容量)を取得
        var originalBinary = canvasImage.toDataURL("image/jpeg"); //画質落とさずバイナリ化
        var originalBlob = base64ToBlob(originalBinary); //オリジナル容量blobデータを取得
        console.log(originalBlob["size"]);

        //オリジナル容量blobデータをアップロード用blobに設定
        var uploadBlob = originalBlob;                    

        //オリジナル容量が2MB以上かチェック
        if(2000000 <= originalBlob["size"]) {
            //2MB以下に落とす
            var capacityRatio = 2000000 / originalBlob["size"];
            var processingBinary = canvasImage.toDataURL("image/jpeg", capacityRatio); //画質落としてバイナリ化
            uploadBlob = base64ToBlob(processingBinary); //画質落としたblobデータをアップロード用blobに設定
            console.log(capacityRatio);                        
            console.log(uploadBlob["size"]);
        }

        //アップロード用blobをformDataに追加
        formData.append("selectImage", uploadBlob);
    }

    //formDataをPOSTで送信
    $.ajax({
        async: false,
        type: "POST",
        url: "upload.php",
        data: formData,
        dataType: "text",
        cache: false,
        contentType: false,
        processData: false,
        error: function (XMLHttpRequest) {
            console.log(XMLHttpRequest);
            alert("アップロードに失敗しました");
        },
        success: function (res) {
            if(res !== "OK") {
                console.log(res);
                alert("アップロードに失敗しました");
            } else {
                alert("アップロードに成功しました");
            }
        }
    });
}

// 引数のBase64の文字列をBlob形式にする
function base64ToBlob(base64) {
    var base64Data = base64.split(',')[1], // Data URLからBase64のデータ部分のみを取得
          data = window.atob(base64Data), // base64形式の文字列をデコード
          buff = new ArrayBuffer(data.length),
          arr = new Uint8Array(buff),
          blob,
          i,
          dataLen;
    // blobの生成
    for (i = 0, dataLen = data.length; i < dataLen; i++) {
        arr[i] = data.charCodeAt(i);
    }
    blob = new Blob([arr], {type: 'image/jpeg'});
    return blob;
}          

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/21 09:56

    mtdsnsk様 ご回答有難うございます。私もご紹介頂きましたサイトを参考に、BLOB型で画像を保存するところまではできたのですが、表示の部分が出来なくて困っております。もし、BLOB型で保存したファイルの表示方法をご存知でしたら、ご教授下さいませ。

    キャンセル

0

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/21 10:14

    Kosuke_Shibuya様 ご回答有難うございます。最近のモバイル端末のカメラ性能の向上で、一つの画像が10メガを超えるケースがあるので、サーバーにアップロードする前に、画像の容量を抑えたいと考えております。色々調べた際に、BLOB型に変換して容量を削減してアップロードする方法を見つけたのですが、その保存したBLOB型のファイルを展開する方法が、わからないのが現状です。

    現状のサイトでは、お教え頂きました方法に近い形で画像を保存して、DBにはファイルパスを保存してGDにて画像を表示しているのですが、モバイル端末での画像アップロードを考えた際に、どうしても容量の壁にあたってしまいます。

    現状私が抱えている問題としては、
    ■BLOB型のファイルで保存することは出来たが、表示方法がわからない
    ■画像をファイル保存して、DBに画像パスを保存することはできるが、モバイル端末時にアップロード制限にかかってしまう

    実現したいこととしては
    ■BLOB型で保存したファイルの表示方法をしりたい
    もしくは
    ■お教え頂いたような方法で、画像を保存する際に、サーバーにアップロードする前に画像を圧縮したい

    わかりにくい文章で申し訳ございません。
    御手数ではございますが、ご教授頂ければと思います。
    宜しくお願い致します。

    キャンセル

  • キャンセル

0

2014年の記事ですが、以前私はこのページを大分参考にさせてもらいました。
https://qiita.com/mpyw/items/117ab6a88fd58d911c34

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.11%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる