next up previous
Next: 3.0.0.1 参考にした情報 Up: OpenGL/Glut メモ Previous: 2.5 数学科WS (Solaris 2.6)

3 画像のJPEG形式での保存

OpenGL には、画像のピクセルを得る仕組みが備わっている。 それを使って得たものを、 Independent JPEG Group による ライブラリィを使って1、 JPEG 圧縮し、ファイルに出力する関数を書いてみた。

でっちあげたプログラム (2008/8/16作成, 2008/8/30更新) ijg-saveimage.cには、 次の3つの関数が含まれている。

  1. prepare_ijg_buffer(int w, int h) -- 画像のサイズが分かってから、これを呼び出して、バッファーを用意する。
  2. snap_ijg_image() -- 描画が終ってから、これを呼び出すと、バッファーにピクセルが読み込まれる。
  3. save_ijg_image(char *fname) -- これを呼び出すと、バッファーに保存されているイメージを、 指定した名前のファイルに出力する。


/*
 * ijg-saveimage.c --- Independent JPEG Group のライブラリィを用いて
 *                     OpenGL で描いた画像を保存する (2008/8/16, by mk)
 *                     正方形でない画像が保存できないバグを取る (2008/8/30)
 *                     メモリー・リークしないよう img を固定長配列にする (同上)
 *                     ijg_buffer も重複して確保しないようにした (2008/11/2)
 *
 *  使い方:
 *    prepare_ijg_buffer(幅, 高さ);
 *    snape_ijg_image();
 *    save_ijg_image(ファイル名);
 *
 *  参考: http://www.syuhitu.org/other/jpeg/jpeg.html
 */

#include <stdio.h>
#include <stdlib.h>
#include <GL/glut.h>
#include <GL/gl.h>
#include <jpeglib.h>

#define MAX_HEIGHT (2048)

static int ijg_width = 0, ijg_height = 0;
static JSAMPLE *ijg_buffer = NULL;

void prepare_ijg_buffer(int w, int h)
{
  /* 前回と同じサイズならば何もしない */
  if (w == ijg_width && h == ijg_height)
    return;
  /* 大きすぎるものは拒否 */
  if (h > MAX_HEIGHT) {
    fprintf(stderr, "h=%d is too large (must be <= %d)\n", h, MAX_HEIGHT);
    return;
  }
  ijg_width = w; ijg_height = h;
  if (ijg_buffer != NULL)
    free(ijg_buffer);
  ijg_buffer = malloc(w * h * 3);
}

void snap_ijg_image()
{
  /* フロント・バッファーを読み込むように設定する */
  glReadBuffer(GL_FRONT);
  /* ピクセルの内容を buffer に保存 */
  glReadPixels(0, 0, ijg_width, ijg_height, GL_RGB, GL_UNSIGNED_BYTE, ijg_buffer);
}

void save_ijg_image(char *fname)
{
  struct jpeg_compress_struct cinfo;
  struct jpeg_error_mgr jerr;
  FILE *outfile;
  JSAMPROW img[2048]; // JSAMPARRAY *img; だった。
  int i,j;

  // JPEGオブジェクトの初期化
  cinfo.err = jpeg_std_error(&jerr);
  jpeg_create_compress(&cinfo);

  // ファイルを開く
  outfile = fopen(fname, "wb");
  jpeg_stdio_dest(&cinfo, outfile);

  // パラメータの設定
  cinfo.image_width = ijg_width;
  cinfo.image_height = ijg_height;
  cinfo.input_components = 3;
  cinfo.in_color_space = JCS_RGB;

  // デフォルト値の設定
  jpeg_set_defaults(&cinfo);

  jpeg_set_quality(&cinfo, 100, TRUE);
  // 圧縮の開始
  jpeg_start_compress(&cinfo, TRUE);
  // 全イメージデータを出力
  for (i = 0; i < ijg_height; i++) {
    img[i] = ijg_buffer + (ijg_height - i) * 3 * ijg_width;
  }
  jpeg_write_scanlines(&cinfo, img, ijg_height);
  // 圧縮の終了
  jpeg_finish_compress(&cinfo);
  // JPEGオブジェクトの破棄
  jpeg_destroy_compress(&cinfo);
  // ファイルを閉じる
  fclose(outfile);	
}



Subsections
next up previous
Next: 3.0.0.1 参考にした情報 Up: OpenGL/Glut メモ Previous: 2.5 数学科WS (Solaris 2.6)
桂田 祐史
2015-04-17