-
Star
(120)
You must be signed in to star a gist -
Fork
(24)
You must be signed in to fork a gist
-
-
Save niw/5963798 to your computer and use it in GitHub Desktop.
| /* | |
| * A simple libpng example program | |
| * http://zarb.org/~gc/html/libpng.html | |
| * | |
| * Modified by Yoshimasa Niwa to make it much simpler | |
| * and support all defined color_type. | |
| * | |
| * To build, use the next instruction on OS X. | |
| * $ brew install libpng | |
| * $ clang -lz -lpng16 libpng_test.c | |
| * | |
| * Copyright 2002-2010 Guillaume Cottenceau. | |
| * | |
| * This software may be freely redistributed under the terms | |
| * of the X11 license. | |
| * | |
| */ | |
| #include <stdlib.h> | |
| #include <stdio.h> | |
| #include <png.h> | |
| int width, height; | |
| png_byte color_type; | |
| png_byte bit_depth; | |
| png_bytep *row_pointers = NULL; | |
| void read_png_file(char *filename) { | |
| FILE *fp = fopen(filename, "rb"); | |
| png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); | |
| if(!png) abort(); | |
| png_infop info = png_create_info_struct(png); | |
| if(!info) abort(); | |
| if(setjmp(png_jmpbuf(png))) abort(); | |
| png_init_io(png, fp); | |
| png_read_info(png, info); | |
| width = png_get_image_width(png, info); | |
| height = png_get_image_height(png, info); | |
| color_type = png_get_color_type(png, info); | |
| bit_depth = png_get_bit_depth(png, info); | |
| // Read any color_type into 8bit depth, RGBA format. | |
| // See http://www.libpng.org/pub/png/libpng-manual.txt | |
| if(bit_depth == 16) | |
| png_set_strip_16(png); | |
| if(color_type == PNG_COLOR_TYPE_PALETTE) | |
| png_set_palette_to_rgb(png); | |
| // PNG_COLOR_TYPE_GRAY_ALPHA is always 8 or 16bit depth. | |
| if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) | |
| png_set_expand_gray_1_2_4_to_8(png); | |
| if(png_get_valid(png, info, PNG_INFO_tRNS)) | |
| png_set_tRNS_to_alpha(png); | |
| // These color_type don't have an alpha channel then fill it with 0xff. | |
| if(color_type == PNG_COLOR_TYPE_RGB || | |
| color_type == PNG_COLOR_TYPE_GRAY || | |
| color_type == PNG_COLOR_TYPE_PALETTE) | |
| png_set_filler(png, 0xFF, PNG_FILLER_AFTER); | |
| if(color_type == PNG_COLOR_TYPE_GRAY || | |
| color_type == PNG_COLOR_TYPE_GRAY_ALPHA) | |
| png_set_gray_to_rgb(png); | |
| png_read_update_info(png, info); | |
| if (row_pointers) abort(); | |
| row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height); | |
| for(int y = 0; y < height; y++) { | |
| row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png,info)); | |
| } | |
| png_read_image(png, row_pointers); | |
| fclose(fp); | |
| png_destroy_read_struct(&png, &info, NULL); | |
| } | |
| void write_png_file(char *filename) { | |
| int y; | |
| FILE *fp = fopen(filename, "wb"); | |
| if(!fp) abort(); | |
| png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); | |
| if (!png) abort(); | |
| png_infop info = png_create_info_struct(png); | |
| if (!info) abort(); | |
| if (setjmp(png_jmpbuf(png))) abort(); | |
| png_init_io(png, fp); | |
| // Output is 8bit depth, RGBA format. | |
| png_set_IHDR( | |
| png, | |
| info, | |
| width, height, | |
| 8, | |
| PNG_COLOR_TYPE_RGBA, | |
| PNG_INTERLACE_NONE, | |
| PNG_COMPRESSION_TYPE_DEFAULT, | |
| PNG_FILTER_TYPE_DEFAULT | |
| ); | |
| png_write_info(png, info); | |
| // To remove the alpha channel for PNG_COLOR_TYPE_RGB format, | |
| // Use png_set_filler(). | |
| //png_set_filler(png, 0, PNG_FILLER_AFTER); | |
| if (!row_pointers) abort(); | |
| png_write_image(png, row_pointers); | |
| png_write_end(png, NULL); | |
| for(int y = 0; y < height; y++) { | |
| free(row_pointers[y]); | |
| } | |
| free(row_pointers); | |
| fclose(fp); | |
| png_destroy_write_struct(&png, &info); | |
| } | |
| void process_png_file() { | |
| for(int y = 0; y < height; y++) { | |
| png_bytep row = row_pointers[y]; | |
| for(int x = 0; x < width; x++) { | |
| png_bytep px = &(row[x * 4]); | |
| // Do something awesome for each pixel here... | |
| //printf("%4d, %4d = RGBA(%3d, %3d, %3d, %3d)\n", x, y, px[0], px[1], px[2], px[3]); | |
| } | |
| } | |
| } | |
| int main(int argc, char *argv[]) { | |
| if(argc != 3) abort(); | |
| read_png_file(argv[1]); | |
| process_png_file(); | |
| write_png_file(argv[2]); | |
| return 0; | |
| } |
*> Cool, but the png.h is impossible to compile, which makes your code useless.
@Soraiko png.h is impossible to compile, because it is just a header. If you install cmake, you can download and build libpng library from sources.
- download libpng from sourceforge,
- download cmake and install,
- go to libpng sources
- make a build directory
- run cmake in that directory, point at parent directory
- select your host environment (visual studio, mingw, linux gcc) and target environment
that's it, I've done it a million times. On linux it is even easier.
- wget sourceforgeurl.targ.z
- tar zvxf package.tar.gz
- cd package
- mkdir build
- cd build
- cmake ..
- make -j 4
- done
Somehow for me, the script won't execute this line png_read_info(png, info); and png_write_info(png, info);
Can anyone explain what's happening?
Thanks for this snippet! It helped me a lot :)
The original code checks for a valid PNG signature before trying to read the file. You claim to have simplified the code. Omitting sanity checks is a bad way to simplify.
You should add
//check header magic
{
unsigned char header[8];
fread(header, 1, 8, fp);
if (png_sig_cmp(header, 0, 8))
{
std::cerr << "File " << filename << " is not recognized as a PNG file" << std::endl;
fclose(fp);
return;
}
}right before png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); in read_png_file
and
png_set_sig_bytes(png, 8); // we already read the 8 signature bytes right before png_read_info(png, info);
(FYI: I have #include <iostream> that's why i can use std::cerr)
In the setjmp() conditional, it's a good practice to also destroy the read struct and close the FILE*.
if (setjmp(png_jmpbuf(png))) {
png_destroy_read_struct(&png, &info, NULL);
fclose(fp);
return NULL;
}
I realized my old gist has many comments... and so I decided to update it to cover next things.
-lpng16, which is current Homebrew provided libpng version.row_pointersfor read and write.