Created
December 30, 2013 00:09
-
-
Save vegardsjo/8176262 to your computer and use it in GitHub Desktop.
D readpng wrapper
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import std.stdio; | |
| import std.stdint; | |
| import std.string; | |
| import std.conv; | |
| import core.memory; | |
| extern (C) Png.png_image_t read_png(ubyte* in_data, size_t in_size, void* function(uint32_t) alloc); | |
| class Png | |
| { | |
| struct png_image_t | |
| { | |
| ubyte* data; | |
| size_t size; | |
| uint32_t width, height; | |
| int32_t bit_depth, color_type; | |
| int32_t components; | |
| int32_t alpha; | |
| byte error; | |
| char* error_message; | |
| } | |
| private png_image_t image; | |
| @property ubyte* data() { return image.data; } | |
| @property size_t size() { return image.size; } | |
| @property uint32_t width() { return image.width; } | |
| @property uint32_t height() { return image.height; } | |
| @property int32_t bitDepth() { return image.bit_depth; } | |
| @property int32_t colorType() { return image.color_type; } | |
| @property int32_t alpha() { return image.alpha; } | |
| private extern (C) void* alloc(uint32_t size) { | |
| //writefln("Trying to alloc %s bytes", size); | |
| return GC.malloc(size); | |
| } | |
| static Png readData(ubyte[] data) | |
| { | |
| auto self = new Png; | |
| self.image = read_png(data.ptr, data.length, &alloc); | |
| if (self.image.error) | |
| throw new Exception("Could not read image: %s".format(self.image.error_message.to!(string))); | |
| return self; | |
| } | |
| static Png readFile(string filename) | |
| { | |
| auto fp = File(filename, "rb"); | |
| fp.seek(0, SEEK_END); | |
| size_t size = fp.tell(); | |
| fp.seek(0); | |
| auto buffer = new ubyte[size]; | |
| buffer = fp.rawRead(buffer); | |
| return readData(buffer); | |
| } | |
| private this() {}; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdlib.h> | |
| #include <stdio.h> | |
| #include <setjmp.h> | |
| #include <stdint.h> | |
| #include <stdbool.h> | |
| #include "readpng.h" | |
| typedef struct user_read_struct | |
| { | |
| unsigned char *in_data; | |
| size_t size; | |
| size_t pos; | |
| } user_read_struct_t; | |
| void read_fn(png_structp png_ptr, png_bytep out_data, png_size_t length) | |
| { | |
| user_read_struct_t *read_struct = (user_read_struct_t*)png_get_io_ptr(png_ptr); | |
| if (read_struct->pos + length > read_struct->size) { | |
| png_error(png_ptr, "trying to read past end of image data"); | |
| return; | |
| } | |
| //printf("Reading %d bytes from data\n", length); | |
| memcpy(out_data, read_struct->in_data + read_struct->pos, length); | |
| read_struct->pos += length; | |
| } | |
| //png_image read_png(unsigned char *in_data, size_t size, unsigned char *out_data, size_t out_size) | |
| png_image_t read_png(unsigned char *in_data, size_t size, void *(*alloc)(uint32_t)) | |
| { | |
| png_image_t image; | |
| printf("COLOR_TYPE_RGBA: %d\n", PNG_COLOR_TYPE_RGBA); | |
| if (size < 8 || png_sig_cmp(in_data, 0, 8)) { | |
| image.error_message = "file is not a png image"; | |
| goto read_png_error; | |
| } | |
| png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); | |
| if (!png_ptr) { | |
| image.error_message = "could not allocate png struct."; | |
| goto read_png_error; | |
| } | |
| png_infop info_ptr = png_create_info_struct(png_ptr); | |
| if (!info_ptr) { | |
| image.error_message = "could not allocate png info struct."; | |
| png_destroy_read_struct(&png_ptr, NULL, NULL); | |
| goto read_png_error; | |
| } | |
| png_infop end_info_ptr = png_create_info_struct(png_ptr); | |
| if (!end_info_ptr) { | |
| image.error_message = "could not allocate png end info struct."; | |
| png_destroy_read_struct(&png_ptr, &info_ptr, NULL); | |
| goto read_png_error; | |
| } | |
| // Error handling | |
| if (setjmp(png_jmpbuf(png_ptr))) { | |
| image.error_message = "error reading image."; // TODO: get detailed error from png | |
| png_destroy_read_struct(&png_ptr, &info_ptr, &end_info_ptr); | |
| goto read_png_error; | |
| } | |
| // Initialize io | |
| //png_init_io(png_ptr, fp); | |
| user_read_struct_t user_read_struct = { in_data, size, 0 }; | |
| png_set_read_fn(png_ptr, &user_read_struct, read_fn); | |
| //png_set_sig_bytes(png_ptr, 8); // Necessary when not reading from file? | |
| // Callbacks | |
| //png_set_read_user_chunk_fn(png_ptr, user_chunk_ptr, read_chunk_callback); | |
| //png_set_read_status_fn(png_ptr, read_row_callback); | |
| // Unusued chunks | |
| png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_NEVER, NULL, 0); // ignore all custom chunks | |
| //png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_NEVER, "TODO", 1); | |
| // Custom chunks | |
| //png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_IF_SAFE, "CAKE", 1); | |
| // Set sane image resolution limits | |
| png_uint_32 width_max = 4096, height_max = 4096; // TODO | |
| png_set_user_limits(png_ptr, width_max, height_max); | |
| // Read image header | |
| png_read_info(png_ptr, info_ptr); | |
| png_get_IHDR(png_ptr, info_ptr, &image.width, &image.height, &image.bit_depth, &image.color_type, NULL, NULL, NULL); | |
| // Do input transformations | |
| // Convert paletted image to rgb | |
| if (image.color_type == PNG_COLOR_TYPE_PALETTE) | |
| png_set_palette_to_rgb(png_ptr); | |
| // Convert sub 8bit grayscale to 8bit | |
| else if (image.color_type == PNG_COLOR_TYPE_GRAY && image.bit_depth < 8) | |
| png_set_expand_gray_1_2_4_to_8(png_ptr); | |
| // TODO: document | |
| if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) | |
| png_set_tRNS_to_alpha(png_ptr); | |
| // Set the alpha channel to mean level of transparency instead of opacity | |
| //png_set_invert_alpha(png_ptr); | |
| // Unpack packed pixels | |
| if (image.bit_depth < 8) | |
| png_set_packing(png_ptr); | |
| // Convert 16 bit pixels to 8 | |
| else if (image.bit_depth == 16) | |
| png_set_strip_16(png_ptr); | |
| // Convert grayscale to rgb | |
| if (image.color_type == PNG_COLOR_TYPE_GRAY || image.color_type == PNG_COLOR_TYPE_GRAY_ALPHA) | |
| png_set_gray_to_rgb(png_ptr); | |
| // Convert RGB to RGBA | |
| png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); | |
| image.color_type = PNG_COLOR_TYPE_RGBA; | |
| // TODO: something to with interlacing; document | |
| //int number_of_passes = png_set_interlace_handling(png_ptr); | |
| // Update the info struct | |
| png_read_update_info(png_ptr, info_ptr); | |
| // Will probably be useful later | |
| image.alpha = image.color_type == PNG_COLOR_TYPE_RGBA; | |
| image.components = image.alpha ? 4 : 3; | |
| // Allocate space for image | |
| int rowbytes = png_get_rowbytes(png_ptr, info_ptr); | |
| image.size = sizeof(png_byte) * rowbytes * image.height; | |
| image.data = (png_bytep)alloc(image.size); | |
| // Setup row pointer and read image | |
| //png_bytepp image_rowp = png_get_rows(png_ptr, info_ptr); | |
| png_bytepp image_rowp = malloc(sizeof(png_bytep) * image.height); | |
| for (png_uint_32 i = 0; i < image.height; i++) | |
| //image_rowp[image.height - i - 1] = image.data + rowbytes * i; | |
| image_rowp[i] = image.data + rowbytes * i; | |
| png_read_image(png_ptr, image_rowp); | |
| printf("[read_png] width: %u, height: %u, bit_depth: %d, components: %d, alpha: %s\n", image.width, image.height, image.bit_depth, image.components, image.alpha ? "true" : "false"); | |
| png_destroy_read_struct(&png_ptr, &info_ptr, &end_info_ptr); | |
| free(image_rowp); | |
| read_png_ok: | |
| image.error = false; | |
| return image; | |
| read_png_error: | |
| image.error = true; | |
| return image; | |
| } | |
| #if 0 | |
| void read_row_callback(png_structp png_ptr, png_uint_32 row, int pass) | |
| { | |
| } | |
| #endif |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #ifndef READPNG_H | |
| #define READPNG_H | |
| #include <stdlib.h> | |
| #include <stdint.h> | |
| #include <png.h> | |
| typedef struct png_image | |
| { | |
| png_bytep data; | |
| size_t size; | |
| png_uint_32 width, height; | |
| png_int_32 bit_depth, color_type; | |
| png_int_32 components; | |
| png_int_32 alpha; | |
| int8_t error; | |
| char* error_message; | |
| } png_image_t; | |
| png_image_t read_png(unsigned char *in_data, size_t size, void *(*alloc)(uint32_t)); | |
| #endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment