-
Star
(121)
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; | |
} |
It might be a good idea to call png_destroy_read_struct
to avoid leaking memory.
TO avoid memory leaks just add:
in function:
write_png_file()
at the end add:
if (png && info)
png_destroy_write_struct(&png, &info);
in function
read_png_file()
at the end add:
png_destroy_read_struct(&png, &info, NULL);
png=NULL;
info=NULL;
Thanks for your sample.
I want to ask something about row data. How can I get only row data in png image. No header no info only image data. I want to get a pointer to (char *) type?
Has any idea about it ?
You have image data in row_pointers and you can access it directelly in process_png_file() function
Great code. I am using with xlib and it is working well.
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.
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;
}
Thanks :3