jpeg_start_compress

オープンソースライブラリ編・・・。
初めてということでまずはlibjpegから・・・。

Independent JPEG Group

libjpegはJpeg画像を圧縮・伸長をするライブラリ・・・。

今回はLinux(Ubuntu)でビットマップをJpegに変換してみる・・・。

まず、ビットマップのデータを格納する構造体や、関数を作る必要がある・・・。

bitmap.hを用意し、

まずはビットマップファイルヘッダ・・・。
ここで注意しなければならないのは、typeがunsigned shortの2バイトに対して、そのあとのsizeがunsigned intの4バイトということ・・・。
構造体のワード境界が4バイトなので、typeとsizeの間に2バイト空白領域が存在する・・・。
freadでファイルから構造体に読み込んだ時に、この2バイト分位置がずれてしまう・・・。
そこで#pragma pack(2)とすることで、ワード境界を2バイトにし、隙間なく読み込めるように・・・。

元に戻して、今度はビットマップ情報ヘッダ・・・。

今回は24bitビットマップのみ扱うので、カラーテーブルは使わない・・・。

最終的にビットマップは、ファイルヘッダ、情報ヘッダ、ピクセルバッファ、の3部分からなる・・・。

load_bitmapで、ビットマップのこれらの情報を読み込む・・・。

bitmap.cにある定義では、

渡されたfilenameのビットマップを開いて、freadでファイルヘッダ、情報ヘッダを、渡されたbitmap_ptrの要素に格納・・・。
ピクセルバッファのサイズは、statで調べたファイルサイズから、2つのヘッダのサイズを引いたものなので、mallocでその分のバッファを確保して、そこにfreadで読み込む・・・。
でファイルを閉じる・・・。
これで構造体にビットマップのデータが入った・・・。

destroy_bitmapは、ピクセルバッファを破棄して、ファイルヘッダ、情報ヘッダをクリアにする・・・。

destroy_bitmapの定義は、

ピクセルバッファをfreeして、bitmap_ptrの参照先を0で埋める・・・。

これでビットマップ読み込みの準備はできたので、

$ sudo apt-get install libjpeg-dev
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています                
状態情報を読み取っています... 完了
以下の追加パッケージがインストールされます:
  libjpeg-turbo8-dev libjpeg8-dev
以下のパッケージが新たにインストールされます:
  libjpeg-dev libjpeg-turbo8-dev libjpeg8-dev
アップグレード: 0 個、新規インストール: 3 個、削除: 0 個、保留: 272 個。
257 kB のアーカイブを取得する必要があります。
この操作後に追加で 1,471 kB のディスク容量が消費されます。
続行しますか? [Y/n] y
取得:1 http://jp.archive.ubuntu.com/ubuntu xenial/main amd64 libjpeg-turbo8-dev amd64 1.4.2-0ubuntu3 [254 kB]
取得:2 http://jp.archive.ubuntu.com/ubuntu xenial/main amd64 libjpeg8-dev amd64 8c-2ubuntu8 [1,552 B]
取得:3 http://jp.archive.ubuntu.com/ubuntu xenial/main amd64 libjpeg-dev amd64 8c-2ubuntu8 [1,546 B]
257 kB を 1秒 で取得しました (243 kB/s)
以前に未選択のパッケージ libjpeg-turbo8-dev:amd64 を選択しています。
(データベースを読み込んでいます ... 現在 208532 個のファイルとディレクトリがインストールされています。)
.../libjpeg-turbo8-dev_1.4.2-0ubuntu3_amd64.deb を展開する準備をしています ...
libjpeg-turbo8-dev:amd64 (1.4.2-0ubuntu3) を展開しています...
以前に未選択のパッケージ libjpeg8-dev:amd64 を選択しています。
.../libjpeg8-dev_8c-2ubuntu8_amd64.deb を展開する準備をしています ...
libjpeg8-dev:amd64 (8c-2ubuntu8) を展開しています...
以前に未選択のパッケージ libjpeg-dev:amd64 を選択しています。
.../libjpeg-dev_8c-2ubuntu8_amd64.deb を展開する準備をしています ...
libjpeg-dev:amd64 (8c-2ubuntu8) を展開しています...
libjpeg-turbo8-dev:amd64 (1.4.2-0ubuntu3) を設定しています ...
libjpeg8-dev:amd64 (8c-2ubuntu8) を設定しています ...
libjpeg-dev:amd64 (8c-2ubuntu8) を設定しています ...
$ 

apt-getでlibjpeg-devをインストール・・・。

main.cは、

jpeglib.hをインクルード・・・。(libjpegなのにjpeglib.h・・・。)
また先ほど作ったbitmap.hもインクルード・・・。

cinfoがJpeg圧縮情報で、ほとんどの関数でこれを渡す・・・。

load_bitmapで"test.bmp"をロードしたら、Jpegエラー処理を初期化・・・。(Jpegエラー処理はいずれ扱う・・・。)

"test.jpg"を開いて、Jpeg出力先をそこに・・・。
各パラメータの設定など・・・。画質は50にしている・・・。

24ビットなら3色なので、3色 * 幅で行が構成されるかと思うが、実際にはビットマップファイルはワード境界のこともあり、最後に4で割った余りの部分が空白領域paddingとして付加されている・・・。
この情報をもとにline_bufferを作成・・・。
行ごとにビットマップのピクセルバッファを流し込んでいく・・・。

jpeg_start_compressで圧縮開始、

http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Desktop-generic/LSB-Desktop-generic/libjpeg.jpeg.start.compress.1.html

ビットマップのピクセルバッファを行ごとにline_bufferに受け渡し、line_bufferをjpeg_write_scanlinesで書き込み、jpeg_finish_compressで圧縮終了・・・。
ビットマップのピクセルバッファはRGBではなくBGRの順で格納されているので注意・・・。
また、上下も逆なので、その辺も気を付けて受け渡し・・・。

line_bufferを解放、jpeg_destroy_compressでcinfoも破棄・・・。
fcloseでfpも閉じて、destroy_bitmapでビットマップも破棄・・・。

これでJpegが出力できるかな・・・。

$ gcc -o main main.c bitmap.c -ljpeg
$ ls
bitmap.c  bitmap.h  license.txt  main  main.c  test.bmp
$ ./main 
$ ls
bitmap.c  bitmap.h  license.txt  main  main.c  test.bmp  test.jpg
$ 

libjpegをリンクするときは-ljpegを付ける・・・。
実行すると、test.jpgが生成されてるのがわかる・・・。

f:id:BG1:20160807080700p:plain

test.bmpとほぼ同じようなtest.jpgを生成できてる・・・。

Sample/libjpeg/jpeg_start_compress/jpeg_start_compress/src/jpeg_start_compress at master · bg1bgst333/Sample · GitHub