「モバイル用Webアプリで撮影したカメラ画像のファイルサイズが大きすぎる・・・」
そんな悩みは無いですか?
昨今カメラ会社の経営が傾くほどスマホのカメラ性能が向上、それに応じて年々ファイルサイズも増大しています。
サーバに送ってから圧縮だとパケ代かかっちゃうし・・・という時はCompressor.jsを使うとブラウザでイイ感じにサイズ圧縮出来ます。
目次
スマホカメラで撮影した画像ファイルサイズはどれくらい?
手持ち端末でのファイルサイズ平均。
iPhone6 | Google Nexus5 | HTC HTV33 | |
OS | iOS12 | Android5 | Android7 |
解像度 | 2448×3264 | 1080×1920 | 3024×4032 |
サイズ | 1.5Mbyte | 1.8Mbyte | 3.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前後になります。
これくらいであればパケ代節約が出来、実戦投入出来そうです。