libpngを使用して画像を保存する



OpenGLを楽しみながら楽しんで、システムではなくプログラムを使用してスクリーンショットを撮る方法を学ぶことにしました。 glReadPixelsをかなり迅速にGoogleに検索しましたが、画像の保存に問題がありました。 私はコードをbmpで完全に保存し、tgaに保存機能を見つけた昔を思い出しましたが、これらのオプションはすべて自転車の匂いがすることに気づき、広範なライブラリを使用することにしました。 選択肢はlibpngにありました。

次に熊手に行きました。



ロシア語のライブラリの説明はないことがわかりました(これが私が現在この投稿を書いている理由です)、そして英語のドキュメントは最も便利な方法で書かれておらず、簡単な本格的な使用例さえ含んでいません。

以下では、最も簡単な場合にlibpngが画像を保存する方法を説明します。





まず、ヘッダーファイルを含める必要があります。



#include <png.h>
      
      







画像を保存する関数/メソッドで、保存するファイルを開き、png構造を作成します。



 void Renderer::screenshoot(const std::string& name) { FILE *fp = fopen(name.c_str(), "wb"); if (!fp) { return; } png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); if (!png_ptr) { goto close_file; }
      
      







次に、pngに関する情報の構造を作成し、エラーが発生した場合にsetjmpを呼び出し、出力をファイルに初期化する必要があります。



  png_infop png_info; if (!(png_info = png_create_info_struct(png_ptr))) { goto destroy_write; } if (setjmp(png_jmpbuf(png_ptr))) { goto destroy_write; } png_init_io(png_ptr, fp);
      
      







次に、画像のパラメーター(サイズ、色の数、カラーチャネルごとのビット数、インターレースと圧縮)を設定する必要があります。また、画像と画像の個々の行へのポインターの配列を作成します。



ここで熊手が始まります。



レーキ番号1:glReadPixels関数は、線が下から上に行く画像を提供しますが、通常、グラフィックスを扱うときは逆の順序を意味します。

熊手番号2:RGBAカラーを取得するglReadPixels関数を指定した場合、実際にはARGBの順序で取得します。 面倒ですが、見つけるのに1時間かかりましたが、その間にスクリーンショットの色が正しく表示されなかった理由がわかりませんでした。



libpngのデータがあるデータ配列と、OpenGLからのデータがあるargb_data配列を宣言します。行ポインターの配列を忘れないでください。



  png_set_IHDR(png_ptr, png_info, width, height, 0, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); unsigned char data[width*height*3], argb_data[width*height*4]; unsigned char *rows[height]; render(); glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, argb_data); for (int i = 0; i < height; ++i) { rows[height - i - 1] = data + (i*width*3); for (int j = 0; j < width; ++j) { int i1 = (i*width+j)*3; int i2 = (i*width+j)*4; data[i1++] = argb_data[++i2]; data[i1++] = argb_data[++i2]; data[i1++] = argb_data[++i2]; } }
      
      







画像を保存し、入力を完了し、エラーを処理するのはあなた次第です。



  png_set_rows(png_ptr, png_info, rows); png_write_png(png_ptr, png_info, PNG_TRANSFORM_IDENTITY, nullptr); png_write_end(png_ptr, png_info); destroy_write: png_destroy_write_struct(&png_str, nullptr); close_file: fclose(fp); }
      
      







したがって、比較的簡単な方法で、pngに画像を保存できます。 ただし、これだけでこのライブラリに対応できるとは思わないでください。 保存プロセスに従い、フィルターを適用し、インターレースを使用し、圧縮することができます...しかし、これを理解するには、元のドキュメントを読む必要があります



UPD。 glReadPixelsおよび行の順序に関するコメントを寄せてくれたMrGobusに感謝します。



All Articles