-
Notifications
You must be signed in to change notification settings - Fork 83
Writing a PNG using the simplified API
Julien Rebetez edited this page Apr 16, 2016
·
2 revisions
This is an example of using libpng 1.6's simplified API to write an image. In this case, the source image comes from an OpenGL FBO which is in rgb565 format, so we first unpack rgb565 to uint8.
bool WritePNG(const std::string& filename, int width, int height, const uint16_t* rgb565) {
png_image img;
memset(&img, 0, sizeof(img));
img.version = PNG_IMAGE_VERSION;
img.width = width;
img.height = height;
img.format = PNG_FORMAT_RGB;
img.flags = 0;
img.colormap_entries = 0;
// We have to convert from RGB565 to RGB each coded on uint8 because PNG doesn't support RGB565
const int npixels = width * height;
std::vector<uint8_t> imgu8(npixels * 3);
for (int i = 0; i < npixels; ++i) {
const uint16_t v = rgb565[i];
// Convert and rescale to the full 0-255 range
// See http://stackoverflow.com/a/29326693
const uint8_t red5 = (v & 0xF800) >> 11;
const uint8_t green6 = (v & 0x7E0) >> 5;
const uint8_t blue5 = (v & 0x001F);
imgu8[3 * i] = ((red5 * 255 + 15) / 31);
imgu8[3 * i + 1] = ((green6 * 255 + 31) / 63);
imgu8[3 * i + 2] = ((blue5 * 255 + 15) / 31);
}
// negative stride indicates that bottom-most row is first in the buffer (to flip image)
const int row_stride = -width * 3;
png_image_write_to_file(
&img, filename.c_str(), false, (void*)imgu8.data(), row_stride, NULL
);
if (PNG_IMAGE_FAILED(img)) {
LOG(ERROR) << "Failed to write image : " << img.message;
return false;
} else {
if (img.warning_or_error != 0) {
LOG(WARNING) << "libpng warning : " << img.message;
}
return true;
}
}