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
-, ,

執筆者:

関連記事

ionicアプリを多言語化する

目次1 目的2 環境3 手順1.インストール4 手順2.src/assets/i18nに翻訳ファイルを作成する5 手順3.app.module.tsにngx-translate関連のモジュールを登録す …

Android、iPhoneが向いている方向をWeb地図上で表現してみる(leaflet.js使用)

前回Javascriptでコンパス機能を実装して、Android、iPhoneの背面が向いている方角が数値(0~360:0が北)で分かるようになりました。 One IT Thing  9 P …

Javascriptでコンパスを作ってAndroid、iPhoneが向いている方角を特定

普段は意識しなくても、AndroidもiPhoneも自然データをデジタルに変換するセンサーの塊です。 加速度センサー重力センサージャイロセンサー地磁気センサー気圧センサー照度センサー温度センサー位置セ …

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

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

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

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

 

shingo.nakanishi
 

東京在勤、1977年生まれ、IT職歴2n年、生涯技術者として楽しく生きることを目指しています。デスマに負けず健康第一。