1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

恣意的に作った大量の JPEG ファイルを zip 形式と tgz 形式で圧縮してみる例

1
Posted at

背景

あの SNS で、こんな投稿を見つけた。

大量の JPG 画像を 2 種類のソフトウェアで圧縮し、処理速度と圧縮率を比較しているようである。
そして、「JPG は既に圧縮されているから圧縮のテストには向かない、テキストやプログラムなどでやれ」的なコメントがついている。

今回は、この投稿と直接は関係ないが、ある性質を持った JPEG 画像を大量に生成し、それを zip 形式と tgz (tar.gz) 形式で圧縮し、圧縮率を比較してみた。

データの生成

ImageMagickでホワイトノイズ画像を生成する #ランダム画像 - Qiita
を参考に、ImageMagick でランダムな画像を大量に生成する。
このとき、
ImageMagick の JPEG オプション #ImageMagick - Qiita
を参考に、ハフマン符号の最適化を抑止し、同じ大きさなら圧縮データ以外は同じようなデータができるようにする。

今回は、

  • 184x184
  • 192x192
  • 200x200
  • 208x208

の 4 種類の解像度での実験結果を紹介する。
また、最初の記事で紹介されているコマンドから

  • それぞれの解像度で名付けたディレクトリに入れる
  • 生成数を 10000 枚ではなく 1000 枚にする
  • magick コマンドを使用する
  • ハフマン符号の最適化を抑止するオプションを追加する

という改変を行った。

画像を生成するコマンド
mkdir 184x184
for i in `seq -f %04g 0 999` ; do
  magick convert -size 184x184 xc:gray +noise random -colorspace gray -define jpeg:optimize-coding=false 184x184/noise${i}.jpg
done

mkdir 192x192
for i in `seq -f %04g 0 999` ; do
  magick convert -size 192x192 xc:gray +noise random -colorspace gray -define jpeg:optimize-coding=false 192x192/noise${i}.jpg
done

mkdir 200x200
for i in `seq -f %04g 0 999` ; do
  magick convert -size 200x200 xc:gray +noise random -colorspace gray -define jpeg:optimize-coding=false 200x200/noise${i}.jpg
done

mkdir 208x208
for i in `seq -f %04g 0 999` ; do
  magick convert -size 208x208 xc:gray +noise random -colorspace gray -define jpeg:optimize-coding=false 208x208/noise${i}.jpg
done

さらに、生成した画像が入った各ディレクトリを、7-Zip で zip および tar 形式で圧縮した。
そして、これによりできた tar ファイルを、さらに 7-Zip で gzip 形式で圧縮した。
zip および gzip での圧縮は、圧縮レベル「9 - 超圧縮」を用いた。

使用したバージョンは

  • ImageMagick 7.1.1-12 Q16-HDRI x64 a09d8dd:20230625
  • 7-Zip 24.09 (x64)

である。

サイズの比較

元のファイル群、および圧縮後の各ファイルのバイト数は、以下のようになった。

解像度 184x184 192x192 200x200 208x208
元ファイル計 28,834,419 31,371,378 34,009,863 36,756,755
tar 29,697,536 32,257,536 34,817,536 37,384,192
tar.gz 28,352,762 30,871,538 33,868,560 36,592,661
zip 28,832,841 31,351,001 33,970,103 36,696,300

各解像度について、それらにおける各圧縮形式のサイズの「元ファイル計」との比は、以下のようになった。

解像度 184x184 192x192 200x200 208x208
tar 102.99 % 102.82 % 102.37 % 101.71 %
tar.gz 98.33 % 98.41 % 99.58 % 99.55 %
zip 99.99 % 99.94 % 99.88 % 99.84 %

データサイズ比のグラフ

このグラフは、数値軸を 0 から始めないことにより、細かい差を強調している。

今回実験をした範囲では、tar や zip のデータサイズ比は、解像度が上がる (すなわち、データサイズが大きくなる) につれて少しずつ小さくなってきている。
一方、tar.gz のデータサイズ比は、解像度が 192x192 から 200x200 になったところでその前後での変化よりも大幅に大きくなっている。
これらには、今回用いた各圧縮形式の性質が関わっていると考えられる。

各圧縮形式の性質

zip

zip 形式では、格納するファイルそれぞれを個別に圧縮し、ファイルのメタデータ (ファイル名や更新日時など) を無圧縮で格納する。
圧縮には、一般的には DEFLATE が用いられる。

各ファイルを個別に圧縮するので、異なるファイルに共通するデータがあっても、そのことを活かした圧縮はできないと考えられる。
また、メタデータのサイズはファイルの内容によらないので、ファイルが大きくなるとメタデータの影響の割合は小さくなる。

tar

tar 形式では、格納するファイルそれぞれの前にファイルのメタデータ (ファイル名や更新日時など) をつけ、その後そのファイルのデータをそのまま (無圧縮で) 格納する。

tar 形式では圧縮をしないが、この記事では便宜上「圧縮形式」と呼ぶ。

圧縮をせずにメタデータを追加するため、当然ファイルサイズは元より大きくなるが、複数のファイルを 1 個のデータにまとめることができる。

tar.gz

tar 形式にまとめたデータを、gzip 形式 で圧縮したものである。
gzip 形式は、DEFLATE で圧縮したデータにヘッダとフッタを追加したものである。

tar 形式は「複数のファイルをまとめることができるが、圧縮はできない」ので、このように gzip などの「1 個のデータだけを対象に、圧縮をする」形式と組み合わせて用いることが多い。

DEFLATE 圧縮の性質

今回の zip 形式や tar.gz 形式では、DEFLATE 圧縮が用いられる。
DEFLATE 圧縮は RFC 1951 で定義されており、

  • よく使われるバイトを短く表現する (ハフマン符号)
  • 前に出てきたバイト列を再利用する

という 2 つのテクニックを使用して圧縮を行う。
ただし、「前に出てきたバイト列」として参照できるのは、現在の位置から 32,768 バイト前までである。

今回の実験結果の考察

ランダムデータを格納した JPEG ファイル

ランダムデータを格納した JPEG ファイルでは、画像データのエントロピーが高くなり、圧縮が効きにくくなるはずである。
実際に CyberChef の Entropy オペレーションで確かめてみる。

以下は、今回生成した解像度 192x192 の画像ファイルの一つに対し、この Entropy オペレーションを Curve モードで適用した結果である。

画像データのエントロピー

ファイルのほとんどの部分について、エントロピーは 7 前後と高くなっていることがわかる。
さらに、Take Bytes オペレーションでこの画像ファイルの最初の 1,024 バイトを取り出し、同様に Entropy オペレーションを適用すると、以下のようになった。

画像データの冒頭のエントロピー

画像の最初の部分のみ、エントロピーが他より低くなっていることがわかる。
この部分は、画像の最初の 328 バイトを占める圧縮データ以外の部分に対応していると考えられる。
よって、この圧縮データ以外の部分については、画像の圧縮データよりも圧縮が効きやすいことが期待できる。

さらに、今回は JPEG 画像群の生成の際にハフマン符号の最適化を抑止したので、ハフマン符号の情報を含むこの「圧縮データ以外の部分」は、異なる画像でも解像度が同じなら (今回は) 同じになることが期待できる。

DEFLATE 圧縮によるデータの再利用

今回生成した解像度 192x192 の JPEG 画像は、1 ファイルあたり 31,371 バイトである。
tar 形式で各ファイルに追加されるヘッダは 512 バイトであり、さらにファイルのデータの終わりが 512 バイト境界にパディングされるため、これらを足すと 32,395 バイトとなる。
これは 32,768 バイトより小さいので、tar 形式で冒頭が共通しているこれらのファイルをまとめると、DEFLATE 圧縮を行う際に冒頭部分のデータを再利用できることが期待できる。

一方、解像度 200x200 の JPEG 画像は 1 ファイルあたり 34,010 バイトであり、32,768 バイトを超えてしまう。
そのため、32,768 バイト前までしか参照できない DEFLATE 圧縮では冒頭部分のデータを再利用できず、毎回 1 バイトずつ (もしくは、1 個の冒頭部分の中にある再利用できる部分は再利用して) 記述することになってしまうだろう。

このことにより、192x192 以下の解像度では冒頭部分のデータを再利用できる分 tar.gz 形式が zip 形式より有利になる一方、200x200 以上の解像度では tar.gz 形式でも冒頭部分のデータを再利用できないため、ファイルごとに分かれているために再利用できない zip 形式に近い圧縮率になると考えられる。
とはいえ、tar.gz 形式ではファイルのメタデータも圧縮の対象になるため、メタデータを圧縮しない zip 形式よりも若干有利になったと推測できる。

まとめ

冒頭部分のデータが共通し、ファイルサイズが DEFLATE 圧縮でデータの再利用が可能な距離の上限である 32,768 バイト前後の JPEG ファイルを大量に生成した。
そして、それらを zip 形式と tar.gz 形式で圧縮し、圧縮率を比較した。
すると、あるファイルサイズから tar.gz 形式の圧縮率が悪くなる様子を観察できた。
これは、同じデータ間の距離が 32,768 バイトを超え、データの再利用ができなくなったためであると考えられる。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?