この章の目次にもどる
前頁: 2.16 付箋固有データ処理にもどる
次頁:2.18 その他にすすむ

2.17 画像形式変換ライブラリ

本ライブラリは次に挙げる項目を行うために作成されたものである。

  1. BTRON3仕様のビットマップ構造体(BMP)と JPEG, PNG, Windows BMP画像形式との相互変換
  2. 圧縮ビットマップ構造体(CBMP)と TADの画像セグメント(IMAGESEG)との相互変換

《R4 で追加された機能》

BTRON BMP・JPEG/PNGの相互変換

本ライブラリのこの部分では以下のライブラリコードが含まれている。

これらのコードを、Bright/V開発環境において動作させるべく、 一部のコードを改変している。その理由を以下に挙げる。

本ライブラリを使用して PNG形式やJPEG形式の画像を読み込む/書き込む アプリケーションを構築した場合、 該当ライブラリのライセンス条項に基づいて配布すること。
画像形式使用ライブラリ
PNGzlib v1.1.3(README), libpng v1.0.9(LICENSE)
JPEGjpeg-6b(README)
BMP(独自実装につきライセンス不要)

本項目で使用する構造体の形式を以下に示す。

IMG_BMP

typedef struct _libimg_bmp {
  CSPEC* color_spec;
  BMP*   bmap;
  ERR    (*funcptr)();
  VOID   (*flushptr)();
  VOID   *io_src;
} IMG_BMP;

color_specには BTRON3仕様で示された CSPEC構造体を指定すること。 このエントリは読み込みと書き込みのいずれの場合にも参照される。

bmapには BTRON3仕様で示された BMP構造体を指定する。 書き込み時には BMP構造体中の全てのエントリが使用される。 ただし、このときプレーン数は現在のところ 1のみに対応している。
読み込み時には BMP構造体のpixbitsエントリのみを使用する。 後述する関数を実行後、全てのエントリが記述されている。 アプリケーション処理によって、ここで生成した BMP構造体を使用しなくなった時点で BMP構造体のbaseaddr[]領域を解放し忘れないようにすること(単純に free(baseaddr[0])等を呼べば良い)。

funcptrには以下の引数の並びをもつ関数へのポインタを設定する。
書き込み時 (VOID* io_src, UB* bytes, UW size)
読み込み時 (UB* bytes, UW reqsize, VOID* io_src)

flushptrには以下の引数の並びをもつ関数へのポインタを設定する。 なお、このエントリは書き込み時のみ使用される。
書き込み時 (VOID* io_src)

io_ptrは読み書き対象へのポインタを指定する。 このエントリはfuncptrflushptrからそのまま渡される。

IMG_COMPACT

typedef struct _libimg_compact {
  H method;
  H opt;
} IMG_COMPACT;

methodには読み書きする画像形式を示す。

optには読み書きする画像形式に依存したオプションを指定する。

例を次に示す。

書き込み例
ERR write_fn(VOID* io_src, UB* bytes, UW size);
ERR flush_fn(VOID* io_src);

...

ERR
draw_func()
{
  W gid0;
  CSPEC cspec;
  IMG_COMPACT compact = { LIBIMG_METHOD_PNG, LIBIMG_PNG_OPT_DEFAULT };
  IMG_BMP img_bmp;
  W so0; /* socketの場合 */

  /* ここでCSPECの設定 */
  gid0 = gopn_mem(NULL, &bmp, (VOID*)&cspec);
  /* ここで描画処理 */
  gcls_env(gid0);

  img_bmp.color_spec = &cspec;
  img_bmp.bmap     = &bmp;
  img_bmp.funcptr  = write_fn; /* 書き込み用コールバックへのポインタ */
  img_bmp.flushptr = flush_fn; /* flush用コールバックへのポインタ */
  img_bmp.io_src   = &so0;     /* 入力ソース(ファイルやソケットディスクリプタ等) */

  err = libimg_wri_bmp(&img_bmp, &compact);
  return err;
}

ERR
write_fn(VOID* io_src, UB* bytes, UW size)
{
  /*
   * 書き込み時に呼び出されるコールバックルーチン
   * io_src(入力) IMG_BMP.io_srcと同じ
   * bytes(入力)  書き込むデータ
   * size(入力)   領域 bytes の長さ
   * 返値 ( >=0 ) 実際に書き込んだバイト数
   *      ( < 0 ) エラー
   */
  W* socket_descriptor = (W*)io_src;
  so_send(*socket_descriptor, bytes, size, 0);
  return size;
}

VOID
flush_fn(VOID* io_src)
{
  /*
   * flush時に呼び出されるコールバックルーチン
   * io_src(入力) IMG_BMP.io_srcと同じ
   */
  /* no operation */
}

読み込み例

ERR read_fn(UB* bytes, UW reqsize, VOID* io_src);

...

ERR
draw_func()
{
  CSPEC cspec;
  BMP bmap;
  IMG_COMPACT compact = { LIBIMG_METHOD_PNG, LIBIMG_PNG_OPT_DEFAULT };
  IMG_BMP img_bmp;
  W so0; /* socketの場合 */

  /* CSPECの設定 */
  cspec = { 1, { 0x1008, 0x0808, 0x0008, 0 }, NULL };
  /* BMPの設定 */
  bmap.pixbits = 0x2018;

  img_bmp.color_spec = &cspec;
  img_bmp.bmap     = &bmap;
  img_bmp.funcptr  = read_fn;  /* 読み込み用コールバックへのポインタ */
  img_bmp.flushptr = NULL;     /* 読み込み時には flushは使わない */
  img_bmp.io_src   = &so0;     /* 入力ソース(ファイルやソケットディスクリプタ等) */

  err = libimg_rea_bmp(&img_bmp, &compact);
#if 0
#error この間に BMP関係の処理を行う。
#error しかし、BMP等をグローバルで持つ場合はここで処理する必要はない。
#error いずれにせよ。処理終了後に bmap.baseaddr[0]を解放し忘れないこと。
#error 解放するには、free(bmap.baseaddr[0]); とすれば良い
#endif
  return err;
}

ERR
read_fn(UB* bytes, UW reqsize, VOID* io_src)
{
  /*
   * 読み込み時に呼び出されるコールバックルーチン
   * bytes(出力) 読み込んだデータを格納する領域へのポインタ
   * reqsize(入力) 要求されたバイト数
   * io_src(入力) IMG_BMP.io_srcと同じ
   * 返値 ( >=0 ) 実際に読み込んだバイト数
   *      ( < 0 ) エラー
   */
  return so_read(*((W*)io_src), bytes, reqsize);
}

ライブラリ関数リファレンス

libimg_rea_bmp
libimg_rea_bmp_jpeg
libimg_rea_bmp_png
libimg_rea_bmp_bmp
 
画像をBMP構造体に変換

【形式】

ERR libimg_rea_bmp( IMG_BMP *dst, IMG_COMPACT *compact )
ERR libimg_rea_bmp_jpeg( IMG_BMP *dst, IMG_COMPACT *compact )
ERR libimg_rea_bmp_png( IMG_BMP *dst, IMG_COMPACT *compact )
ERR libimg_rea_bmp_bmp( IMG_BMP *dst, IMG_COMPACT *compact )

【パラメータ】

IMG_BMP     *dst     IMG_BMP構造体
IMG_COMPACT *compact DEV_SPEC データ

【リターン値】

≧ 0    正常
< 0    エラー(エラーコード)
  (形式共通)
  LIBIMG_ERR_READ_WRITE_ERROR  読み込みエラー(不正なバイト列であった場合も含む)
  LIBIMG_ERR_NO_MEMORY         作業用メモリの確保に失敗した
  LIBIMG_ERR_ILLEGAL_PARAMETER サポートされないパラメータが与えられた
  (以下はPNG形式の場合のみ)
  LIBIMG_PNG_ERR_CANNOT_CREATE_STRUCT libpngで使用する構造体が生成できなかった

【解説】

指定された形式の画像を読み込んで BMP構造体データに変換する。
compactmethodエントリには以下の値を使用できる。

  LIBIMG_METHOD_JPEG  JPEG形式の画像読み込み
  LIBIMG_METHOD_PNG   PNG形式の画像読み込み
  LIBIMG_METHOD_BMP   Windows BMP形式の画像読み込み
compactoptエントリに指定する値は、以下の関数を用いた場合と同じ値を指定する。
compactmethod関数名
LIBIMG_METHOD_JPEGlibimg_rea_bmp_jpeg
LIBIMG_METHOD_PNGlibimg_rea_bmp_png
LIBIMG_METHOD_BMPlibimg_rea_bmp_bmp

JPEG画像(LIBIMG_METHOD_JPEG)の場合

JPEG形式の画像を読み込んで BMP構造体データに変換する。
compactoptエントリには以下の値を使用できる。

  LIBIMG_JPEG_READ_OPT_1_8_SIZE  元画像の 1/8の大きさで BMPを取得する
  LIBIMG_JPEG_READ_OPT_1_4_SIZE  元画像の 1/4の大きさで BMPを取得する
  LIBIMG_JPEG_READ_OPT_1_2_SIZE  元画像の 1/2の大きさで BMPを取得する
  LIBIMG_JPEG_READ_OPT_1_1_SIZE  元画像と同じ大きさで BMPを取得する

PNG画像(LIBIMG_METHOD_PNG)の場合

PNG形式の画像を読み込んで BMP構造体データに変換する。
compactoptエントリの値にはLIBIMG_PNG_OPT_DEFAULTを指定しておくことが望ましい。
compactoptエントリには以下の値の ORを取る。

LIBIMG_PNG_OPT_DEFAULT
デフォルト設定
LIBIMG_PNG_READ_OPT_SAVE_ALPHA
このオプションを設定し、次の条件を満すとき、 アルファ値をIMG_BMP->bmap->baseaddr[1]に保存する。 (bmapの大きさに注意すること)。baseaddr[1]に確保される メモリ量はbaseaddr[0]に確保されるメモリ量に等しい。
LIBIMG_PNG_READ_OPT_OVERWRITABLE_COLMAP
このオプションを設定し、次の条件を満すとき、 IMG_BMP->cspec->colmapを元画像のパレットで上書きする。 このとき、システムから得られる標準カラーマップの判定は行わない。

Windows BMP画像(LIBIMG_METHOD_BMP)の場合

Windows BMP形式の画像を読み込んで BMP構造体データに変換する。
compactoptエントリの値にはLIBIMG_PNG_OPT_DEFAULTを指定しておくことが望ましい。
compactoptエントリには以下の値の ORを取る。

LIBIMG_BMP_OPT_DEFAULT
デフォルト設定
LIBIMG_BMP_READ_OPT_OVERWRITABLE_COLMAP
このオプションを設定し、次の条件を満すとき、 IMG_BMP->cspec->colmapを元画像のパレットで上書きする。 このとき、システムから得られる標準カラーマップの判定は行わない。

libimg_wri_bmp
libimg_wri_bmp_jpeg
libimg_wri_bmp_png
libimg_wri_bmp_bmp
 
BMP構造体を指定画像形式に変換

【形式】

ERR libimg_wri_bmp( IMG_BMP *src, IMG_COMPACT *compact )
ERR libimg_wri_bmp_jpeg( IMG_BMP *src, IMG_COMPACT *compact )
ERR libimg_wri_bmp_png( IMG_BMP *src, IMG_COMPACT *compact )
ERR libimg_wri_bmp_bmp( IMG_BMP *src, IMG_COMPACT *compact )

【パラメータ】

IMG_BMP     *src     IMG_BMP構造体
IMG_COMPACT *compact DEV_SPEC データ

【リターン値】

≧ 0    正常
< 0    エラー(エラーコード)
  (形式共通)
  LIBIMG_ERR_READ_WRITE_ERROR  読み込みエラー(不正なバイト列であった場合も含む)
  LIBIMG_ERR_NO_MEMORY         作業用メモリの確保に失敗した
  LIBIMG_ERR_ILLEGAL_PARAMETER サポートされないパラメータが与えられた
  (以下はPNG形式の場合のみ)
  LIBIMG_PNG_ERR_CANNOT_CREATE_STRUCT libpngで使用する構造体が生成できなかった

【解説】

BMP構造体のデータから指定された形式の画像に変換する。
compactmethodエントリには以下の値を使用できる。

  LIBIMG_METHOD_JPEG  JPEG形式の画像書き込み
  LIBIMG_METHOD_PNG   PNG形式の画像書き込み
  LIBIMG_METHOD_BMP   Windows BMP形式の画像書き込み
compactoptエントリに指定する値は、以下の関数を用いた場合と同じ値を指定する。
compactmethod関数名
LIBIMG_METHOD_JPEGlibimg_wri_bmp_jpeg
LIBIMG_METHOD_PNGlibimg_wri_bmp_png
LIBIMG_METHOD_BMPlibimg_wri_bmp_bmp

JPEG画像(LIBIMG_METHOD_JPEG)の場合

compactoptエントリには以下の値を使用できる。

(all)
  LIBIMG_JPEG_OPT_NONE        オプションを指定しない
  LIBIMG_JPEG_OPT_DEFAULT     デフォルト値を指定

(quality parcentage)
  1〜100                      品質率(※この数字は10進数)。値が高い程品質は高い。

(dct tables)
  LIBIMG_JEPG_OPT_DCT_INT     DCTで intを使用
  LIBIMG_JPEG_OPT_DCT_SLOW    LIBIMG_JPEG_OPT_DCT_INTと同
  LIBIMG_JPEG_OPT_DCT_FAST    DCTの高速版を使用
  LIBIMG_JPEG_OPT_DCT_FLOAT   DCTで floatを使用

(progression)
  LIBIMG_JPEG_OPT_PROGRESSION プログレッシブJPEG形式

(progression option)
  LIBIMG_JPEG_OPT_BASELINE    LIBIMG_JPEG_OPT_PROGRESSION使用時にベースラインオプションを指定する

optに与える形式は次のとおり。
opt := [ all || ( progression option | progression | dct tables | quality parcentage ) ]

PNG(LIBIMG_METHOD_PNG)画像の場合

compactoptエントリには以下の値を使用できる。

  LIBIMG_PNG_OPT_BEST         圧縮率最適
  LIBIMG_PNG_OPT_DEFAULT      デフォルト値を使用
  LIBIMG_PNG_OPT_INTERLACE    インタレース形式

optに与える形式は次のとおり。
opt := [ LIBIMG_PNG_OPTDEFAULT || ( LIBIMG_PNG_OPT_INTERLACE | LIBIMG_PNG_OPT_BEST ) ]

なお、CSPEC/BMPのピクセル値にて透明色を設定している(最上位ビットが 1である)場合でも、PNGのアルファ値にその設定は反映されない。

Windows BMP(LIBIMG_METHOD_BMP)画像の場合

compactoptエントリには以下の値を使用できる。

  LIBIMG_BMP_OPT_COMPRESS     (8ビット)RLE圧縮の適用(カラーマップ使用時のみ)。

optに与える形式は次のとおり。
opt := [ LIBIMG_BMP_OPT_DEFAULT || (LIBIMG_BMP_OPT_COMPRESS) ]


CBMPIMAGESEGとの相互変換

本項目で使用する構造体の形式を以下に示す。

IMG_TADINFO

typedef struct {
  RECT  view;     /* 表示領域 */
  RECT  draw;     /* 描画領域 */
  UNITS h_unit;   /* 座標単位(水平) */
  UNITS v_unit;   /* 座標単位(垂直) */
  H     slope;    /* 傾き */
  H     rsrv1;    /* 予約 */
  CSPEC* cspec;   /* カラー情報 */
  CBMP*  cbmp;    /* 圧縮ビットマップ */
  UB*    mask;    /* マスク */
  W      masksz;  /* マスクのサイズ */
  COLOR  bgcolor; /* 背景色 */
  Bool   reverse; /* 色の反転表現 */
} IMG_TADINFO;

IMG_TADINFOの各エントリは、 IMAGESEGのエントリと対応している。

maskmaskszcbmpに示した画像の マスクを設定するものだが、マスクが存在しない場合にはそれぞれ NULL0を設定する。

bgcolorは背景色を設定するものだが、 背景色を設定しない場合には、0xffffffffを設定する。

ライブラリ関数リファレンス

libimg_rea_seg
 
TAD画像セグメントからのCBMPデータ読み込み

【形式】

WERR libimg_rea_seg(IMAGESEG* imgseg, W imgsegsz, IMG_TADINFO* info)

【パラメータ】

IMAGESEG*    imgseg   読み込み元の画像セグメント
W            imgsegsz 画像セグメントのサイズ
IMG_TADINFO* info     読み込んだ画像セグメント情報

【リターン値】

≧ 0    正常; 読み込んだプレーン番号(NULL指定時も含む)
< 0    エラー(エラーコード)
  ER_PAR 指定した画像セグメントのサイズ(imgsegsz)が BASE_SIZE_IMAGESEGよりも少なかった

【解説】

TAD画像セグメントを読みこんで、CBMP構造体データに格納しなおす。 格納先のメモリは予め用意しておかなければならない。

次のようにimgsegszを BASE_SIZE_IMAGESEGに指定することにより、 必要なメモリ格納にデータが取得できる。

{
  err = libimg_rea_seg(imageseg, BASE_SIZE_IMAGESEG, &info);
  if(err < 0) return -1;
  /* この間にメモリ確保 */
  err = libimg_rea_seg(imageseg, sizeof(imageseg), &info);
  if(err < 0) return -1;
  /* CSPECと CBMPを用いて処理 */
}

libimg_rea_seg
 
CBMPデータからTAD画像セグメントへの書き込み

【形式】

WERR libimg_wri_seg(IMAGESEG* imgseg, IMG_TADINFO* info);

【パラメータ】

IMAGESEG*    imgseg   書き込み先の画像セグメント。NULLのときは格納しない。
IMG_TADINFO* info     書き込む画像セグメント情報

【リターン値】

≧ 0    正常; 画像セグメントのサイズ
< 0    エラー(エラーコード)
  ER_PAR cspec, cbmpに NULLが指定された。

【解説】

CBMP構造体から TAD画像セグメントに書き込む。 格納先のメモリは予め用意しておかなければならない。

必要なメモリを計算するには、次のようにimgsegに NULLを指定する。

{
  W rec_offs; /* レコードオフセット */
  W ofd;      /* 出力先のファイルデスクリプタ */
  /* 画像セグメントの書き出し */
  {
    LTADSEG ltadseg = { TC_SPEC | TS_IMAGE, 0, 0 };
    IMAGESEG *imgseg;
    W imgseg_size = libimg_wri_seg(NULL, cspec, dstcbmp, NULL, NULL);
    
    if(imgseg_size > 65534)
      {
	ltadseg.len = 0xffff;
	ltadseg.llen = imgseg_size;
	wri_rec(ofd, rec_offs, (B*)<adseg, sizeof(LTADSEG), NULL, NULL, 0);
	rec_offs += sizeof(LTADSEG);
      }
    else 
      {
	ltadseg.len = imgseg_size;
	wri_rec(ofd, rec_offs, (B*)<adseg, sizeof(TADSEG), NULL, NULL, 0);
	rec_offs += sizeof(TADSEG);
      }
    imgseg = (IMAGESEG*)malloc(imgseg_size);
    libimg_wri_seg(imgseg, cspec, dstcbmp, NULL, NULL);
    wri_rec(ofd, rec_offs, (B*)imgseg, imgseg_size, NULL, NULL, 0);
    free(imgseg);
    rec_offs += imgseg_size;
  }
}


この章の目次にもどる
前頁: 2.16 付箋固有データ処理にもどる
次頁:2.18 その他にすすむ