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

執筆者:

関連記事

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

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

Typescript3.0以下の環境で発生する「Cannot find name ‘unknown’」に対処する

目次1 事象2 原因3 対処4 まとめ 事象 Typescript2.3.4を使っている息の長いWebシステムでnpm installをし直し、tscビルドし直したらトランスパイルエラーが発生。「un …

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

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

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

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

IndexedDBにblob保存されたPDFファイルを外部アプリに頼らずにJavascriptで表示(後編)

目次1 はじめに2 ビューワ機能を提供してくれるnpmモジュールを選別する3 実装開始3.1 ng2-pdfjs-viewerを使えるようにする3.2 PDFビューワコンポーネントを作る3.3 Hom …

 

shingo.nakanishi
 

東京在勤、1977年生まれ、IT職歴2n年、生涯現役技術者を目指しています。健康第一。