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

執筆者:

関連記事

ionicアプリを多言語化する

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

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

目次1 はじめに2 検証環境3 Ionicプロジェクト作成4 PDFダウンロード、IndexedDB保存を実装5 実行してみる はじめに PDFをHTTPダウンロードするとHDDに保存されるか、外部ビ …

http-serverコマンドでHTTPS、CORSサーバをたてる

「フロントエンドをHTTPS化してHTTP公開しているREST APIに接続したい、でも自分のPCにApacheやNginxを入れてHTTPS化するのは面倒くさい」 開発中ってこういうニーズと悩みが結 …

Android+ChromeでlocalhostアクセスしてPCサーバへPort Forward(Fwdアプリ使用)

昨今はプライバシーの侵害防止、セキュリティ観点から、HTTPS環境下でないと使えないHTML5 APIが増えました。 反してAndroid7でオレオレ証明書に関する仕様が変わり、Android6だった …

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

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

 

shingo.nakanishi
 

東京在勤、職歴20年越え中年ITエンジニアです。まだ開発現場で頑張っています。

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

私と同じく、今後IT業界で生計を立てて行きたいと考えている方や、技術共有したいけどフリーランスで孤独、といった方と一緒に成長、知識共有して行けたら楽しいな、と思っています。