-
-
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; | |
} |
The most useful part of this was process_png_file()
; more specifically the lines png_bytep row = row_pointers[y];
and png_bytep px = &(row[x * 4]);
. Thanks!
hello,I want to use libpng to parse png file. I have downloaded the libpng, and build it successfully. Could you tell me how to put your c file into the libpng project?
Great when i use clang.
But then i need to compile it using g++-8 and the error is: fatal error: png.h: No such file or directory
I'm on mac and I did:
$ brew install libpng
Please help to solve it.
Cool, but the png.h is impossible to compile, which makes your code useless.
I'm tired of idiots unable to upload a working library. Yes, idiots. When my codes don't compile for my friends, I remove them.
Because there's nothing more unbearable than a programmer sharing the code of its super cool program when he's the only one on the earth that can compile it. Screw it.
hello,I want to use libpng to parse png file. I have downloaded the libpng, and build it successfully. Could you tell me how to put your c file into the libpng project?
Allow me to call you a liar. You can NOT successfully build libpng and ignore how to include one single C file in a project.
Hello.
I have used a picture.png to write in a file, and then saved that file successfully as another image (picture1.png). But I dont want to save to a file, i want to send it directly to a usb thermal printer which is connected to my raspberry pi (/dev/usb/lp0). When i do that it doesn't print as an image but some weird Chinese letters.
If anyone can help i would be very grateful.
Very nice example usage. Thank you.
This is awesome. Thank you so much.
png_get_rowbytes was the same, cache that would be better.
I realized my old gist has many comments... and so I decided to update it to cover next things.
- Destroy read and write structs.
- Update comments to use
-lpng16
, which is current Homebrew provided libpng version. - Check
row_pointers
for read and write.
*> 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;
}
Great code. I am using with xlib and it is working well.