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); }