保存的OpenGL屏幕像素为PNG使用的libpng [英] Save OpenGL screen pixels to PNG using libpng

查看:1841
本文介绍了保存的OpenGL屏幕像素为PNG使用的libpng的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直用土将图像保存为BMP,但事实证明,土(或stbi更具体)保存5MB〜图像(大约是1366×768分辨率的图像或更多),这是相当疯狂的。

I've been using SOIL to save images as BMP, but it turns out that SOIL (or stbi to be more specific) saves ~5MB images (which is about 1366x768 resolution image or more) which is quite insane.

原BMP节省code(注意一切都在渲染函数来完成):

Original BMP saving code (NOTE Everything is done in the render function):

uint8_t *pixels = new uint8_t[w * h * 3];
// copy pixels from screen
glBindTexture(GL_TEXTURE_2D, screenTex);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, w, h);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid *)pixels);

// invert pixels (stolen from SOILs source code)
for (int j = 0; j * 2 < h; ++j) {
    int x = j * w * 3;
    int y = (h - 1 - j) * w * 3;
    for (int i = w * 3; i > 0; --i) {
        uint8_t tmp = pixels[x];
        pixels[x] = pixels[y];
        pixels[y] = tmp;
        ++x;
        ++y;
    }
}

// save the image
int err = SOIL_save_image(fileName, SOIL_SAVE_TYPE_BMP, w, h, 3, pixels);
if (err)
   printf("Done\n");
else
   printf("Failed\n");

code保存PNG:

Code for saving PNG:

bool save_png_libpng(const char *filename, uint8_t *pixels, int w, int h)
{
    png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
    if (!png)
        return false;

    png_infop info = png_create_info_struct(png);
    if (!info) {
        png_destroy_write_struct(&png, &info);
        return false;
    }

    FILE *fp = fopen(filename, "wb");
    if (!fp) {
        png_destroy_write_struct(&png, &info);
        return false;
    }

    png_init_io(png, fp);
    png_set_IHDR(png, info, w, h, 8 /* depth */, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
        PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
    png_colorp palette = (png_colorp)png_malloc(png, PNG_MAX_PALETTE_LENGTH * sizeof(png_color));
    if (!palette) {
        fclose(fp);
        png_destroy_write_struct(&png, &info);
        return false;
    }
    png_set_PLTE(png, info, palette, PNG_MAX_PALETTE_LENGTH);
    png_write_info(png, info);
    png_set_packing(png);

    png_bytepp rows = (png_bytepp)png_malloc(png, h * sizeof(png_bytep));
    for (int i = 0; i < h; ++i)
        rows[i] = (png_bytep)(pixels + (h - i) * w * 3);

    png_write_image(png, rows);
    png_write_end(png, info);
    png_free(png, palette);
    png_destroy_write_struct(&png, &info);

    fclose(fp);
    delete[] rows;
    return true;
}

注意:我并没有改变任何原始code,只需更换 SOIL_save_image save_png

NOTE: I have not changed any of the original code, just replaced SOIL_save_image with save_png.

在code以下行失败:

The code fails in the following line:

png_write_image(PNG,行)

在PNG源$ C ​​$ C,此功能在突出显示的行失败:

in PNG's source code, this function fails at the highlighted line:

void PNGAPI
png_write_image(png_structrp png_ptr, png_bytepp image)
{
   png_uint_32 i; /* row index */
   int pass, num_pass; /* pass variables */
   png_bytepp rp; /* points to current row */

   if (png_ptr == NULL)
      return;

   png_debug(1, "in png_write_image");

#ifdef PNG_WRITE_INTERLACING_SUPPORTED
   /* Initialize interlace handling.  If image is not interlaced,
    * this will set pass to 1
    */
   num_pass = png_set_interlace_handling(png_ptr);
#else
   num_pass = 1;
#endif
   /* Loop through passes */
   for (pass = 0; pass < num_pass; pass++)
   {
      /* Loop through image */
      for (i = 0, rp = image; i < png_ptr->height; i++, rp++)
      {
         png_write_row(png_ptr, *rp); // HERE
      }
   }
}

png_write_row 失败,则这里(的code为png_write_row是很长,张贴在这里,所以如果你好奇这行之前发生了什么,你可以检查出在巴布亚新几内亚的源$ C ​​$ C pngwrite.c。)

png_write_row then fails here: (The code for png_write_row is quite long to post here, so if you're curious about what happens before this line, you can check out pngwrite.c in png's source code. )

   /* Copy user's row into buffer, leaving room for filter byte. */
   memcpy(png_ptr->row_buf + 1, row, row_info.rowbytes);

P.S:我用正是在MinGW的同一code和它的工作100%的罚款,当我切换到MSVC它开始失败。我不知道,如果GCC做了神奇在这里或这是我的code的错,所以我想知道学习的缘故。

P.S: I was using exactly the same code on MinGW and it was working 100% fine, when I switched to MSVC it started failing. I'm not sure if GCC does something magically here or it's my code's fault, so I would like to know for the sake of learning.

推荐答案

以下行:

行[I] =(png_bytep)(像素+(H - I)* W * 3);

是unforunately会过去的内存块(像素),所以下面编辑修复它:

is unforunately going past the block of memory (pixels), so the following edit fixes it:

行[I] =(png_bytep)(像素+(H - 我 - 1)* W * 3);

很微不足道,但不管。

这篇关于保存的OpenGL屏幕像素为PNG使用的libpng的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆