One IT Thing

IT業界を楽しむ為の学習系雑記

html5 nodejs

ブラウザから起動したカメラの撮影画像をjavascriptで圧縮【Compressor.js】

投稿日:2019年5月1日 更新日:

「モバイル用Webアプリで撮影したカメラ画像のファイルサイズが大きすぎる・・・」

そんな悩みは無いですか?

昨今カメラ会社の経営が傾くほどスマホのカメラ性能が向上、それに応じて年々ファイルサイズも増大しています。

サーバに送ってから圧縮だとパケ代かかっちゃうし・・・という時はCompressor.jsを使うとブラウザでイイ感じにサイズ圧縮出来ます。

スマホカメラで撮影した画像ファイルサイズはどれくらい?

手持ち端末でのファイルサイズ平均。

iPhone6Google Nexus5HTC HTV33
OSiOS12Android5 Android7
解像度2448×3264 1080×1920 3024×4032
サイズ1.5Mbyte1.8Mbyte3.5Mbyte

被写体によって1Mbyte前後の誤差が有ります。 最新機種ではより大きいファイルサイズになっているはずです。

このサイズをそのまま使うと色々困る

  • サーバにアップロードし続けるとそこそこのパケ代圧迫になる
  • アプリ速度が 通信速度に引きずられて遅くなる
  • 画像保存するシステムだとストレージを喰ってしまう

2022年くらいになって5Gが普及していたら速度は気にならないのかも知れませんが、スマホもサーバもストレージは有限です。

なので撮影直後に圧縮することでファイルサイズを小さくします。

検証開始

Android7で撮影 → ブラウザ(Javascript)で画像圧縮 → サーバに圧縮前と圧縮後のファイルをアップロード → 比較、の流れ。

環境

  • Windows10
  • node v8.11.1
  • Android7 + Chrome74
  • npm initした適当なディレクトリで作業

事前準備

Compressor.jsをnpmインストール。使い方が容易で圧縮後の減衰が少ないです。

$ npm install compressorjs
+ compressorjs@1.0.5
added 3 packages in 112.364s

ファイルアップロード用にexpressとmulterをインストール。

$ npm install express
+ express@4.16.4
added 48 packages in 8.871s

$ npm install multer
+ multer@1.4.1
added 21 packages in 5.014s

クライアント(index.html)作成

スマホブラウザだとinput type=”file”にcapture属性を付けてacceptをimage/*にすることでカメラが起動します。(video/*にするとビデオが起動)

圧縮具合を確認するだけなのでHTMLにjavascriptを平べったく書いていきます。

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="node_modules/compressorjs/dist/compressor.js"></script>
    <script>
        function compress(image) {
            console.log("original size", image.size);
            sendServer(image, "圧縮前.jpg");

            new Compressor(image, {
                quality: 0.4,
                success(result) {
                    console.log("compressed size", result.size);
                    sendServer(result, "圧縮後.jpg");
                },
                error(err) {
                    console.log(err.message);
                },
            });
        }

        function sendServer(image, fileName) {
            let xhr = new XMLHttpRequest();

            let formData = new FormData();
            formData.append("upFile", image, fileName);

            xhr.open("POST", "http://{expressのIP}:3000", true);
            xhr.send(formData);
        }
    </script>
</head>

<body>
    <input type="file" accept="image/*" capture onchange="compress(this.files[0])"></input>
</body>

</html>

サーバ(server.js)作成

express + multerで/にPOSTされたらファイル保存します。アップロード用にuploadディレクトリを事前作成しておきます。

var express = require('express');
const multer = require('multer');
const path = require('path');

var app = express();
app.use("/", express.static('.'));

const storage = multer.diskStorage({
    destination: (req, file, cb) => {
        cb(null, './upload');
    },
    filename: (req, file, cb) => {
        cb(null, Date.now() + file.originalname);
    }
});

app.get('/', function (req, res) {
    res.send('./index.html');
});

app.post('/', multer({ storage: storage }).single('upFile'), (req, res) => {
    console.log('保存されたパス:' + req.file.path);
});

app.listen(3000, function () {
});

確認

  • 「node server.js」を実行してexpressサーバを起動
  • Android Chromeから「http://{expressのIP}:3000」を表示
  • 作業ディレクトリ/uploadに2ファイル上がっていることを確認

まとめ

  • 圧縮前:4.2Mbyte
  • 圧縮後:736Kbyte

原寸大では人の目で殆ど劣化が分かりませんでした。仕様と相談してアスペクト比を削れば200Kbyte前後になります。

これくらいであればパケ代節約が出来、実戦投入出来そうです。

-html5, nodejs
-, ,

執筆者:

関連記事

B2BスマホアプリをGooglePlay、AppStoreに公開することがお勧め出来ない7つの理由とその対策

商材の性質やシーンに応じてスマホアプリをGooglePlayやAppleStoreのようなストアに公開することがマイナスに働くこともあります。 商材として価値の有る電子データをお持ちの商社さんとアプリ …

IndexedDBにストアしたオブジェクトのキー値を部分的に更新する

目次1 はじめに2 課題3 より良い方法4 まとめ5 補足 はじめに IndexedDBは「key : value」でレコードを保存するキーバリューストアです。 バリューには「単値」または「Javas …

Nodeアプリが依存するnpmモジュールライセンスをlicense-checker & Jenkinsで自動チェック(1)

目次1 目的2 使用するnpmモジュール3 ライセンスを表示してみる3.1 サマリで出す3.2 CSVファイルで出す4 まとめ 目的 ionicやNode.jsアプリが依存するライブラリにライセンス違 …

Angular4.4のHTTP通信処理にタイムアウトを設定をすると「timeout is not a function」エラーが発生する

目次1 事象2 原因3 対処4 まとめ 事象 Angular4.3で追加されたHttpClientModuleに移行せず、HttpModuleを使い続けているアプリで、とある理由からpackage-l …

Nodeアプリが依存するnpmモジュールライセンスをlicense-checker & Jenkinsで自動チェック(2)

目次1 目的1.1 動作イメージ2 Jenkinsジョブを設定2.1 前提2.2 Jenkins「シェルの実行」を設定2.3 想定外ライセンスが含まれていた場合の通知3 まとめ 目的 前回の続き。&n …


shingo nakanishi。東京で消耗中の職歴20年越え中年ITエンジニアです。「生涯現役プログラマを楽しむ」ことができる働き方探しをライフワークにしています。

19歳(1996年)から書き始めた個人日記が5,000日を超え、残りの人生は発信をして行きたいと思い、令和元日からこのサイトを開始しました。勉強と試行錯誤をしながら、自分が経験したIT関連情報を投稿しています。