OpenGL には、画像のピクセルを得る仕組みが備わっている。 それを使って得たものを、 Independent JPEG Group による ライブラリィを使って1、 JPEG 圧縮し、ファイルに出力する関数を書いてみた。
でっちあげたプログラム (2008/8/16作成, 2008/8/30更新) ijg-saveimage.cには、 次の3つの関数が含まれている。
/*
* 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);
}