0
0

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画像を無劣化(ロスレス)で切り貼りしたい ~ハフマン符号の読み方の答え~

Posted at

前回のラブライブ!

【調査中】JPEG画像を無劣化(ロスレス)で切り貼りしたい【ハフマン符号】 #画像処理 - Qiita

  • JPEG画像を無劣化でトリミングしたり、左右に連結したりできるとするソフトウェアを紹介した
  • JPEG画像内のハフマン符号の観察を行い、deflate と似た技術で符号が記述されていると予想した

別の表現をされた同じ(だろう)データの用意

圧縮をかけると、圧縮のしかたによって得られる画像に違いが出る可能性がある。
とはいえ、品質を 100 にして圧縮を避けることで、同じ画像が得られるかもしれないと考えた。
そこで、まず「8×8の緑背景で左上だけ黒いブロックを3個横に並べたPNG画像」を用意し、これを以下のソフトウェアでJPEGに変換した。

GIMP における品質以外の保存設定は、以下のようにした。

  • 各種「保存」(Exif データなど):オフ
  • コメント:空
  • Use arithmetic coding:オフ
  • プログレッシブ:オフ
  • スムージング:0.00
  • リスタートマーカー:オフ
  • サブサンプリング:4:4:4 (最高品質)
  • DCT 変換方法:整数

以下が、元の画像と各ソフトウェアで変換した画像ファイルの hexdump である。

元の画像 (PNG)
test_green_dot_24x8.png
00000000  89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52  |.PNG........IHDR|
00000010  00 00 00 18 00 00 00 08 08 06 00 00 00 e3 a1 3f  |...............?|
00000020  63 00 00 00 01 73 52 47 42 00 ae ce 1c e9 00 00  |c....sRGB.......|
00000030  00 04 67 41 4d 41 00 00 b1 8f 0b fc 61 05 00 00  |..gAMA......a...|
00000040  00 09 70 48 59 73 00 00 0e c3 00 00 0e c3 01 c7  |..pHYs..........|
00000050  6f a8 64 00 00 00 2b 49 44 41 54 38 4f ad c9 b1  |o.d...+IDAT8O...|
00000060  0d 00 30 0c 80 30 fe 7f 3a dd 83 94 a5 c8 1b 00  |..0..0..:.......|
00000070  cc e9 fb ef 50 53 a8 29 d4 14 6a 0a 35 85 9a 42  |....PS.)..j.5..B|
00000080  ec 01 75 e0 7b 93 47 3f c0 92 00 00 00 00 49 45  |..u.{.G?......IE|
00000090  4e 44 ae 42 60 82                                |ND.B`.|
ImageMagick で変換した画像
test_green_dot_24x8_magick_q100.jpg
00000000  ff d8 ff e0 00 10 4a 46 49 46 00 01 01 02 00 25  |......JFIF.....%|
00000010  00 25 00 00 ff db 00 43 00 01 01 01 01 01 01 01  |.%.....C........|
00000020  01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01  |................|
00000030  01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01  |................|
00000040  01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01  |................|
00000050  01 01 01 01 01 01 01 01 01 ff db 00 43 01 01 01  |............C...|
00000060  01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01  |................|
00000070  01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01  |................|
00000080  01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01  |................|
00000090  01 01 01 01 01 01 01 01 01 01 01 01 01 01 ff c0  |................|
000000a0  00 11 08 00 08 00 18 03 01 11 00 02 11 01 03 11  |................|
000000b0  01 ff c4 00 15 00 01 01 00 00 00 00 00 00 00 00  |................|
000000c0  00 00 00 00 00 00 00 08 ff c4 00 19 10 01 01 01  |................|
000000d0  01 01 01 00 00 00 00 00 00 00 00 00 00 05 04 03  |................|
000000e0  06 02 01 ff c4 00 15 01 01 01 00 00 00 00 00 00  |................|
000000f0  00 00 00 00 00 00 00 00 00 0a ff c4 00 18 11 01  |................|
00000100  01 01 01 01 00 00 00 00 00 00 00 00 00 00 00 04  |................|
00000110  03 05 02 01 ff da 00 0c 03 01 00 02 11 03 11 00  |................|
00000120  3f 00 a7 45 14 6e 6c 62 79 de 74 93 00 e7 c0 32  |?..E.nlby.t....2|
00000130  01 42 08 58 25 2c 61 46 2e 5c a1 30 92 4c 87 2c  |.B.X%,aF.\.0.L.,|
00000140  22 38 c3 a2 c3 08 e0 82 3c 31 96 39 71 ca 79 f2  |"8......<1.9q.y.|
00000150  cf 1c fc 78 f9 2d 2f 7b b5 1c cd 3d 36 2f 47 4b  |...x.-/{...=6/GK|
00000160  45 68 7e 86 83 d1 66 39 ee 65 bb 42 d8 c5 a3 ba  |Eh~...f9.e.B....|
00000170  5d 4b 55 e9 4b a1 17 a7 76 bd bb ee b5 ef ae fa  |]KU.K...v.......|
00000180  eb af 62 d3 4f 4f 4b 6b 4b 43 63 63 41 ba da fa  |..b.OOKkKCccA...|
00000190  cd 5e 9e ae ae 9a ee fd 2d 3d 27 de 8a 76 86 83  |.^......-='..v..|
000001a0  95 4a a9 8d 62 ab 54 ad 69 ad 2e 8b d2 96 b5 3b  |.J..b.T.i......;|
000001b0  a7 7d 75 e8 51 46 e6 c6 27 9d e7 49 30 0e 7c 03  |.}u.QF..'..I0.|.|
000001c0  20 14 20 85 82 52 c6 14 62 e5 ca 13 09 24 c8 72  | . ..R..b....$.r|
000001d0  c2 23 8c 3a 2c 30 8e 08 23 c3 19 63 97 1c a7 9f  |.#.:,0..#..c....|
000001e0  2c f1 cf c7 8f 87 bd da 8e 66 9e 9b 17 a3 a5 a2  |,........f......|
000001f0  b4 3f 43 41 e8 b3 1c f7 32 dd a1 6c 62 d1 dd 2e  |.?CA....2..lb...|
00000200  a5 aa f4 a5 d0 8b d3 bb 5e dd f7 5a f7 d7 7d 75  |........^..Z..}u|
00000210  d7 ad 3d 3d 2d ad 2d 0d 8d 8d 06 eb 6b eb 35 7a  |..==-.-.....k.5z|
00000220  7a ba ba 6b bb f4 b4 f4 9f 7a 29 da 1a 0e 55 2a  |z..k.....z)...U*|
00000230  a6 35 8a ad 52 b5 a6 b4 ba 2f 4a 5a d4 ee 9d f5  |.5..R..../JZ....|
00000240  d7 a1 45 1b 9b 18 9e 77 9d 24 c0 39 f0 0c 80 50  |..E....w.$.9...P|
00000250  82 16 09 4b 18 51 8b 97 28 4c 24 93 21 cb 08 8e  |...K.Q..(L$.!...|
00000260  30 e8 b0 c2 38 20 8f 0c 65 8e 5c 72 9e 7c b3 c7  |0...8 ..e.\r.|..|
00000270  3f 1e 3e 1e f7 6a 39 9a 7a 6c 5e 8e 96 8a d0 fd  |?.>..j9.zl^.....|
00000280  0d 07 a2 cc 73 dc cb 76 85 b1 8b 47 74 ba 96 ab  |....s..v...Gt...|
00000290  d2 97 42 2f 4e ed 7b 77 dd 6b df 5d f5 d7 5e b4  |..B/N.{w.k.]..^.|
000002a0  f4 f4 b6 b4 b4 36 36 34 1b ad af ac d5 e9 ea ea  |.....664........|
000002b0  e9 ae ef d2 d3 d2 7d e8 a7 68 68 39 54 aa 98 d6  |......}..hh9T...|
000002c0  2a b5 4a d6 9a d2 e8 bd 29 6b 53 ba 77 d7 5e ff  |*.J.....)kS.w.^.|
000002d0  00 ff d9                                         |...|
JTrim で変換した画像
test_green_dot_24x8_jtrim_q100.jpg
00000000  ff d8 ff e0 00 10 4a 46 49 46 00 01 01 00 00 01  |......JFIF......|
00000010  00 01 00 00 ff db 00 43 00 01 01 01 01 01 01 01  |.......C........|
00000020  01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01  |................|
00000030  01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01  |................|
00000040  01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01  |................|
00000050  01 01 01 01 01 01 01 01 01 ff db 00 43 01 01 01  |............C...|
00000060  01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01  |................|
00000070  01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01  |................|
00000080  01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01  |................|
00000090  01 01 01 01 01 01 01 01 01 01 01 01 01 01 ff c0  |................|
000000a0  00 11 08 00 08 00 18 03 01 22 00 02 11 01 03 11  |........."......|
000000b0  01 ff c4 00 1f 00 00 01 05 01 01 01 01 01 01 00  |................|
000000c0  00 00 00 00 00 00 00 01 02 03 04 05 06 07 08 09  |................|
000000d0  0a 0b ff c4 00 b5 10 00 02 01 03 03 02 04 03 05  |................|
000000e0  05 04 04 00 00 01 7d 01 02 03 00 04 11 05 12 21  |......}........!|
000000f0  31 41 06 13 51 61 07 22 71 14 32 81 91 a1 08 23  |1A..Qa."q.2....#|
00000100  42 b1 c1 15 52 d1 f0 24 33 62 72 82 09 0a 16 17  |B...R..$3br.....|
00000110  18 19 1a 25 26 27 28 29 2a 34 35 36 37 38 39 3a  |...%&'()*456789:|
00000120  43 44 45 46 47 48 49 4a 53 54 55 56 57 58 59 5a  |CDEFGHIJSTUVWXYZ|
00000130  63 64 65 66 67 68 69 6a 73 74 75 76 77 78 79 7a  |cdefghijstuvwxyz|
00000140  83 84 85 86 87 88 89 8a 92 93 94 95 96 97 98 99  |................|
00000150  9a a2 a3 a4 a5 a6 a7 a8 a9 aa b2 b3 b4 b5 b6 b7  |................|
00000160  b8 b9 ba c2 c3 c4 c5 c6 c7 c8 c9 ca d2 d3 d4 d5  |................|
00000170  d6 d7 d8 d9 da e1 e2 e3 e4 e5 e6 e7 e8 e9 ea f1  |................|
00000180  f2 f3 f4 f5 f6 f7 f8 f9 fa ff c4 00 1f 01 00 03  |................|
00000190  01 01 01 01 01 01 01 01 01 00 00 00 00 00 00 01  |................|
000001a0  02 03 04 05 06 07 08 09 0a 0b ff c4 00 b5 11 00  |................|
000001b0  02 01 02 04 04 03 04 07 05 04 04 00 01 02 77 00  |..............w.|
000001c0  01 02 03 11 04 05 21 31 06 12 41 51 07 61 71 13  |......!1..AQ.aq.|
000001d0  22 32 81 08 14 42 91 a1 b1 c1 09 23 33 52 f0 15  |"2...B.....#3R..|
000001e0  62 72 d1 0a 16 24 34 e1 25 f1 17 18 19 1a 26 27  |br...$4.%.....&'|
000001f0  28 29 2a 35 36 37 38 39 3a 43 44 45 46 47 48 49  |()*56789:CDEFGHI|
00000200  4a 53 54 55 56 57 58 59 5a 63 64 65 66 67 68 69  |JSTUVWXYZcdefghi|
00000210  6a 73 74 75 76 77 78 79 7a 82 83 84 85 86 87 88  |jstuvwxyz.......|
00000220  89 8a 92 93 94 95 96 97 98 99 9a a2 a3 a4 a5 a6  |................|
00000230  a7 a8 a9 aa b2 b3 b4 b5 b6 b7 b8 b9 ba c2 c3 c4  |................|
00000240  c5 c6 c7 c8 c9 ca d2 d3 d4 d5 d6 d7 d8 d9 da e2  |................|
00000250  e3 e4 e5 e6 e7 e8 e9 ea f2 f3 f4 f5 f6 f7 f8 f9  |................|
00000260  fa ff da 00 0c 03 01 00 02 11 03 11 00 3f 00 fa  |.............?..|
00000270  77 45 d1 74 6f 0d e8 da 4f 87 7c 3b a4 e9 9a 07  |wE.to...O.|;....|
00000280  87 f4 0d 32 c3 45 d0 b4 2d 16 c2 d7 4b d1 b4 5d  |...2.E..-...K..]|
00000290  1b 4b b5 8a c7 4c d2 74 9d 32 c6 28 2c b4 ed 33  |.K...L.t.2.(,..3|
000002a0  4e b2 82 0b 3b 0b 0b 38 21 b5 b3 b5 86 2b 7b 78  |N...;..8!....+{x|
000002b0  a3 86 34 40 68 ba 2e 8d e1 bd 1b 49 f0 ef 87 74  |..4@h......I...t|
000002c0  9d 33 40 f0 fe 81 a6 58 68 ba 16 85 a2 d8 5a e9  |.3@....Xh.....Z.|
000002d0  7a 36 8b a3 69 76 b1 58 e9 9a 4e 93 a6 58 c5 05  |z6..iv.X..N..X..|
000002e0  96 9d a6 69 d6 50 41 67 61 61 67 04 36 b6 76 b0  |...i.PAgaag.6.v.|
000002f0  c5 6f 6f 14 70 c6 88 0a 2b fe 59 27 5e bd 4f 6b  |.oo.p...+.Y'^.Ok|
00000300  ed 2b 55 9f b7 aa ab d7 e7 a9 39 7b 6a eb da 5a  |.+U.......9{j..Z|
00000310  b5 5e 69 3f 69 55 7b 6a d6 a9 3b cd 7b 5a 96 97  |.^i?iU{j..;.{Z..|
00000320  ef 25 7f f8 ae a9 89 c4 d5 f6 fe d7 11 5e a7 d6  |.%...........^..|
00000330  6b ac 4e 27 da 55 a9 3f ac 62 63 ed b9 71 15 f9  |k.N'.U.?.bc..q..|
00000340  a4 fd ad 78 fd 62 bd aa d4 e6 a8 bd bd 6b 4b f7  |...x.b.......kK.|
00000350  93 e6 34 5d 17 46 f0 de 8d a4 f8 77 c3 ba 4e 99  |..4].F.....w..N.|
00000360  a0 78 7f 40 d3 2c 34 5d 0b 42 d1 6c 2d 74 bd 1b  |.x.@.,4].B.l-t..|
00000370  45 d1 b4 bb 58 ac 74 cd 27 49 d3 2c 62 82 cb 4e  |E...X.t.'I.,b..N|
00000380  d3 34 eb 28 20 b3 b0 b0 b3 82 1b 5b 3b 58 62 b7  |.4.( ......[;Xb.|
00000390  b7 8a 38 63 44 05 14 54 d4 a9 3a b5 27 56 ac e7  |..8cD..T..:.'V..|
000003a0  52 ad 49 ca a5 4a 95 24 e7 52 a4 e6 dc a7 39 ce  |R.I..J.$.R....9.|
000003b0  4d ca 53 94 9b 94 a5 26 dc 9b 6d b6 d9 9d 5a b5  |M.S....&..m...Z.|
000003c0  2b d4 a9 5a b5 49 d6 ad 5a 73 ab 56 ad 59 ca a5  |+..Z.I..Zs.V.Y..|
000003d0  4a b5 2a 49 ce a5 4a 95 26 dc a7 39 c9 b9 4e 72  |J.*I..J.&..9..Nr|
000003e0  6e 52 93 6d b6 db 67 ff d9                       |nR.m..g..|
GIMP で変換した画像 (最適化オン)
test_green_dot_24x8_gimp_q100.jpg
00000000  ff d8 ff e0 00 10 4a 46 49 46 00 01 01 02 00 25  |......JFIF.....%|
00000010  00 25 00 00 ff db 00 43 00 01 01 01 01 01 01 01  |.%.....C........|
00000020  01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01  |................|
00000030  01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01  |................|
00000040  01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01  |................|
00000050  01 01 01 01 01 01 01 01 01 ff db 00 43 01 01 01  |............C...|
00000060  01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01  |................|
00000070  01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01  |................|
00000080  01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01  |................|
00000090  01 01 01 01 01 01 01 01 01 01 01 01 01 01 ff c0  |................|
000000a0  00 11 08 00 08 00 18 03 01 11 00 02 11 01 03 11  |................|
000000b0  01 ff c4 00 15 00 01 01 00 00 00 00 00 00 00 00  |................|
000000c0  00 00 00 00 00 00 00 08 ff c4 00 19 10 01 01 01  |................|
000000d0  01 01 01 00 00 00 00 00 00 00 00 00 00 05 04 03  |................|
000000e0  06 02 01 ff c4 00 15 01 01 01 00 00 00 00 00 00  |................|
000000f0  00 00 00 00 00 00 00 00 00 0a ff c4 00 18 11 01  |................|
00000100  01 01 01 01 00 00 00 00 00 00 00 00 00 00 00 04  |................|
00000110  03 05 02 01 ff da 00 0c 03 01 00 02 11 03 11 00  |................|
00000120  3f 00 a7 45 14 6e 6c 62 79 de 74 93 00 e7 c0 32  |?..E.nlby.t....2|
00000130  01 42 08 58 25 2c 61 46 2e 5c a1 30 92 4c 87 2c  |.B.X%,aF.\.0.L.,|
00000140  22 38 c3 a2 c3 08 e0 82 3c 31 96 39 71 ca 79 f2  |"8......<1.9q.y.|
00000150  cf 1c fc 78 f9 2d 2f 7b b5 1c cd 3d 36 2f 47 4b  |...x.-/{...=6/GK|
00000160  45 68 7e 86 83 d1 66 39 ee 65 bb 42 d8 c5 a3 ba  |Eh~...f9.e.B....|
00000170  5d 4b 55 e9 4b a1 17 a7 76 bd bb ee b5 ef ae fa  |]KU.K...v.......|
00000180  eb af 62 d3 4f 4f 4b 6b 4b 43 63 63 41 ba da fa  |..b.OOKkKCccA...|
00000190  cd 5e 9e ae ae 9a ee fd 2d 3d 27 de 8a 76 86 83  |.^......-='..v..|
000001a0  95 4a a9 8d 62 ab 54 ad 69 ad 2e 8b d2 96 b5 3b  |.J..b.T.i......;|
000001b0  a7 7d 75 e8 51 46 e6 c6 27 9d e7 49 30 0e 7c 03  |.}u.QF..'..I0.|.|
000001c0  20 14 20 85 82 52 c6 14 62 e5 ca 13 09 24 c8 72  | . ..R..b....$.r|
000001d0  c2 23 8c 3a 2c 30 8e 08 23 c3 19 63 97 1c a7 9f  |.#.:,0..#..c....|
000001e0  2c f1 cf c7 8f 87 bd da 8e 66 9e 9b 17 a3 a5 a2  |,........f......|
000001f0  b4 3f 43 41 e8 b3 1c f7 32 dd a1 6c 62 d1 dd 2e  |.?CA....2..lb...|
00000200  a5 aa f4 a5 d0 8b d3 bb 5e dd f7 5a f7 d7 7d 75  |........^..Z..}u|
00000210  d7 ad 3d 3d 2d ad 2d 0d 8d 8d 06 eb 6b eb 35 7a  |..==-.-.....k.5z|
00000220  7a ba ba 6b bb f4 b4 f4 9f 7a 29 da 1a 0e 55 2a  |z..k.....z)...U*|
00000230  a6 35 8a ad 52 b5 a6 b4 ba 2f 4a 5a d4 ee 9d f5  |.5..R..../JZ....|
00000240  d7 a1 45 1b 9b 18 9e 77 9d 24 c0 39 f0 0c 80 50  |..E....w.$.9...P|
00000250  82 16 09 4b 18 51 8b 97 28 4c 24 93 21 cb 08 8e  |...K.Q..(L$.!...|
00000260  30 e8 b0 c2 38 20 8f 0c 65 8e 5c 72 9e 7c b3 c7  |0...8 ..e.\r.|..|
00000270  3f 1e 3e 1e f7 6a 39 9a 7a 6c 5e 8e 96 8a d0 fd  |?.>..j9.zl^.....|
00000280  0d 07 a2 cc 73 dc cb 76 85 b1 8b 47 74 ba 96 ab  |....s..v...Gt...|
00000290  d2 97 42 2f 4e ed 7b 77 dd 6b df 5d f5 d7 5e b4  |..B/N.{w.k.]..^.|
000002a0  f4 f4 b6 b4 b4 36 36 34 1b ad af ac d5 e9 ea ea  |.....664........|
000002b0  e9 ae ef d2 d3 d2 7d e8 a7 68 68 39 54 aa 98 d6  |......}..hh9T...|
000002c0  2a b5 4a d6 9a d2 e8 bd 29 6b 53 ba 77 d7 5e ff  |*.J.....)kS.w.^.|
000002d0  00 ff d9                                         |...|
GIMP で変換した画像 (最適化オフ)
test_green_dot_24x8_gimp_q100_noopt.jpg
00000000  ff d8 ff e0 00 10 4a 46 49 46 00 01 01 02 00 25  |......JFIF.....%|
00000010  00 25 00 00 ff db 00 43 00 01 01 01 01 01 01 01  |.%.....C........|
00000020  01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01  |................|
00000030  01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01  |................|
00000040  01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01  |................|
00000050  01 01 01 01 01 01 01 01 01 ff db 00 43 01 01 01  |............C...|
00000060  01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01  |................|
00000070  01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01  |................|
00000080  01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01  |................|
00000090  01 01 01 01 01 01 01 01 01 01 01 01 01 01 ff c0  |................|
000000a0  00 11 08 00 08 00 18 03 01 11 00 02 11 01 03 11  |................|
000000b0  01 ff c4 00 1f 00 00 01 05 01 01 01 01 01 01 00  |................|
000000c0  00 00 00 00 00 00 00 01 02 03 04 05 06 07 08 09  |................|
000000d0  0a 0b ff c4 00 b5 10 00 02 01 03 03 02 04 03 05  |................|
000000e0  05 04 04 00 00 01 7d 01 02 03 00 04 11 05 12 21  |......}........!|
000000f0  31 41 06 13 51 61 07 22 71 14 32 81 91 a1 08 23  |1A..Qa."q.2....#|
00000100  42 b1 c1 15 52 d1 f0 24 33 62 72 82 09 0a 16 17  |B...R..$3br.....|
00000110  18 19 1a 25 26 27 28 29 2a 34 35 36 37 38 39 3a  |...%&'()*456789:|
00000120  43 44 45 46 47 48 49 4a 53 54 55 56 57 58 59 5a  |CDEFGHIJSTUVWXYZ|
00000130  63 64 65 66 67 68 69 6a 73 74 75 76 77 78 79 7a  |cdefghijstuvwxyz|
00000140  83 84 85 86 87 88 89 8a 92 93 94 95 96 97 98 99  |................|
00000150  9a a2 a3 a4 a5 a6 a7 a8 a9 aa b2 b3 b4 b5 b6 b7  |................|
00000160  b8 b9 ba c2 c3 c4 c5 c6 c7 c8 c9 ca d2 d3 d4 d5  |................|
00000170  d6 d7 d8 d9 da e1 e2 e3 e4 e5 e6 e7 e8 e9 ea f1  |................|
00000180  f2 f3 f4 f5 f6 f7 f8 f9 fa ff c4 00 1f 01 00 03  |................|
00000190  01 01 01 01 01 01 01 01 01 00 00 00 00 00 00 01  |................|
000001a0  02 03 04 05 06 07 08 09 0a 0b ff c4 00 b5 11 00  |................|
000001b0  02 01 02 04 04 03 04 07 05 04 04 00 01 02 77 00  |..............w.|
000001c0  01 02 03 11 04 05 21 31 06 12 41 51 07 61 71 13  |......!1..AQ.aq.|
000001d0  22 32 81 08 14 42 91 a1 b1 c1 09 23 33 52 f0 15  |"2...B.....#3R..|
000001e0  62 72 d1 0a 16 24 34 e1 25 f1 17 18 19 1a 26 27  |br...$4.%.....&'|
000001f0  28 29 2a 35 36 37 38 39 3a 43 44 45 46 47 48 49  |()*56789:CDEFGHI|
00000200  4a 53 54 55 56 57 58 59 5a 63 64 65 66 67 68 69  |JSTUVWXYZcdefghi|
00000210  6a 73 74 75 76 77 78 79 7a 82 83 84 85 86 87 88  |jstuvwxyz.......|
00000220  89 8a 92 93 94 95 96 97 98 99 9a a2 a3 a4 a5 a6  |................|
00000230  a7 a8 a9 aa b2 b3 b4 b5 b6 b7 b8 b9 ba c2 c3 c4  |................|
00000240  c5 c6 c7 c8 c9 ca d2 d3 d4 d5 d6 d7 d8 d9 da e2  |................|
00000250  e3 e4 e5 e6 e7 e8 e9 ea f2 f3 f4 f5 f6 f7 f8 f9  |................|
00000260  fa ff da 00 0c 03 01 00 02 11 03 11 00 3f 00 fa  |.............?..|
00000270  77 45 d1 74 6f 0d e8 da 4f 87 7c 3b a4 e9 9a 07  |wE.to...O.|;....|
00000280  87 f4 0d 32 c3 45 d0 b4 2d 16 c2 d7 4b d1 b4 5d  |...2.E..-...K..]|
00000290  1b 4b b5 8a c7 4c d2 74 9d 32 c6 28 2c b4 ed 33  |.K...L.t.2.(,..3|
000002a0  4e b2 82 0b 3b 0b 0b 38 21 b5 b3 b5 86 2b 7b 78  |N...;..8!....+{x|
000002b0  a3 86 34 41 ff 00 2d 38 fc 7e 3b 34 c7 63 33 3c  |..4A..-8.~;4.c3<|
000002c0  cf 19 8b cc 73 2c c7 17 88 c7 e6 19 86 3f 11 5b  |....s,.......?.[|
000002d0  19 8e c7 e3 b1 95 a7 88 c5 e3 31 98 bc 44 ea 57  |..........1..D.W|
000002e0  c5 62 f1 55 ea 54 af 88 c4 57 a9 3a d5 eb 4e 75  |.b.U.T...W.:..Nu|
000002f0  6a ce 53 94 a4 ff 00 e2 d3 33 cc f3 2c eb 32 cc  |j.S......3..,.2.|
00000300  33 8c e3 30 c6 e6 d9 be 6d 8d c5 e6 79 ae 6b 99  |3..0....m...y.k.|
00000310  e2 eb e3 f3 2c cf 32 c7 d7 a9 8a c7 66 19 86 3b  |....,.2.....f..;|
00000320  15 52 ae 2b 19 8d c6 62 aa d5 c4 e2 f1 78 9a b5  |.R.+...b.....x..|
00000330  2b e2 2b d4 a9 5a b5 49 d4 9c a4 cd 17 45 d1 bc  |+.+..Z.I.....E..|
00000340  37 a3 69 3e 1d f0 ee 93 a6 68 1e 1f d0 34 cb 0d  |7.i>.....h...4..|
00000350  17 42 d0 b4 5b 0b 5d 2f 46 d1 74 6d 2e d6 2b 1d  |.B..[.]/F.tm..+.|
00000360  33 49 d2 74 cb 18 a0 b2 d3 b4 cd 3a ca 08 2c ec  |3I.t.......:..,.|
00000370  2c 2c e0 86 d6 ce d6 18 ad ed e2 8e 18 d1 01 8f  |,,..............|
00000380  c7 e3 b3 4c 76 33 33 cc f1 98 bc c7 32 cc 71 78  |...Lv33.....2.qx|
00000390  8c 7e 61 98 63 f1 15 b1 98 ec 7e 3b 19 5a 78 8c  |.~a.c.....~;.Zx.|
000003a0  5e 33 19 8b c4 4e a5 7c 56 2f 15 5e a5 4a f8 8c  |^3...N.|V/.^.J..|
000003b0  45 7a 93 ad 5e b4 e7 56 ac e5 39 4a 4c cc f3 3c  |Ez..^..V..9JL..<|
000003c0  cb 3a cc b3 0c e3 38 cc 31 b9 b6 6f 9b 63 71 79  |.:....8.1..o.cqy|
000003d0  9e 6b 9a e6 78 ba f8 fc cb 33 cc b1 f5 ea 62 b1  |.k..x....3....b.|
000003e0  d9 86 61 8e c5 54 ab 8a c6 63 71 98 aa b5 71 38  |..a..T...cq...q8|
000003f0  bc 5e 26 ad 4a f8 8a f5 2a 56 ad 52 75 27 29 33  |.^&.J...*V.Ru')3|
00000400  45 d1 74 6f 0d e8 da 4f 87 7c 3b a4 e9 9a 07 87  |E.to...O.|;.....|
00000410  f4 0d 32 c3 45 d0 b4 2d 16 c2 d7 4b d1 b4 5d 1b  |..2.E..-...K..].|
00000420  4b b5 8a c7 4c d2 74 9d 32 c6 28 2c b4 ed 33 4e  |K...L.t.2.(,..3N|
00000430  b2 82 0b 3b 0b 0b 38 21 b5 b3 b5 86 2b 7b 78 a3  |...;..8!....+{x.|
00000440  86 34 40 63 f1 f8 ec d3 1d 8c cc f3 3c 66 2f 31  |.4@c........<f/1|
00000450  cc b3 1c 5e 23 1f 98 66 18 fc 45 6c 66 3b 1f 8e  |...^#..f..Elf;..|
00000460  c6 56 9e 23 17 8c c6 62 f1 13 a9 5f 15 8b c5 57  |.V.#...b..._...W|
00000470  a9 52 be 23 11 5e a4 eb 57 ad 39 d5 ab 39 4e 52  |.R.#.^..W.9..9NR|
00000480  93 33 3c cf 32 ce b3 2c c3 38 ce 33 0c 6e 6d 9b  |.3<.2..,.8.3.nm.|
00000490  e6 d8 dc 5e 67 9a e6 b9 9e 2e be 3f 32 cc f3 2c  |...^g......?2..,|
000004a0  7d 7a 98 ac 76 61 98 63 b1 55 2a e2 b1 98 dc 66  |}z..va.c.U*....f|
000004b0  2a ad 5c 4e 2f 17 89 ab 52 be 22 bd 4a 95 ab 54  |*.\N/...R.".J..T|
000004c0  9d 49 ca 4f ff d9                                |.I.O..|

すると、以下のことがわかった。

  • ImageMagick で変換した画像と GIMP で変換した画像 (最適化オン) は、全く同じ (SHA-1 ハッシュ値が同じ) である
  • ImageMagick の compare で比較した結果、GIMP で変換した2種類の画像は同じ内容であり、これらは JTrim で変換した画像とは異なる内容である

確実ではないものの、画像の内容が同じということは、記録されている内容も同じ可能性が高いと考えられる。
そこで、TSXBIN を用いて、GIMP で変換した2種類の画像のハフマン符号テーブル情報を見てみた。
結果は以下である。

最適化オン
0B1  ★DHT[0]              FF C4
0B3  SizeOfThis[0]         00 15
0B5  Th                    00
0B6  DCHaffman[0]          01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0C6  DCHaffman[16]         00 08
0C8  ★DHT[0]              FF C4
0CA  SizeOfThis[0]         00 19
0CC  Th                    10
0CD  ACHaffman[0]          01 01 01 01 01 01 00 00 00 00 00 00 00 00 00 00
0DD  ACHaffman[16]         05 04 03 06 02 01
0E3  ★DHT[0]              FF C4
0E5  SizeOfThis[0]         00 15
0E7  Th                    01
0E8  DCHaffman[0]          01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0F8  DCHaffman[16]         00 0A
0FA  ★DHT[0]              FF C4
0FC  SizeOfThis[0]         00 18
0FE  Th                    11
0FF  ACHaffman[0]          01 01 01 01 01 00 00 00 00 00 00 00 00 00 00 00
10F  ACHaffman[16]         04 03 05 02 01
最適化オフ
0B1  ★DHT[0]              FF C4
0B3  SizeOfThis[0]         00 1F
0B5  Th                    00
0B6  DCHaffman[0]          00 01 05 01 01 01 01 01 01 00 00 00 00 00 00 00
0C6  DCHaffman[16]         00 01 02 03 04 05 06 07 08 09 0A 0B
0D2  ★DHT[0]              FF C4
0D4  SizeOfThis[0]         00 B5
0D6  Th                    10
0D7  ACHaffman[0]          00 02 01 03 03 02 04 03 05 05 04 04 00 00 01 7D
0E7  ACHaffman[16]         01 02 03 00 04 11 05 12 21 31 41 06 13 51 61 07
0F7  ACHaffman[32]         22 71 14 32 81 91 A1 08 23 42 B1 C1 15 52 D1 F0
107  ACHaffman[48]         24 33 62 72 82 09 0A 16 17 18 19 1A 25 26 27 28
117  ACHaffman[64]         29 2A 34 35 36 37 38 39 3A 43 44 45 46 47 48 49
127  ACHaffman[80]         4A 53 54 55 56 57 58 59 5A 63 64 65 66 67 68 69
137  ACHaffman[96]         6A 73 74 75 76 77 78 79 7A 83 84 85 86 87 88 89
147  ACHaffman[112]        8A 92 93 94 95 96 97 98 99 9A A2 A3 A4 A5 A6 A7
157  ACHaffman[128]        A8 A9 AA B2 B3 B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5
167  ACHaffman[144]        C6 C7 C8 C9 CA D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2
177  ACHaffman[160]        E3 E4 E5 E6 E7 E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8
187  ACHaffman[176]        F9 FA
189  ★DHT[0]              FF C4
18B  SizeOfThis[0]         00 1F
18D  Th                    01
18E  DCHaffman[0]          00 03 01 01 01 01 01 01 01 01 01 00 00 00 00 00
19E  DCHaffman[16]         00 01 02 03 04 05 06 07 08 09 0A 0B
1AA  ★DHT[0]              FF C4
1AC  SizeOfThis[0]         00 B5
1AE  Th                    11
1AF  ACHaffman[0]          00 02 01 02 04 04 03 04 07 05 04 04 00 01 02 77
1BF  ACHaffman[16]         00 01 02 03 11 04 05 21 31 06 12 41 51 07 61 71
1CF  ACHaffman[32]         13 22 32 81 08 14 42 91 A1 B1 C1 09 23 33 52 F0
1DF  ACHaffman[48]         15 62 72 D1 0A 16 24 34 E1 25 F1 17 18 19 1A 26
1EF  ACHaffman[64]         27 28 29 2A 35 36 37 38 39 3A 43 44 45 46 47 48
1FF  ACHaffman[80]         49 4A 53 54 55 56 57 58 59 5A 63 64 65 66 67 68
20F  ACHaffman[96]         69 6A 73 74 75 76 77 78 79 7A 82 83 84 85 86 87
21F  ACHaffman[112]        88 89 8A 92 93 94 95 96 97 98 99 9A A2 A3 A4 A5
22F  ACHaffman[128]        A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 B8 B9 BA C2 C3
23F  ACHaffman[144]        C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 D6 D7 D8 D9 DA
24F  ACHaffman[160]        E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 F4 F5 F6 F7 F8
25F  ACHaffman[176]        F9 FA

最適化オンのときは、画像データで用いる最低限のデータをハフマン符号テーブルに載せていそうである。
一方、最適化オフのときは、画像データで用いないデータも含む?多くのデータがハフマン符号テーブルに載り、比較的複雑な符号になりそうである。

また、品質を 90 にした場合でも、GIMP の最適化オンとオフで今回変換した画像の内容は変わらなかった。

各符号長の符号が1個ずつしか無いデータの観察

より小さいデータで観察するため、白背景の8x8で左上だけ黒いPNG画像を用意し、GIMP で JPEG に変換した。
なお、普通に変換すると3個のコンポーネントがみられたので、画像を読み込んだあとメニューの「画像 → モード」で「グレースケール」を選択し、変換を行った。

元画像 (PNG)
test_white_dot_8x8.png
00000000  89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52  |.PNG........IHDR|
00000010  00 00 00 08 00 00 00 08 08 06 00 00 00 c4 0f be  |................|
00000020  8b 00 00 00 01 73 52 47 42 00 ae ce 1c e9 00 00  |.....sRGB.......|
00000030  00 04 67 41 4d 41 00 00 b1 8f 0b fc 61 05 00 00  |..gAMA......a...|
00000040  00 09 70 48 59 73 00 00 0e c3 00 00 0e c3 01 c7  |..pHYs..........|
00000050  6f a8 64 00 00 00 13 49 44 41 54 28 53 63 60 60  |o.d....IDAT(Sc``|
00000060  60 f8 8f 0f e0 97 1d 36 0a 00 75 9a fc 04 ca 40  |`......6..u....@|
00000070  e7 f3 00 00 00 00 49 45 4e 44 ae 42 60 82        |......IEND.B`.|
GIMP で変換した画像 (最適化オン)
test_white_dot_8x8_gimp_q100_gray.jpg
00000000  ff d8 ff e0 00 10 4a 46 49 46 00 01 01 02 00 25  |......JFIF.....%|
00000010  00 25 00 00 ff db 00 43 00 01 01 01 01 01 01 01  |.%.....C........|
00000020  01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01  |................|
00000030  01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01  |................|
00000040  01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01  |................|
00000050  01 01 01 01 01 01 01 01 01 ff c0 00 0b 08 00 08  |................|
00000060  00 08 01 01 11 00 ff c4 00 14 00 01 00 00 00 00  |................|
00000070  00 00 00 00 00 00 00 00 00 00 00 0a ff c4 00 18  |................|
00000080  10 01 01 01 01 01 00 00 00 00 00 00 00 00 00 00  |................|
00000090  00 06 05 04 03 02 ff da 00 08 01 01 00 00 3f 00  |..............?.|
000000a0  7b 04 c9 95 04 54 c8 50 a6 4f 8b 12 2c fc 62 63  |{....T.P.O..,.bc|
000000b0  87 13 8d 38 e1 52 65 4e 4e cd 1c f1 93 27 a3 e6  |...8.ReNN....'..|
000000c0  c7 22 09 f8 52 31 e3 97 1a 34 bc 79 67 4b 9d 97  |."..R1...4.ygK..|
000000d0  36 1c 39 b8 66 e1 cb 97 9f ff d9                 |6.9.f......|
GIMP で変換した画像 (最適化オフ)
test_white_dot_8x8_gimp_q100_gray_noopt.jpg
00000000  ff d8 ff e0 00 10 4a 46 49 46 00 01 01 02 00 25  |......JFIF.....%|
00000010  00 25 00 00 ff db 00 43 00 01 01 01 01 01 01 01  |.%.....C........|
00000020  01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01  |................|
00000030  01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01  |................|
00000040  01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01  |................|
00000050  01 01 01 01 01 01 01 01 01 ff c0 00 0b 08 00 08  |................|
00000060  00 08 01 01 11 00 ff c4 00 1f 00 00 01 05 01 01  |................|
00000070  01 01 01 01 00 00 00 00 00 00 00 00 01 02 03 04  |................|
00000080  05 06 07 08 09 0a 0b ff c4 00 b5 10 00 02 01 03  |................|
00000090  03 02 04 03 05 05 04 04 00 00 01 7d 01 02 03 00  |...........}....|
000000a0  04 11 05 12 21 31 41 06 13 51 61 07 22 71 14 32  |....!1A..Qa."q.2|
000000b0  81 91 a1 08 23 42 b1 c1 15 52 d1 f0 24 33 62 72  |....#B...R..$3br|
000000c0  82 09 0a 16 17 18 19 1a 25 26 27 28 29 2a 34 35  |........%&'()*45|
000000d0  36 37 38 39 3a 43 44 45 46 47 48 49 4a 53 54 55  |6789:CDEFGHIJSTU|
000000e0  56 57 58 59 5a 63 64 65 66 67 68 69 6a 73 74 75  |VWXYZcdefghijstu|
000000f0  76 77 78 79 7a 83 84 85 86 87 88 89 8a 92 93 94  |vwxyz...........|
00000100  95 96 97 98 99 9a a2 a3 a4 a5 a6 a7 a8 a9 aa b2  |................|
00000110  b3 b4 b5 b6 b7 b8 b9 ba c2 c3 c4 c5 c6 c7 c8 c9  |................|
00000120  ca d2 d3 d4 d5 d6 d7 d8 d9 da e1 e2 e3 e4 e5 e6  |................|
00000130  e7 e8 e9 ea f1 f2 f3 f4 f5 f6 f7 f8 f9 fa ff da  |................|
00000140  00 08 01 01 00 00 3f 00 fe f6 3c 27 e1 3f 0a f8  |......?...<'.?..|
00000150  0b c2 be 19 f0 2f 81 7c 33 e1 ff 00 05 f8 27 c1  |...../.|3.....'.|
00000160  7e 1f d1 bc 27 e0 ef 07 78 4f 46 d3 bc 39 e1 5f  |~...'...xOF..9._|
00000170  09 f8 57 c3 9a 75 b6 8f e1 ef 0c f8 67 c3 da 3d  |..W..u......g..=|
00000180  b5 9e 91 a0 f8 7f 42 d2 2c ec f4 bd 1b 46 d2 ec  |......B.,....F..|
00000190  ed 74 ed 2f 4e b5 b6 b1 b1 b6 82 da 08 a2 5f ff  |.t./N........._.|
000001a0  d9                                               |.|

最適化オンのハフマン符号情報と圧縮データ (一部) は、以下のようになっていた。

ハフマン符号情報 (最適化オン)
66  ★DHT[0]            FF C4
68  SizeOfThis[0]       00 14
6A  Th                  00
6B  DCHaffman[0]        01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
7B  DCHaffman[16]       0A
7C  ★DHT[0]            FF C4
7E  SizeOfThis[0]       00 18
80  Th                  10
81  ACHaffman[0]        01 01 01 01 01 00 00 00 00 00 00 00 00 00 00 00
91  ACHaffman[16]       06 05 04 03 02
圧縮データの冒頭 (最適化オン)
A0  圧縮データ(57B)[0]  7B 04 C9 95 04 54 C8 50 A6 4F 8B 12 2C FC 62 63

最適化オフでは、以下のようになっていた。

ハフマン符号情報 (最適化オフ)
066  ★DHT[0]            FF C4
068  SizeOfThis[0]       00 1F
06A  Th                  00
06B  DCHaffman[0]        00 01 05 01 01 01 01 01 01 00 00 00 00 00 00 00
07B  DCHaffman[16]       00 01 02 03 04 05 06 07 08 09 0A 0B
087  ★DHT[0]            FF C4
089  SizeOfThis[0]       00 B5
08B  Th                  10
08C  ACHaffman[0]        00 02 01 03 03 02 04 03 05 05 04 04 00 00 01 7D
09C  ACHaffman[16]       01 02 03 00 04 11 05 12 21 31 41 06 13 51 61 07
0AC  ACHaffman[32]       22 71 14 32 81 91 A1 08 23 42 B1 C1 15 52 D1 F0
0BC  ACHaffman[48]       24 33 62 72 82 09 0A 16 17 18 19 1A 25 26 27 28
0CC  ACHaffman[64]       29 2A 34 35 36 37 38 39 3A 43 44 45 46 47 48 49
0DC  ACHaffman[80]       4A 53 54 55 56 57 58 59 5A 63 64 65 66 67 68 69
0EC  ACHaffman[96]       6A 73 74 75 76 77 78 79 7A 83 84 85 86 87 88 89
0FC  ACHaffman[112]      8A 92 93 94 95 96 97 98 99 9A A2 A3 A4 A5 A6 A7
10C  ACHaffman[128]      A8 A9 AA B2 B3 B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5
11C  ACHaffman[144]      C6 C7 C8 C9 CA D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2
12C  ACHaffman[160]      E3 E4 E5 E6 E7 E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8
13C  ACHaffman[176]      F9 FA
圧縮データの冒頭 (最適化オフ)
148  圧縮データ(87B)[0]  FE F6 3C 27 E1 3F 0A F8 0B C2 BE 19 F0 2F 81 7C

最適化オンのデータにおいて、各長さの符号の数が全て 0 または 1 となっている。
deflate と同様のハフマン符号が用いられていると仮定すれば、このとき、符号は 010110、… のように、全て「1 が何個か続き、最後に1個 0」のパターンになるはずである。
そのため、解析しやすそうである。

deflate と同様のハフマン符号が用いられていると仮定すれば、それぞれの画像におけるデータと符号の関係は、以下のようになる。

テーブル データ 最適化オン 最適化オフ
DC 0A 0 11111110
AC 02 11110 01
AC 03 1110 100
AC 04 110 1011
AC 05 10 11010
AC 06 0 1111000

さらに、CyberChef を用いて、圧縮データを 0/1 で表したものを 0 で区切ってみた。

Find / Replace, 3 more - CyberChef

この Recipe では、圧縮データ FFFF 00 で表すことは考慮していない。
今回は、手動でこの 00 を削除する対応をとった。

結果の冒頭は、以下のようになった。

最適化オン 最適化オフ
0
11110
110
0
0
0
0
10
0
110
11111110
11110
110
0
0
11110
0
0
0
10

1行目は、最適化オンが 0、最適化オフが 11111110 で、これはそれぞれのデータ 0A に対応する DC 用ハフマン符号のようである。
しかし、その後のデータはよくわからなかった。
更に、今回の最適化オンの画像におけるハフマン符号は5ビットまでのはずであるにもかかわらず、1111110 (上記圧縮データの冒頭の FC の部分に相当する) など6ビット以上の符号のようなものもみられた。
単純なハフマン符号ではないかもしれない……?

ググレカス

自分の頭だけで考えていても、らちがあかなそうなので、「jpeg ハフマン符号」でググってみた。
すると、以下のページが見つかった。

これらのページを読むことで、以下のことがわかった。

  • DC 成分は、「符号の後に何ビット追加するか」を符号で表す
  • AC 成分は、「その符号が表すデータの前に 0 のデータがいくつあるか」と「符号の後に何ビット追加するか」の組を符号で表す
  • それぞれ、符号の後に実際に追加するビット数分のビットを置く
  • AC 成分のデータは、全部で 63 個になるようにする
    • ただし、「これ以降のデータは全部 0」(EOB) を表す符号を用いることもある
  • ハフマン符号情報 (符号長ごとの符号数) からハフマン符号を構築する方法は、予想通り deflate で行う方法に近い

たとえば、先ほどの例においては、1行目で「追加データ10ビット」を表し、2~5行目の

11110
110
0
0

の部分がその追加データであると考えられそうである。

ハフマン符号の構築方法だけでなく、ハフマン符号に続けて追加のビット列を置く、という構造も、deflate に似ている。

最適化オフの画像における AC ハフマン符号のテーブルでは、多くのバイトが網羅されていそうであるにもかかわらず、なぜ FF ではなく FA までなのかが疑問だった。
しかし、この情報をもとに、

  • 上位ニブル (4ビット) が、データの前に置く 0 の数を表す
  • 下位ニブルが、符号の後に追加するビット数を表す

と仮定すれば、辻褄が合いそうである。
「ハフマン符号の後に追加のデータが配置される」ことがわかれば、圧縮データ内に符号としてはおかしいデータがあったこともうなづける。
とはいえ、これだけでは DC 用ハフマン符号と AC 用ハフマン符号をどう使い分けるかがわからない。

詳細な情報を可視化してくれるソフトウェア

上記サイトで言及されていた「jpegsnoop」は、以下のソフトウェアを表すと思われる。

GitHub - ImpulseAdventure/JPEGsnoop: JPEGsnoop: JPEG decoder and detailed analysis

メニューの「Options → Scan Segment → Detailed Decode...」からダイアログを開き、「Enable detailed Scan Decode?」をオンにした状態で解析を行うことで、圧縮データをハフマン符号と追加データに分解して出力してくれる。
設定を変更したら、メニューの「File → Reprocess File」を押すことで、開いているファイルを新しい設定で再解析してくれる。

以下の結果が得られた。

圧縮データの分解結果 (最適化オン)
圧縮データの分解結果 (最適化オン)
    Lum (Tbl #0), MCU=[0,0]
      [0x000000A0.0]: ZRL=[ 0] Val=[  984] Coef=[00= DC] Data=[0x 7B 04 C9 95 = 0b (01111011 000----- -------- --------)] 
      [0x000000A1.3]: ZRL=[ 0] Val=[  -44] Coef=[01..01] Data=[0x 04 C9 95 04 = 0b (---00100 11------ -------- --------)] 
      [0x000000A2.2]: ZRL=[ 0] Val=[  -44] Coef=[02..02] Data=[0x C9 95 04 54 = 0b (--001001 1------- -------- --------)] 
      [0x000000A3.1]: ZRL=[ 0] Val=[  -42] Coef=[03..03] Data=[0x 95 04 54 C8 = 0b (-0010101 -------- -------- --------)] 
      [0x000000A4.0]: ZRL=[ 0] Val=[  -61] Coef=[04..04] Data=[0x 04 54 C8 50 = 0b (0000010- -------- -------- --------)] 
      [0x000000A4.7]: ZRL=[ 0] Val=[  -42] Coef=[05..05] Data=[0x 04 54 C8 50 = 0b (-------0 010101-- -------- --------)] 
      [0x000000A5.6]: ZRL=[ 0] Val=[  -38] Coef=[06..06] Data=[0x 54 C8 50 A6 = 0b (------00 11001--- -------- --------)] 
      [0x000000A6.5]: ZRL=[ 0] Val=[  -58] Coef=[07..07] Data=[0x C8 50 A6 4F = 0b (-----000 0101---- -------- --------)] 
      [0x000000A7.4]: ZRL=[ 0] Val=[  -58] Coef=[08..08] Data=[0x 50 A6 4F 8B = 0b (----0000 101----- -------- --------)] 
      [0x000000A8.3]: ZRL=[ 0] Val=[  -38] Coef=[09..09] Data=[0x A6 4F 8B 12 = 0b (---00110 01------ -------- --------)] 
      [0x000000A9.2]: ZRL=[ 0] Val=[  -32] Coef=[10..10] Data=[0x 4F 8B 12 2C = 0b (--001111 1------- -------- --------)] 
      [0x000000AA.1]: ZRL=[ 0] Val=[  -52] Coef=[11..11] Data=[0x 8B 12 2C FC = 0b (-0001011 -------- -------- --------)] 
      [0x000000AB.0]: ZRL=[ 0] Val=[  -54] Coef=[12..12] Data=[0x 12 2C FC 62 = 0b (0001001- -------- -------- --------)] 
      [0x000000AB.7]: ZRL=[ 0] Val=[  -52] Coef=[13..13] Data=[0x 12 2C FC 62 = 0b (-------0 001011-- -------- --------)] 
      [0x000000AC.6]: ZRL=[ 0] Val=[  -32] Coef=[14..14] Data=[0x 2C FC 62 63 = 0b (------00 11111--- -------- --------)] 
      [0x000000AD.5]: ZRL=[ 0] Val=[  -25] Coef=[15..15] Data=[0x FC 62 63 87 = 0b (-----100 0110---- -------- --------)] 
      [0x000000AE.4]: ZRL=[ 0] Val=[  -44] Coef=[16..16] Data=[0x 62 63 87 13 = 0b (----0010 011----- -------- --------)] 
      [0x000000AF.3]: ZRL=[ 0] Val=[  -49] Coef=[17..17] Data=[0x 63 87 13 8D = 0b (---00011 10------ -------- --------)] 
      [0x000000B0.2]: ZRL=[ 0] Val=[  -49] Coef=[18..18] Data=[0x 87 13 8D 38 = 0b (--000111 0------- -------- --------)] 
      [0x000000B1.1]: ZRL=[ 0] Val=[  -44] Coef=[19..19] Data=[0x 13 8D 38 E1 = 0b (-0010011 -------- -------- --------)] 
      [0x000000B2.0]: ZRL=[ 0] Val=[  -25] Coef=[20..20] Data=[0x 8D 38 E1 52 = 0b (1000110- -------- -------- --------)] 
      [0x000000B2.7]: ZRL=[ 0] Val=[  -17] Coef=[21..21] Data=[0x 8D 38 E1 52 = 0b (-------1 001110-- -------- --------)] 
      [0x000000B3.6]: ZRL=[ 0] Val=[  -35] Coef=[22..22] Data=[0x 38 E1 52 65 = 0b (------00 11100--- -------- --------)] 
      [0x000000B4.5]: ZRL=[ 0] Val=[  -42] Coef=[23..23] Data=[0x E1 52 65 4E = 0b (-----001 0101---- -------- --------)] 
      [0x000000B5.4]: ZRL=[ 0] Val=[  -44] Coef=[24..24] Data=[0x 52 65 4E 4E = 0b (----0010 011----- -------- --------)] 
      [0x000000B6.3]: ZRL=[ 0] Val=[  -42] Coef=[25..25] Data=[0x 65 4E 4E CD = 0b (---00101 01------ -------- --------)] 
      [0x000000B7.2]: ZRL=[ 0] Val=[  -35] Coef=[26..26] Data=[0x 4E 4E CD 1C = 0b (--001110 0------- -------- --------)] 
      [0x000000B8.1]: ZRL=[ 0] Val=[  -17] Coef=[27..27] Data=[0x 4E CD 1C F1 = 0b (-1001110 -------- -------- --------)] 
      [0x000000B9.0]: ZRL=[ 0] Val=[   -9] Coef=[28..28] Data=[0x CD 1C F1 93 = 0b (1100110- -------- -------- --------)] 
      [0x000000B9.7]: ZRL=[ 0] Val=[  -24] Coef=[29..29] Data=[0x CD 1C F1 93 = 0b (-------1 000111-- -------- --------)] 
      [0x000000BA.6]: ZRL=[ 0] Val=[  -33] Coef=[30..30] Data=[0x 1C F1 93 27 = 0b (------00 11110--- -------- --------)] 
      [0x000000BB.5]: ZRL=[ 0] Val=[  -38] Coef=[31..31] Data=[0x F1 93 27 A3 = 0b (-----001 1001---- -------- --------)] 
      [0x000000BC.4]: ZRL=[ 0] Val=[  -38] Coef=[32..32] Data=[0x 93 27 A3 E6 = 0b (----0011 001----- -------- --------)] 
      [0x000000BD.3]: ZRL=[ 0] Val=[  -33] Coef=[33..33] Data=[0x 27 A3 E6 C7 = 0b (---00111 10------ -------- --------)] 
      [0x000000BE.2]: ZRL=[ 0] Val=[  -24] Coef=[34..34] Data=[0x A3 E6 C7 22 = 0b (--100011 1------- -------- --------)] 
      [0x000000BF.1]: ZRL=[ 0] Val=[   -9] Coef=[35..35] Data=[0x E6 C7 22 09 = 0b (-1100110 -------- -------- --------)] 
      [0x000000C0.0]: ZRL=[ 0] Val=[  -12] Coef=[36..36] Data=[0x C7 22 09 F8 = 0b (1100011- -------- -------- --------)] 
      [0x000000C0.7]: ZRL=[ 0] Val=[  -23] Coef=[37..37] Data=[0x C7 22 09 F8 = 0b (-------1 001000-- -------- --------)] 
      [0x000000C1.6]: ZRL=[ 0] Val=[  -30] Coef=[38..38] Data=[0x 22 09 F8 52 = 0b (------10 00001--- -------- --------)] 
      [0x000000C2.5]: ZRL=[ 0] Val=[  -32] Coef=[39..39] Data=[0x 09 F8 52 31 = 0b (-----001 1111---- -------- --------)] 
      [0x000000C3.4]: ZRL=[ 0] Val=[  -29] Coef=[40..40] Data=[0x F8 52 31 E3 = 0b (----1000 010----- -------- --------)] 
      [0x000000C4.3]: ZRL=[ 0] Val=[  -23] Coef=[41..41] Data=[0x 52 31 E3 97 = 0b (---10010 00------ -------- --------)] 
      [0x000000C5.2]: ZRL=[ 0] Val=[  -12] Coef=[42..42] Data=[0x 31 E3 97 1A = 0b (--110001 1------- -------- --------)] 
      [0x000000C6.1]: ZRL=[ 0] Val=[  -12] Coef=[43..43] Data=[0x E3 97 1A 34 = 0b (-1100011 -------- -------- --------)] 
      [0x000000C7.0]: ZRL=[ 0] Val=[  -20] Coef=[44..44] Data=[0x 97 1A 34 BC = 0b (1001011- -------- -------- --------)] 
      [0x000000C7.7]: ZRL=[ 0] Val=[  -25] Coef=[45..45] Data=[0x 97 1A 34 BC = 0b (-------1 000110-- -------- --------)] 
      [0x000000C8.6]: ZRL=[ 0] Val=[  -25] Coef=[46..46] Data=[0x 1A 34 BC 79 = 0b (------10 00110--- -------- --------)] 
      [0x000000C9.5]: ZRL=[ 0] Val=[  -20] Coef=[47..47] Data=[0x 34 BC 79 67 = 0b (-----100 1011---- -------- --------)] 
      [0x000000CA.4]: ZRL=[ 0] Val=[  -12] Coef=[48..48] Data=[0x BC 79 67 4B = 0b (----1100 011----- -------- --------)] 
      [0x000000CB.3]: ZRL=[ 0] Val=[  -10] Coef=[49..49] Data=[0x 79 67 4B 9D = 0b (---11001 01------ -------- --------)] 
      [0x000000CC.2]: ZRL=[ 0] Val=[  -17] Coef=[50..50] Data=[0x 67 4B 9D 97 = 0b (--100111 0------- -------- --------)] 
      [0x000000CD.1]: ZRL=[ 0] Val=[  -20] Coef=[51..51] Data=[0x 4B 9D 97 36 = 0b (-1001011 -------- -------- --------)] 
      [0x000000CE.0]: ZRL=[ 0] Val=[  -17] Coef=[52..52] Data=[0x 9D 97 36 1C = 0b (1001110- -------- -------- --------)] 
      [0x000000CE.7]: ZRL=[ 0] Val=[  -10] Coef=[53..53] Data=[0x 9D 97 36 1C = 0b (-------1 100101-- -------- --------)] 
      [0x000000CF.6]: ZRL=[ 0] Val=[   -9] Coef=[54..54] Data=[0x 97 36 1C 39 = 0b (------11 00110--- -------- --------)] 
      [0x000000D0.5]: ZRL=[ 0] Val=[  -14] Coef=[55..55] Data=[0x 36 1C 39 B8 = 0b (-----110 0001---- -------- --------)] 
      [0x000000D1.4]: ZRL=[ 0] Val=[  -14] Coef=[56..56] Data=[0x 1C 39 B8 66 = 0b (----1100 001----- -------- --------)] 
      [0x000000D2.3]: ZRL=[ 0] Val=[   -9] Coef=[57..57] Data=[0x 39 B8 66 E1 = 0b (---11001 10------ -------- --------)] 
      [0x000000D3.2]: ZRL=[ 0] Val=[   -7] Coef=[58..58] Data=[0x B8 66 E1 CB = 0b (--111000 0------- -------- --------)] 
      [0x000000D4.1]: ZRL=[ 0] Val=[   -9] Coef=[59..59] Data=[0x 66 E1 CB 97 = 0b (-1100110 -------- -------- --------)] 
      [0x000000D5.0]: ZRL=[ 0] Val=[   -7] Coef=[60..60] Data=[0x E1 CB 97 9F = 0b (1110000- -------- -------- --------)] 
  Scan Data encountered marker   0xFFD9 @ 0x000000D9.0
      [0x000000D5.7]: ZRL=[ 0] Val=[   -5] Coef=[61..61] Data=[0x E1 CB 97 9F = 0b (-------1 110010-- -------- --------)] 
      [0x000000D6.6]: ZRL=[ 0] Val=[   -5] Coef=[62..62] Data=[0x CB 97 9F FF = 0b (------11 10010--- -------- --------)] 
      [0x000000D7.5]: ZRL=[ 0] Val=[   -2] Coef=[63..63] Data=[0x 97 9F FF D9 = 0b (-----111 1001---- -------- --------)] EOB64
                      DCT Matrix=[  984   -44   -42   -38   -32   -25   -17    -9]
                                 [  -44   -61   -58   -52   -44   -35   -24   -12]
                                 [  -42   -58   -54   -49   -42   -33   -23   -12]
                                 [  -38   -52   -49   -44   -38   -29   -20   -10]
                                 [  -32   -44   -42   -38   -32   -25   -17    -9]
                                 [  -25   -35   -33   -30   -25   -20   -14    -7]
                                 [  -17   -24   -23   -20   -17   -14    -9    -5]
                                 [   -9   -12   -12   -10    -9    -7    -5    -2]
圧縮データの分解結果 (最適化オフ)
圧縮データの分解結果 (最適化オフ)
    Lum (Tbl #0), MCU=[0,0]
      [0x00000148.0]: ZRL=[ 0] Val=[  984] Coef=[00= DC] Data=[0x FE F6 3C 27 = 0b (11111110 11110110 00------ --------)] 
      [0x0000014A.2]: ZRL=[ 0] Val=[  -44] Coef=[01..01] Data=[0x 3C 27 E1 3F = 0b (--111100 0010011- -------- --------)] 
      [0x0000014B.7]: ZRL=[ 0] Val=[  -44] Coef=[02..02] Data=[0x 27 E1 3F 0A = 0b (-------1 11100001 0011---- --------)] 
      [0x0000014D.4]: ZRL=[ 0] Val=[  -42] Coef=[03..03] Data=[0x 3F 0A F8 0B = 0b (----1111 00001010 1------- --------)] 
      [0x0000014F.1]: ZRL=[ 0] Val=[  -61] Coef=[04..04] Data=[0x F8 0B C2 BE = 0b (-1111000 000010-- -------- --------)] 
      [0x00000150.6]: ZRL=[ 0] Val=[  -42] Coef=[05..05] Data=[0x 0B C2 BE 19 = 0b (------11 11000010 101----- --------)] 
      [0x00000152.3]: ZRL=[ 0] Val=[  -38] Coef=[06..06] Data=[0x BE 19 F0 2F = 0b (---11110 00011001 -------- --------)] 
      [0x00000154.0]: ZRL=[ 0] Val=[  -58] Coef=[07..07] Data=[0x F0 2F 81 7C = 0b (11110000 00101--- -------- --------)] 
      [0x00000155.5]: ZRL=[ 0] Val=[  -58] Coef=[08..08] Data=[0x 2F 81 7C 33 = 0b (-----111 10000001 01------ --------)] 
      [0x00000157.2]: ZRL=[ 0] Val=[  -38] Coef=[09..09] Data=[0x 7C 33 E1 FF = 0b (--111100 0011001- -------- --------)] 
      [0x00000158.7]: ZRL=[ 0] Val=[  -32] Coef=[10..10] Data=[0x 33 E1 FF 05 = 0b (-------1 11100001 1111---- --------)] 
      [0x0000015A.4]: ZRL=[ 0] Val=[  -52] Coef=[11..11] Data=[0x FF 05 F8 27 = 0b (----1111 00000101 1------- --------)] 
      [0x0000015D.1]: ZRL=[ 0] Val=[  -54] Coef=[12..12] Data=[0x F8 27 C1 7E = 0b (-1111000 001001-- -------- --------)] 
      [0x0000015E.6]: ZRL=[ 0] Val=[  -52] Coef=[13..13] Data=[0x 27 C1 7E 1F = 0b (------11 11000001 011----- --------)] 
      [0x00000160.3]: ZRL=[ 0] Val=[  -32] Coef=[14..14] Data=[0x 7E 1F D1 BC = 0b (---11110 00011111 -------- --------)] 
      [0x00000162.0]: ZRL=[ 0] Val=[  -25] Coef=[15..15] Data=[0x D1 BC 27 E0 = 0b (11010001 10------ -------- --------)] 
      [0x00000163.2]: ZRL=[ 0] Val=[  -44] Coef=[16..16] Data=[0x BC 27 E0 EF = 0b (--111100 0010011- -------- --------)] 
      [0x00000164.7]: ZRL=[ 0] Val=[  -49] Coef=[17..17] Data=[0x 27 E0 EF 07 = 0b (-------1 11100000 1110---- --------)] 
      [0x00000166.4]: ZRL=[ 0] Val=[  -49] Coef=[18..18] Data=[0x EF 07 78 4F = 0b (----1111 00000111 0------- --------)] 
      [0x00000168.1]: ZRL=[ 0] Val=[  -44] Coef=[19..19] Data=[0x 78 4F 46 D3 = 0b (-1111000 010011-- -------- --------)] 
      [0x00000169.6]: ZRL=[ 0] Val=[  -25] Coef=[20..20] Data=[0x 4F 46 D3 BC = 0b (------11 01000110 -------- --------)] 
      [0x0000016B.0]: ZRL=[ 0] Val=[  -17] Coef=[21..21] Data=[0x D3 BC 39 E1 = 0b (11010011 10------ -------- --------)] 
      [0x0000016C.2]: ZRL=[ 0] Val=[  -35] Coef=[22..22] Data=[0x BC 39 E1 5F = 0b (--111100 0011100- -------- --------)] 
      [0x0000016D.7]: ZRL=[ 0] Val=[  -42] Coef=[23..23] Data=[0x 39 E1 5F 09 = 0b (-------1 11100001 0101---- --------)] 
      [0x0000016F.4]: ZRL=[ 0] Val=[  -44] Coef=[24..24] Data=[0x 5F 09 F8 57 = 0b (----1111 00001001 1------- --------)] 
      [0x00000171.1]: ZRL=[ 0] Val=[  -42] Coef=[25..25] Data=[0x F8 57 C3 9A = 0b (-1111000 010101-- -------- --------)] 
      [0x00000172.6]: ZRL=[ 0] Val=[  -35] Coef=[26..26] Data=[0x 57 C3 9A 75 = 0b (------11 11000011 100----- --------)] 
      [0x00000174.3]: ZRL=[ 0] Val=[  -17] Coef=[27..27] Data=[0x 9A 75 B6 8F = 0b (---11010 01110--- -------- --------)] 
      [0x00000175.5]: ZRL=[ 0] Val=[   -9] Coef=[28..28] Data=[0x 75 B6 8F E1 = 0b (-----101 10110--- -------- --------)] 
      [0x00000176.5]: ZRL=[ 0] Val=[  -24] Coef=[29..29] Data=[0x B6 8F E1 EF = 0b (-----110 1000111- -------- --------)] 
      [0x00000177.7]: ZRL=[ 0] Val=[  -33] Coef=[30..30] Data=[0x 8F E1 EF 0C = 0b (-------1 11100001 1110---- --------)] 
      [0x00000179.4]: ZRL=[ 0] Val=[  -38] Coef=[31..31] Data=[0x EF 0C F8 67 = 0b (----1111 00001100 1------- --------)] 
      [0x0000017B.1]: ZRL=[ 0] Val=[  -38] Coef=[32..32] Data=[0x F8 67 C3 DA = 0b (-1111000 011001-- -------- --------)] 
      [0x0000017C.6]: ZRL=[ 0] Val=[  -33] Coef=[33..33] Data=[0x 67 C3 DA 3D = 0b (------11 11000011 110----- --------)] 
      [0x0000017E.3]: ZRL=[ 0] Val=[  -24] Coef=[34..34] Data=[0x DA 3D B5 9E = 0b (---11010 00111--- -------- --------)] 
      [0x0000017F.5]: ZRL=[ 0] Val=[   -9] Coef=[35..35] Data=[0x 3D B5 9E 91 = 0b (-----101 10110--- -------- --------)] 
      [0x00000180.5]: ZRL=[ 0] Val=[  -12] Coef=[36..36] Data=[0x B5 9E 91 A0 = 0b (-----101 10011--- -------- --------)] 
      [0x00000181.5]: ZRL=[ 0] Val=[  -23] Coef=[37..37] Data=[0x 9E 91 A0 F8 = 0b (-----110 1001000- -------- --------)] 
      [0x00000182.7]: ZRL=[ 0] Val=[  -30] Coef=[38..38] Data=[0x 91 A0 F8 7F = 0b (-------1 10100000 1------- --------)] 
      [0x00000184.1]: ZRL=[ 0] Val=[  -32] Coef=[39..39] Data=[0x F8 7F 42 D2 = 0b (-1111000 011111-- -------- --------)] 
      [0x00000185.6]: ZRL=[ 0] Val=[  -29] Coef=[40..40] Data=[0x 7F 42 D2 2C = 0b (------11 01000010 -------- --------)] 
      [0x00000187.0]: ZRL=[ 0] Val=[  -23] Coef=[41..41] Data=[0x D2 2C EC F4 = 0b (11010010 00------ -------- --------)] 
      [0x00000188.2]: ZRL=[ 0] Val=[  -12] Coef=[42..42] Data=[0x 2C EC F4 BD = 0b (--101100 11------ -------- --------)] 
      [0x00000189.2]: ZRL=[ 0] Val=[  -12] Coef=[43..43] Data=[0x EC F4 BD 1B = 0b (--101100 11------ -------- --------)] 
      [0x0000018A.2]: ZRL=[ 0] Val=[  -20] Coef=[44..44] Data=[0x F4 BD 1B 46 = 0b (--110100 1011---- -------- --------)] 
      [0x0000018B.4]: ZRL=[ 0] Val=[  -25] Coef=[45..45] Data=[0x BD 1B 46 D2 = 0b (----1101 000110-- -------- --------)] 
      [0x0000018C.6]: ZRL=[ 0] Val=[  -25] Coef=[46..46] Data=[0x 1B 46 D2 EC = 0b (------11 01000110 -------- --------)] 
      [0x0000018E.0]: ZRL=[ 0] Val=[  -20] Coef=[47..47] Data=[0x D2 EC ED 74 = 0b (11010010 11------ -------- --------)] 
      [0x0000018F.2]: ZRL=[ 0] Val=[  -12] Coef=[48..48] Data=[0x EC ED 74 ED = 0b (--101100 11------ -------- --------)] 
      [0x00000190.2]: ZRL=[ 0] Val=[  -10] Coef=[49..49] Data=[0x ED 74 ED 2F = 0b (--101101 01------ -------- --------)] 
      [0x00000191.2]: ZRL=[ 0] Val=[  -17] Coef=[50..50] Data=[0x 74 ED 2F 4E = 0b (--110100 1110---- -------- --------)] 
      [0x00000192.4]: ZRL=[ 0] Val=[  -20] Coef=[51..51] Data=[0x ED 2F 4E B5 = 0b (----1101 001011-- -------- --------)] 
      [0x00000193.6]: ZRL=[ 0] Val=[  -17] Coef=[52..52] Data=[0x 2F 4E B5 B6 = 0b (------11 01001110 -------- --------)] 
      [0x00000195.0]: ZRL=[ 0] Val=[  -10] Coef=[53..53] Data=[0x B5 B6 B1 B1 = 0b (10110101 -------- -------- --------)] 
      [0x00000196.0]: ZRL=[ 0] Val=[   -9] Coef=[54..54] Data=[0x B6 B1 B1 B6 = 0b (10110110 -------- -------- --------)] 
      [0x00000197.0]: ZRL=[ 0] Val=[  -14] Coef=[55..55] Data=[0x B1 B1 B6 82 = 0b (10110001 -------- -------- --------)] 
      [0x00000198.0]: ZRL=[ 0] Val=[  -14] Coef=[56..56] Data=[0x B1 B6 82 DA = 0b (10110001 -------- -------- --------)] 
      [0x00000199.0]: ZRL=[ 0] Val=[   -9] Coef=[57..57] Data=[0x B6 82 DA 08 = 0b (10110110 -------- -------- --------)] 
      [0x0000019A.0]: ZRL=[ 0] Val=[   -7] Coef=[58..58] Data=[0x 82 DA 08 A2 = 0b (100000-- -------- -------- --------)] 
      [0x0000019A.6]: ZRL=[ 0] Val=[   -9] Coef=[59..59] Data=[0x 82 DA 08 A2 = 0b (------10 110110-- -------- --------)] 
  Scan Data encountered marker   0xFFD9 @ 0x0000019F.0
      [0x0000019B.6]: ZRL=[ 0] Val=[   -7] Coef=[60..60] Data=[0x DA 08 A2 5F = 0b (------10 0000---- -------- --------)] 
      [0x0000019C.4]: ZRL=[ 0] Val=[   -5] Coef=[61..61] Data=[0x 08 A2 5F FF = 0b (----1000 10------ -------- --------)] 
      [0x0000019D.2]: ZRL=[ 0] Val=[   -5] Coef=[62..62] Data=[0x A2 5F FF D9 = 0b (--100010 -------- -------- --------)] 
      [0x0000019E.0]: ZRL=[ 0] Val=[   -2] Coef=[63..63] Data=[0x 5F FF D9 00 = 0b (0101---- -------- -------- --------)] EOB64
                      DCT Matrix=[  984   -44   -42   -38   -32   -25   -17    -9]
                                 [  -44   -61   -58   -52   -44   -35   -24   -12]
                                 [  -42   -58   -54   -49   -42   -33   -23   -12]
                                 [  -38   -52   -49   -44   -38   -29   -20   -10]
                                 [  -32   -44   -42   -38   -32   -25   -17    -9]
                                 [  -25   -35   -33   -30   -25   -20   -14    -7]
                                 [  -17   -24   -23   -20   -17   -14    -9    -5]
                                 [   -9   -12   -12   -10    -9    -7    -5    -2]

これから、以下のことが読み取れる。

  • ブロック内の最初のデータのみ DC で、残りは AC である
  • 最適化オンと最適化オフで、(少なくとも今回のデータでは) 異なるエンコードで同じ DCT Matrix が表されている
  • 圧縮データにハフマン符号と追加データ以外のヘッダやフッタなどは含まれていなそうである

さらに、24×8の緑一色の画像も解析してみた。

24×8の緑一色の画像
test_24x8_green_magick.jpg
00000000  ff d8 ff e0 00 10 4a 46 49 46 00 01 01 01 00 60  |......JFIF.....`|
00000010  00 60 00 00 ff e1 00 22 45 78 69 66 00 00 4d 4d  |.`....."Exif..MM|
00000020  00 2a 00 00 00 08 00 01 01 12 00 03 00 00 00 01  |.*..............|
00000030  00 01 00 00 00 00 00 00 ff db 00 43 00 02 01 01  |...........C....|
00000040  02 01 01 02 02 02 02 02 02 02 02 03 05 03 03 03  |................|
00000050  03 03 06 04 04 03 05 07 06 07 07 07 06 07 07 08  |................|
00000060  09 0b 09 08 08 0a 08 07 07 0a 0d 0a 0a 0b 0c 0c  |................|
00000070  0c 0c 07 09 0e 0f 0d 0c 0e 0b 0c 0c 0c ff db 00  |................|
00000080  43 01 02 02 02 03 03 03 06 03 03 06 0c 08 07 08  |C...............|
00000090  0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c  |................|
000000a0  0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c  |................|
000000b0  0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c  |................|
000000c0  0c 0c ff c0 00 11 08 00 08 00 18 03 01 22 00 02  |............."..|
000000d0  11 01 03 11 01 ff c4 00 15 00 01 01 00 00 00 00  |................|
000000e0  00 00 00 00 00 00 00 00 00 00 00 07 ff c4 00 14  |................|
000000f0  10 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |................|
00000100  00 00 ff c4 00 15 01 01 01 00 00 00 00 00 00 00  |................|
00000110  00 00 00 00 00 00 00 00 09 ff c4 00 14 11 01 00  |................|
00000120  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff  |................|
00000130  da 00 0c 03 01 00 02 11 03 11 00 3f 00 ac 00 95  |...........?....|
00000140  e8 a6 00 0f ff d9                                |......|

この画像のハフマン符号情報と圧縮データは、以下である。

ハフマン符号情報
0D5  ★DHT[0]                    FF C4
0D7  SizeOfThis[0]               00 15
0D9  Th                          00
0DA  DCHaffman[0]                01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0EA  DCHaffman[16]               00 07
0EC  ★DHT[0]                    FF C4
0EE  SizeOfThis[0]               00 14
0F0  Th                          10
0F1  ACHaffman[0]                01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
101  ACHaffman[16]               00
102  ★DHT[0]                    FF C4
104  SizeOfThis[0]               00 15
106  Th                          01
107  DCHaffman[0]                01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00
117  DCHaffman[16]               00 09
119  ★DHT[0]                    FF C4
11B  SizeOfThis[0]               00 14
11D  Th                          11
11E  ACHaffman[0]                01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
12E  ACHaffman[16]               00
圧縮データ
13D  圧縮データ(7B)[0]           AC 00 95 E8 A6 00 0F
24×8の緑一色の画像の圧縮データの分解結果
    Lum (Tbl #0), MCU=[0,0]
      [0x0000013D.0]: ZRL=[ 0] Val=[   88] Coef=[00= DC] Data=[0x AC 00 95 E8 = 0b (10101100 0------- -------- --------)] 
      [0x0000013E.1]: ZRL=[ 0] Val=[    0] Coef=[01..01] Data=[0x 00 95 E8 A6 = 0b (-0------ -------- -------- --------)] EOB
                      DCT Matrix=[  176     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]

    Lum (Tbl #0), MCU=[0,0]
      [0x0000013E.2]: ZRL=[ 0] Val=[    0] Coef=[00= DC] Data=[0x 00 95 E8 A6 = 0b (--0----- -------- -------- --------)] EOB
      [0x0000013E.3]: ZRL=[ 0] Val=[    0] Coef=[01..01] Data=[0x 00 95 E8 A6 = 0b (---0---- -------- -------- --------)] EOB
                      DCT Matrix=[    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]

    Lum (Tbl #0), MCU=[0,0]
      [0x0000013E.4]: ZRL=[ 0] Val=[    0] Coef=[00= DC] Data=[0x 00 95 E8 A6 = 0b (----0--- -------- -------- --------)] EOB
      [0x0000013E.5]: ZRL=[ 0] Val=[    0] Coef=[01..01] Data=[0x 00 95 E8 A6 = 0b (-----0-- -------- -------- --------)] EOB
                      DCT Matrix=[    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]

    Lum (Tbl #0), MCU=[0,0]
      [0x0000013E.6]: ZRL=[ 0] Val=[    0] Coef=[00= DC] Data=[0x 00 95 E8 A6 = 0b (------0- -------- -------- --------)] EOB
      [0x0000013E.7]: ZRL=[ 0] Val=[    0] Coef=[01..01] Data=[0x 00 95 E8 A6 = 0b (-------0 -------- -------- --------)] EOB
                      DCT Matrix=[    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]

    Chr(0) (Tbl #1), MCU=[0,0]
      [0x0000013F.0]: ZRL=[ 0] Val=[ -336] Coef=[00= DC] Data=[0x 95 E8 A6 00 = 0b (10010101 111----- -------- --------)] 
      [0x00000140.3]: ZRL=[ 0] Val=[    0] Coef=[01..01] Data=[0x E8 A6 00 0F = 0b (---0---- -------- -------- --------)] EOB
                      DCT Matrix=[ -672     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]

    Chr(0) (Tbl #1), MCU=[0,0]
      [0x00000140.4]: ZRL=[ 0] Val=[ -428] Coef=[00= DC] Data=[0x E8 A6 00 0F = 0b (----1000 1010011- -------- --------)] 
  Scan Data encountered marker   0xFFD9 @ 0x00000144.0
      [0x00000141.7]: ZRL=[ 0] Val=[    0] Coef=[01..01] Data=[0x A6 00 0F FF = 0b (-------0 -------- -------- --------)] EOB
                      DCT Matrix=[ -856     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]
                                 [    0     0     0     0     0     0     0     0]

分解結果は、Lum のブロックが4個、Chr のブロックが2個、計6個のブロックに分かれているようである。

圧縮データの最後の余ったビットは 1 で埋め、これがハフマン符号のデータに対応しないノードに相当すると予想したが、実際には 0 であるにもかかわらず使われないビットもあるようである。

まとめ

今回わかったこと

  • GIMP で JPEG 画像を保存する際の「最適化」の有無で、エンコードは変わるが、エンコードされるデータは変わらなそうである
  • deflate でも用いられるアルゴリズムで、符号長ごとの符号数からハフマン符号を構築する
  • ハフマン符号からは追加データのビット数を読み取り、圧縮データではハフマン符号の後にそのビット数のデータが続く
  • AC 成分では、データの上位ニブルに「その要素の前に何要素の 0 を追加するか」を格納する
  • 圧縮データの各ブロックは、最初に1個の DC 成分を表すハフマン符号+追加データを置き、続いて63個分の AC 成分を表すハフマン符号+追加データを置く
  • 圧縮データにはヘッダは無く、最初のブロックの DC 成分の情報から開始する

今後の課題

  • ハフマン符号を読んでデータブロックを切り出すプログラムを書いてみる
  • 圧縮データ内でデータブロックがどのように並んでいるかを調査する
    • 各コンポーネントの並び順は?
    • 画像内の位置との関係は?
    • サンプリングファクター?
    • プログレッシブ?
    • 実は8×8ではなく16×16がひとかたまり?
0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?