aboutsummaryrefslogtreecommitdiffstats
path: root/loadpng.c
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
commit55f4e4a5ec657a017e3bf75299ad71fd1c968dd3 (patch)
tree550ce922ea0e125ac6a9738210ce2939bf2fe901 /loadpng.c
parent413f05aaf54fa08c0ae7e997327a4f4a473c0a8d (diff)
downloadexternal_qemu-55f4e4a5ec657a017e3bf75299ad71fd1c968dd3.zip
external_qemu-55f4e4a5ec657a017e3bf75299ad71fd1c968dd3.tar.gz
external_qemu-55f4e4a5ec657a017e3bf75299ad71fd1c968dd3.tar.bz2
Initial Contribution
Diffstat (limited to 'loadpng.c')
-rw-r--r--loadpng.c275
1 files changed, 275 insertions, 0 deletions
diff --git a/loadpng.c b/loadpng.c
new file mode 100644
index 0000000..b5c7a37
--- /dev/null
+++ b/loadpng.c
@@ -0,0 +1,275 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <png.h>
+
+#if 0
+#define LOG(x...) fprintf(stderr,"error: " x)
+#else
+#define LOG(x...) do {} while (0)
+#endif
+
+void *loadpng(const char *fn, unsigned *_width, unsigned *_height)
+{
+ FILE *fp = 0;
+ unsigned char header[8];
+ unsigned char *data = 0;
+ unsigned char **rowptrs = 0;
+ png_structp p = 0;
+ png_infop pi = 0;
+
+ png_uint_32 width, height;
+ int bitdepth, colortype, imethod, cmethod, fmethod, i;
+
+ p = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
+ if(p == 0) {
+ LOG("%s: failed to allocate png read struct\n", fn);
+ return 0;
+ }
+
+ pi = png_create_info_struct(p);
+ if(pi == 0) {
+ LOG("%s: failed to allocate png info struct\n", fn);
+ goto oops;
+ }
+
+ fp = fopen(fn, "rb");
+ if(fp == 0) {
+ LOG("%s: failed to open file\n", fn);
+ return 0;
+ }
+
+ if(fread(header, 8, 1, fp) != 1) {
+ LOG("%s: failed to read header\n", fn);
+ goto oops;
+ }
+
+ if(png_sig_cmp(header, 0, 8)) {
+ LOG("%s: header is not a PNG header\n", fn);
+ goto oops;
+ }
+
+ if(setjmp(png_jmpbuf(p))) {
+ LOG("%s: png library error\n", fn);
+ oops:
+ png_destroy_read_struct(&p, &pi, 0);
+ if(fp != 0) fclose(fp);
+ if(data != 0) free(data);
+ if(rowptrs != 0) free(rowptrs);
+ return 0;
+ }
+
+ png_init_io(p, fp);
+ png_set_sig_bytes(p, 8);
+
+ png_read_info(p, pi);
+
+ png_get_IHDR(p, pi, &width, &height, &bitdepth, &colortype,
+ &imethod, &cmethod, &fmethod);
+// printf("PNG: %d x %d (d=%d, c=%d)\n",
+// width, height, bitdepth, colortype);
+
+ switch(colortype){
+ case PNG_COLOR_TYPE_PALETTE:
+ png_set_palette_to_rgb(p);
+ break;
+
+ case PNG_COLOR_TYPE_RGB:
+ if(png_get_valid(p, pi, PNG_INFO_tRNS)) {
+ png_set_tRNS_to_alpha(p);
+ } else {
+ png_set_filler(p, 0xff, PNG_FILLER_AFTER);
+ }
+ break;
+
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ break;
+
+ case PNG_COLOR_TYPE_GRAY:
+ if(bitdepth < 8) {
+ png_set_gray_1_2_4_to_8(p);
+ }
+
+ default:
+ LOG("%s: unsupported (grayscale?) color type\n");
+ goto oops;
+ }
+
+ if(bitdepth == 16) {
+ png_set_strip_16(p);
+ }
+
+ data = (unsigned char*) malloc((width * 4) * height);
+ rowptrs = (unsigned char **) malloc(sizeof(unsigned char*) * height);
+
+ if((data == 0) || (rowptrs == 0)){
+ LOG("could not allocate data buffer\n");
+ goto oops;
+ }
+
+ for(i = 0; i < height; i++) {
+ rowptrs[i] = data + ((width * 4) * i);
+ }
+
+ png_read_image(p, rowptrs);
+
+ png_destroy_read_struct(&p, &pi, 0);
+ fclose(fp);
+ if(rowptrs != 0) free(rowptrs);
+
+ *_width = width;
+ *_height = height;
+
+ return (void*) data;
+}
+
+
+typedef struct
+{
+ const unsigned char* base;
+ const unsigned char* end;
+ const unsigned char* cursor;
+
+} PngReader;
+
+static void
+png_reader_read_data( png_structp png_ptr,
+ png_bytep data,
+ png_size_t length )
+{
+ PngReader* reader = png_get_io_ptr(png_ptr);
+ png_size_t avail = (png_size_t)(reader->end - reader->cursor);
+
+ if (avail > length)
+ avail = length;
+
+ memcpy( data, reader->cursor, avail );
+ reader->cursor += avail;
+}
+
+
+void *readpng(const unsigned char *base, size_t size, unsigned *_width, unsigned *_height)
+{
+ PngReader reader;
+ unsigned char *data = 0;
+ unsigned char **rowptrs = 0;
+ png_structp p = 0;
+ png_infop pi = 0;
+
+ png_uint_32 width, height;
+ int bitdepth, colortype, imethod, cmethod, fmethod, i;
+
+ p = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
+ if(p == 0) {
+ LOG("%s: failed to allocate png read struct\n", fn);
+ return 0;
+ }
+
+ pi = png_create_info_struct(p);
+ if(pi == 0) {
+ LOG("%s: failed to allocate png info struct\n", fn);
+ goto oops;
+ }
+
+ reader.base = base;
+ reader.end = base + size;
+ reader.cursor = base;
+
+ if(size < 8 || png_sig_cmp(base, 0, 8)) {
+ LOG("%s: header is not a PNG header\n", fn);
+ goto oops;
+ }
+
+ reader.cursor += 8;
+
+ if(setjmp(png_jmpbuf(p))) {
+ LOG("%s: png library error\n", fn);
+ oops:
+ png_destroy_read_struct(&p, &pi, 0);
+ if(data != 0) free(data);
+ if(rowptrs != 0) free(rowptrs);
+ return 0;
+ }
+
+ png_set_read_fn (p, &reader, png_reader_read_data);
+ png_set_sig_bytes(p, 8);
+
+ png_read_info(p, pi);
+
+ png_get_IHDR(p, pi, &width, &height, &bitdepth, &colortype,
+ &imethod, &cmethod, &fmethod);
+// printf("PNG: %d x %d (d=%d, c=%d)\n",
+// width, height, bitdepth, colortype);
+
+ switch(colortype){
+ case PNG_COLOR_TYPE_PALETTE:
+ png_set_palette_to_rgb(p);
+ break;
+
+ case PNG_COLOR_TYPE_RGB:
+ if(png_get_valid(p, pi, PNG_INFO_tRNS)) {
+ png_set_tRNS_to_alpha(p);
+ } else {
+ png_set_filler(p, 0xff, PNG_FILLER_AFTER);
+ }
+ break;
+
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ break;
+
+ case PNG_COLOR_TYPE_GRAY:
+ if(bitdepth < 8) {
+ png_set_gray_1_2_4_to_8(p);
+ }
+
+ default:
+ LOG("%s: unsupported (grayscale?) color type\n");
+ goto oops;
+ }
+
+ if(bitdepth == 16) {
+ png_set_strip_16(p);
+ }
+
+ data = (unsigned char*) malloc((width * 4) * height);
+ rowptrs = (unsigned char **) malloc(sizeof(unsigned char*) * height);
+
+ if((data == 0) || (rowptrs == 0)){
+ LOG("could not allocate data buffer\n");
+ goto oops;
+ }
+
+ for(i = 0; i < height; i++) {
+ rowptrs[i] = data + ((width * 4) * i);
+ }
+
+ png_read_image(p, rowptrs);
+
+ png_destroy_read_struct(&p, &pi, 0);
+ if(rowptrs != 0) free(rowptrs);
+
+ *_width = width;
+ *_height = height;
+
+ return (void*) data;
+}
+
+
+#if 0
+int main(int argc, char **argv)
+{
+ unsigned w,h;
+ unsigned char *data;
+
+ if(argc < 2) return 0;
+
+
+ data = loadpng(argv[1], &w, &h);
+
+ if(data != 0) {
+ printf("w: %d h: %d\n", w, h);
+ }
+
+ return 0;
+}
+#endif