問題
現象
当ブログのスクリーンショットには主にPNG形式で作成しています。
しかし、自作のQtアプリケーションで保存した大きめのサイズのスクリーンショットが、WordPressの画像管理プラグインにより、JPG形式に変換されていることに気づきました。
これはPNG形式でのファイル容量が設定値を超えていたことにより、JPG形式に圧縮されていたことによるものです。
原因
このアプリケーションは、
- 画面上でドラッグして範囲選択を行い
- 選択された範囲の大きさのQPixmapを生成して
- 指定範囲のスクリーンショットを貼り付け、
- QPixmap::saveで保存する
という処理を行います。
今回困った点は、上記の処理で保存したpngファイルのサイズが大きくなってしまうことです。
QPixmap::saveにはqualityが指定できますが、これはJPGなどの非可逆圧縮を行うファイル形式のときにのみ関係するものです。
細かい設定をして保存したいときはQImageWriterを自分で呼べば良いはずです。QPixmapのsaveも内部でtoImageしてQImageWriterに渡しているだけのようですし。
— 緑野翁@充電中 (@hermit4) January 25, 2019
Twitterにてタグ付きでぼやいてみたところ、@hermit4氏よりリプライを頂きました。
その内容をヒントにQtソースコードを確認したところ、Qt単体で「qualityが非可逆圧縮を行うファイル形式のときにのみ関係する」という私の認識が誤りであったことがわかりました。
QPixmap::saveにて、quality=0を指定すると、きちんと圧縮されたpng形式のファイルが出力されるようになっています。詳細はリプライツリーを御覧ください。
その日のうちに解決するとは思っておりませんでした。
@hermit4さん、ありがとうございました。
解決法
力技ですが、餅は餅屋ということで、pngquantを使って圧縮することにしました。
ファイルの保存を終わらせたあと、QProcess
を使って作業フォルダにあるpngquant.exeを叩くという方式です。
pngquantのソースをプロジェクトに含める等してもいいのですが、自分用のアプリケーションということもありちょっと横着しています。
// 設定から読み込んでいる変数
QString filepath = "path/to/file";
QString filetype = "png";
// 保存したいスクリーンショット
QPixmap image = ...;
// ファイルの保存
image.save(filepath + "." + filetype, filetype);
// ファイルタイプがpngのとき、pngquantで圧縮
if(filetype == "png"){
QString command = "./pngquant.exe";
QStringList args;
args << "--force" << "--output" << filepath << filepath;
// コマンド実行(./pngquant.exe --force --output path/to/file.png path/to/file.png)
QProcess::execute(command, args);
}
これで無事キレイでファイルサイズが最低限のスクリーンショットを保存することが出来るようになりました。