/** * Reads the heightmap and/or size of the heightmap from a PNG file. * If map == NULL only the size of the PNG is read, otherwise a map * with grayscale pixels is allocated and assigned to *map. */ static bool ReadHeightmapPNG(char *filename, uint *x, uint *y, byte **map) { FILE *fp; png_structp png_ptr = NULL; png_infop info_ptr = NULL; fp = FioFOpenFile(filename, "rb"); if (fp == NULL) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_FILE_NOT_FOUND, WL_ERROR); return false; } png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_MISC, WL_ERROR); fclose(fp); return false; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL || setjmp(png_jmpbuf(png_ptr))) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_MISC, WL_ERROR); fclose(fp); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return false; } png_init_io(png_ptr, fp); /* Allocate memory and read image, without alpha or 16-bit samples * (result is either 8-bit indexed/grayscale or 24-bit RGB) */ png_set_packing(png_ptr); png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_PACKING | PNG_TRANSFORM_STRIP_ALPHA | PNG_TRANSFORM_STRIP_16, NULL); /* Maps of wrong colour-depth are not used. * (this should have been taken care of by stripping alpha and 16-bit samples on load) */ if ((png_get_channels(png_ptr, info_ptr) != 1) && (png_get_channels(png_ptr, info_ptr) != 3) && (png_get_bit_depth(png_ptr, info_ptr) != 8)) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_IMAGE_TYPE, WL_ERROR); fclose(fp); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return false; } if (map != NULL) { *map = MallocT<byte>(png_get_image_width(png_ptr, info_ptr) * png_get_image_height(png_ptr, info_ptr)); ReadHeightmapPNGImageData(*map, png_ptr, info_ptr); } *x = png_get_image_width(png_ptr, info_ptr); *y = png_get_image_height(png_ptr, info_ptr); fclose(fp); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return true; }
/** * The PNG Heightmap loader. */ static void ReadHeightmapPNGImageData(byte *map, png_structp png_ptr, png_infop info_ptr) { uint x, y; byte gray_palette[256]; png_bytep *row_pointers = NULL; /* Get palette and convert it to grayscale */ if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE) { int i; int palette_size; png_color *palette; bool all_gray = true; png_get_PLTE(png_ptr, info_ptr, &palette, &palette_size); for (i = 0; i < palette_size && (palette_size != 16 || all_gray); i++) { all_gray &= palette[i].red == palette[i].green && palette[i].red == palette[i].blue; gray_palette[i] = RGBToGrayscale(palette[i].red, palette[i].green, palette[i].blue); } /** * For a non-gray palette of size 16 we assume that * the order of the palette determines the height; * the first entry is the sea (level 0), the second one * level 1, etc. */ if (palette_size == 16 && !all_gray) { for (i = 0; i < palette_size; i++) { gray_palette[i] = 256 * i / palette_size; } } } row_pointers = png_get_rows(png_ptr, info_ptr); /* Read the raw image data and convert in 8-bit grayscale */ for (x = 0; x < png_get_image_width(png_ptr, info_ptr); x++) { for (y = 0; y < png_get_image_height(png_ptr, info_ptr); y++) { byte *pixel = &map[y * png_get_image_width(png_ptr, info_ptr) + x]; uint x_offset = x * png_get_channels(png_ptr, info_ptr); if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE) { *pixel = gray_palette[row_pointers[y][x_offset]]; } else if (png_get_channels(png_ptr, info_ptr) == 3) { *pixel = RGBToGrayscale(row_pointers[y][x_offset + 0], row_pointers[y][x_offset + 1], row_pointers[y][x_offset + 2]); } else { *pixel = row_pointers[y][x_offset]; } } } }
bool PngLoader::basicImageLoad() { DEBUG_ENTER_FUNC(); _pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!_pngPtr) return false; png_set_error_fn(_pngPtr, (png_voidp) NULL, (png_error_ptr) NULL, warningFn); _infoPtr = png_create_info_struct(_pngPtr); if (!_infoPtr) { png_destroy_read_struct(&_pngPtr, png_infopp_NULL, png_infopp_NULL); return false; } // Set the png lib to use our read function png_set_read_fn(_pngPtr, &_file, libReadFunc); unsigned int sig_read = 0; png_set_sig_bytes(_pngPtr, sig_read); png_read_info(_pngPtr, _infoPtr); int interlaceType; png_get_IHDR(_pngPtr, _infoPtr, (png_uint_32 *)&_width, (png_uint_32 *)&_height, &_bitDepth, &_colorType, &interlaceType, int_p_NULL, int_p_NULL); _channels = png_get_channels(_pngPtr, _infoPtr); if (_colorType & PNG_COLOR_MASK_PALETTE) _paletteSize = _infoPtr->num_palette; return true; }
/** * @brief Reads the png data as 32 bit format. */ png_bytep npng_readImage( npng_t *npng, png_bytep **rows, int *channels, int *pitch ) { png_bytep image_data; png_uint_32 width, height; png_bytep *row_pointers; png_uint_32 i, rowbytes; /* Get info. */ npng_dim( npng, &width, &height ); rowbytes = npng_pitch( npng ); /* Create the array of pointers to image data */ image_data = malloc( rowbytes * height ); if (image_data == NULL) ERR( "Out of Memory" ); row_pointers = malloc( sizeof(png_bytep) * height ); if (row_pointers == NULL) ERR( "Out of Memory" ); for (i=0; i<height; i++) row_pointers[i] = image_data + i*rowbytes; /* Return data. */ if (channels != NULL) *channels = png_get_channels( npng->png_ptr, npng->info_ptr ); if (pitch != NULL) *pitch = rowbytes; if (rows != NULL) *rows = row_pointers; else free( row_pointers ); return image_data; }
static VALUE each_interlace_none(struct each_args *args) { struct readerdata *reader; unsigned char *inwidthbuf, *outwidthbuf, *yinbuf; struct xscaler *xs; struct yscaler *ys; uint32_t i, scaley; int cmp; reader = args->reader; xs = &args->xs; inwidthbuf = xscaler_psl_pos0(xs); outwidthbuf = args->outwidthbuf; ys = &args->ys; scaley = reader->scale_height; cmp = png_get_channels(reader->png, reader->info); png_write_info(args->wpng, args->winfo); for(i=0; i<scaley; i++) { while ((yinbuf = yscaler_next(ys))) { png_read_row(reader->png, inwidthbuf, NULL); xscaler_scale(xs, yinbuf); } yscaler_scale(ys, outwidthbuf, i, cmp, 0); png_write_row(args->wpng, outwidthbuf); } png_write_end(args->wpng, args->winfo); return Qnil; }
static VALUE each_interlace(struct each_args *args) { struct readerdata *reader; unsigned char *inwidthbuf, *outwidthbuf; uint32_t i, width, height, scaley; int cmp; struct xscaler *xs; reader = args->reader; xs = &args->xs; inwidthbuf = xscaler_psl_pos0(xs); outwidthbuf = args->outwidthbuf; scaley = reader->scale_height; cmp = png_get_channels(reader->png, reader->info); width = png_get_image_width(reader->png, reader->info); height = png_get_image_height(reader->png, reader->info); png_write_info(args->wpng, args->winfo); png_read_image(args->reader->png, (png_bytepp)args->scanlines); for (i=0; i<scaley; i++) { yscaler_prealloc_scale(height, scaley, (uint8_t **)args->scanlines, (uint8_t *)inwidthbuf, i, width, cmp, 0); xscaler_scale(xs, outwidthbuf); png_write_row(args->wpng, outwidthbuf); } png_write_end(args->wpng, args->winfo); return Qnil; }
// //////////////////////////////////////////////////// // // Image* readPNGIntoImage() // //////////////////////////////////////////////////// // Image* PNGCodec::readPNGIntoImage(png_structp &png, png_infop &pngInfo) { uint8 **buf; int y; png_uint_32 iWidth, iHeight, iRowLength; png_byte iColourType, iBitsPerChannel, iNumChannels; png_bytepp pngRows; Image* imgPNG; png_read_png(png, pngInfo, PNG_TRANSFORM_BGR | PNG_TRANSFORM_STRIP_ALPHA, png_voidp_NULL); // pixels are in info_ptr->row_pointers // where row_pointers is: // png_bytep row_pointers[height]; // and is probably not contiguous iColourType = png_get_color_type(png, pngInfo); // if (iColourType != PNG_COLOR_TYPE_RGB_ALPHA) if (iColourType != PNG_COLOR_TYPE_RGB) throw new std::runtime_error("Colour type not supported - RGB only, PNGCodec::readPNGIntoImage()"); iBitsPerChannel = png_get_bit_depth(png, pngInfo); iNumChannels = png_get_channels(png, pngInfo); iHeight = png_get_image_height(png, pngInfo); iWidth = png_get_image_width(png, pngInfo); iRowLength = iWidth * (iBitsPerChannel * iNumChannels) / 8; // Should be same as iWidth // 07-Jul-2009: Directly load the PNG into a pre-created image's // buffer. Otherwise ImageRGB24 will make a copy of the buf, which // is a waste of space (and problematic for very large PNGs!) imgPNG = new Image; imgPNG->width = iWidth; imgPNG->height = iHeight; imgPNG->data = new unsigned char*[iHeight]; for (y = 0; y < iHeight; y++) { imgPNG->data[y] = new unsigned char[iRowLength]; } buf = imgPNG->data; pngRows = png_get_rows(png, pngInfo); for (y = 0; y < iHeight; y++) { // for (x = 0; x < iWidth; x++) { // This assumes BGR order, in readiness for the ImageRGB24 constructor // It also assumes 24-bit, no alpha // Yes, this is not good... memcpy(buf[y], pngRows[y], iRowLength); //memcpy((buf + (y * iRowLength)), pngRows[y], iRowLength); } // Clean up png_destroy_read_struct(&png, &pngInfo, png_infopp_NULL); return imgPNG; }
static VALUE each(int argc, VALUE *argv, VALUE self) { struct readerdata *reader; png_infop winfo; png_structp wpng; VALUE opts; int cmp, state, ret; struct each_args args; png_byte ctype; rb_scan_args(argc, argv, "01", &opts); Data_Get_Struct(self, struct readerdata, reader); raise_if_locked(reader); reader->locked = 1; cmp = png_get_channels(reader->png, reader->info); ctype = png_get_color_type(reader->png, reader->info); wpng = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, (png_error_ptr)error, (png_error_ptr)warning); winfo = png_create_info_struct(wpng); png_set_write_fn(wpng, 0, write_data_fn, flush_data_fn); png_set_IHDR(wpng, winfo, reader->scale_width, reader->scale_height, 8, ctype, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); args.reader = reader; args.wpng = wpng; args.winfo = winfo; args.outwidthbuf = malloc(reader->scale_width * cmp); if (!args.outwidthbuf) { rb_raise(rb_eRuntimeError, "Unable to allocate memory."); } ret = oil_libpng_init(&args.ol, reader->png, reader->info, reader->scale_width, reader->scale_height); if (ret!=0) { free(args.outwidthbuf); rb_raise(rb_eRuntimeError, "Unable to allocate memory."); } rb_protect((VALUE(*)(VALUE))each2, (VALUE)&args, &state); oil_libpng_free(&args.ol); free(args.outwidthbuf); png_destroy_write_struct(&wpng, &winfo); if (state) { rb_jump_tag(state); } return self; }
// Read out the image meta-data void LLPngWrapper::updateMetaData() { png_read_update_info(mReadPngPtr, mReadInfoPtr); mWidth = png_get_image_width(mReadPngPtr, mReadInfoPtr); mHeight = png_get_image_height(mReadPngPtr, mReadInfoPtr); mBitDepth = png_get_bit_depth(mReadPngPtr, mReadInfoPtr); mColorType = png_get_color_type(mReadPngPtr, mReadInfoPtr); mChannels = png_get_channels(mReadPngPtr, mReadInfoPtr); mHasBKGD = png_get_bKGD(mReadPngPtr, mReadInfoPtr, &mBackgroundColor); }
void pngSetHeader(PngStream* stream) { stream->info.imageWidth = png_get_image_width(stream->png_ptr, stream->info_ptr); stream->info.imageHeight = png_get_image_height(stream->png_ptr, stream->info_ptr); stream->info.numComponents = png_get_channels(stream->png_ptr, stream->info_ptr); stream->info.colorSpace = getPngDecColourType(png_get_color_type(stream->png_ptr, stream->info_ptr)); stream->info.bitDepth = png_get_bit_depth(stream->png_ptr, stream->info_ptr); stream->info.interlaceMethod = png_get_interlace_type(stream->png_ptr, stream->info_ptr); stream->info.chunkInformation = pngDecGetChunkInformation(stream); }
// Read out the image meta-data void LLPngWrapper::updateMetaData() { png_set_interlace_handling(mReadPngPtr); // <alchemy/> png_read_update_info(mReadPngPtr, mReadInfoPtr); mWidth = png_get_image_width(mReadPngPtr, mReadInfoPtr); mHeight = png_get_image_height(mReadPngPtr, mReadInfoPtr); mBitDepth = png_get_bit_depth(mReadPngPtr, mReadInfoPtr); mColorType = png_get_color_type(mReadPngPtr, mReadInfoPtr); mChannels = png_get_channels(mReadPngPtr, mReadInfoPtr); }
PngImage::PngImage(const ByteBuffer &compressed_bytes) { if (png_sig_cmp((png_bytep)compressed_bytes.raw(), 0, 8)) panic("not png file"); png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) panic("unable to create png read struct"); png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) panic("unable to create png info struct"); // don't call any png_* functions outside of this function D: if (setjmp(png_jmpbuf(png_ptr))) panic("libpng has jumped the shark"); png_set_sig_bytes(png_ptr, 8); PngIo png_io = {8, (unsigned char *)compressed_bytes.raw(), compressed_bytes.length()}; png_set_read_fn(png_ptr, &png_io, read_png_data); png_read_info(png_ptr, info_ptr); _width = png_get_image_width(png_ptr, info_ptr); _height = png_get_image_height(png_ptr, info_ptr); if (_width <= 0 || _height <= 0) panic("spritesheet image has no pixels"); // bits per channel (not per pixel) int bits_per_channel = png_get_bit_depth(png_ptr, info_ptr); if (bits_per_channel != 8) panic("expected 8 bits per channel"); int channel_count = png_get_channels(png_ptr, info_ptr); if (channel_count != 4) panic("expected 4 channels"); int color_type = png_get_color_type(png_ptr, info_ptr); if (color_type != PNG_COLOR_TYPE_RGBA) panic("expected RGBA"); _pitch = _width * bits_per_channel * channel_count / 8; _image_data.resize(_height * _pitch); png_bytep *row_ptrs = ok_mem(allocate_zero<png_bytep>(_height)); for (int i = 0; i < _height; i++) { png_uint_32 q = (_height - i - 1) * _pitch; row_ptrs[i] = (png_bytep)_image_data.raw() + q; } png_read_image(png_ptr, row_ptrs); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); destroy(row_ptrs, _height); }
void ogl::texture::load_png(const void *buf, size_t len, std::vector<GLubyte>& p) { // Initialize all PNG import data structures. png_structp rp = 0; png_infop ip = 0; png_bytep *bp = 0; if (!(rp = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0))) throw std::runtime_error("Failure creating PNG read structure"); if (!(ip = png_create_info_struct(rp))) throw std::runtime_error("Failure creating PNG info structure"); // Initialize the user-defined IO structure. struct png_user_io user; user.buf = (png_bytep) buf; user.len = (png_size_t) len; png_set_read_fn(rp, &user, png_user_read); // Enable the default PNG error handler. if (setjmp(png_jmpbuf(rp)) == 0) { // Read the PNG header. png_read_png(rp, ip, PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_SWAP_ENDIAN, 0); // Extract image properties. w = GLsizei(png_get_image_width (rp, ip)); h = GLsizei(png_get_image_height(rp, ip)); c = GLsizei(png_get_channels (rp, ip)); p.resize(w * h * c); // Read the pixel data. if ((bp = png_get_rows(rp, ip))) for (GLsizei i = 0, j = h - 1; i < h; ++i, --j) memcpy(&p[w * c * i], bp[j], (w * c)); } // Release all resources. png_destroy_read_struct(&rp, &ip, 0); }
GrfArray* grf_image_read_png(const char* filename){ png_structp png_ptr; png_infop info_ptr; unsigned char header[8]; FILE* infile = fopen(filename, "rb"); if(!infile) abort_("[read_png_file] File %s could not be opened for reading", filename); fread(header, 1, 8, infile); if(png_sig_cmp(header, 0, 8)) abort_("[read_png_file] File %s is not recognized as a PNG file", filename); png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(!png_ptr) abort_("[read_png_file] png_create_read_struct failed"); info_ptr = png_create_info_struct(png_ptr); if(!info_ptr) abort_("[read_png_file] png_create_info_struct failed"); if(setjmp(png_jmpbuf(png_ptr))) abort_("[read_png_file] Error during init_io"); png_init_io(png_ptr, infile); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); uint32_t* size = malloc(sizeof(uint32_t) * 3); size[0] = png_get_image_height(png_ptr, info_ptr); size[1] = png_get_image_width(png_ptr, info_ptr); size[2] = png_get_channels(png_ptr, info_ptr); uint8_t bit_depth = png_get_bit_depth(png_ptr, info_ptr); GrfDataType type; switch (bit_depth) { case 16: type = GRF_UINT16; break; default: type = GRF_UINT8; break; } GrfArray* array = grf_array_new_with_size_type(3, size, type); png_read_update_info(png_ptr, info_ptr); // Read file if(setjmp(png_jmpbuf(png_ptr))) abort_("[read_png_file] Error during read_image"); uint8_t**buffer = (uint8_t**)malloc(sizeof(uint8_t*) * size[0]); size_t row_stride = png_get_rowbytes(png_ptr, info_ptr); uint32_t i; for(i = 0; i < size[0]; i++) buffer[i] = array->data_uint8 + row_stride * i; png_read_image(png_ptr, buffer); fclose(infile); free(buffer); return array; }
struct image* image_from_png(const unsigned char* data, size_t sz) { /* Check file data header */ if (png_sig_cmp(data, 0, 8)) { set_last_asset_load_error("Incorrect png header"); return 0; } /* Allocate needed structures */ png_struct* png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); png_info* info = png_create_info_struct(png); png_info* end_info = png_create_info_struct(png); /* Register custom reader function */ struct png_read_callback_data cbdata; cbdata.src_buf = (unsigned char*)data; cbdata.sz = sz; png_set_read_fn(png, (void*)&cbdata, png_read_callback_fn); /* Read image info */ png_set_sig_bytes(png, 0); png_read_info(png, info); /* Gather image info */ int width = png_get_image_width(png, info); int height = png_get_image_height(png, info); /* Bits per CHANNEL not per pixel */ /* int bit_depth = png_get_bit_depth(png, info); */ int channels = png_get_channels(png, info); /* Image to be returned */ struct image* im = image_blank(width, height, channels); /* Read by row */ png_byte** row_ptrs = malloc(height * sizeof(png_byte*)); const size_t stride = png_get_rowbytes(png, info); for (int i = 0; i < height; ++i) { int q = (height - i - 1) * stride; row_ptrs[i] = im->data + q; } png_read_image(png, row_ptrs); free(row_ptrs); /* Free allocated structures */ png_destroy_read_struct(0, 0, &end_info); png_destroy_read_struct(0, &info, 0); png_destroy_read_struct(&png, 0, 0); /* Return read image */ return im; }
struct image *read_png(char *s, int len) { png_structp png_ptr; png_infop info_ptr; struct read_state state; state.base = s; state.off = 0; state.len = len; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, fail, fail, fail); if (png_ptr == NULL) { fprintf(stderr, "PNG init failed\n"); exit(EXIT_FAILURE); } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { fprintf(stderr, "PNG init failed\n"); exit(EXIT_FAILURE); } png_set_read_fn(png_ptr, &state, user_read_data); png_set_sig_bytes(png_ptr, 0); png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND, NULL); png_uint_32 width, height; int bit_depth; int color_type, interlace_type; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); struct image *i = malloc(sizeof(struct image)); i->width = width; i->height = height; i->depth = png_get_channels(png_ptr, info_ptr); i->buf = malloc(i->width * i->height * i->depth); unsigned int row_bytes = png_get_rowbytes(png_ptr, info_ptr); png_bytepp row_pointers = png_get_rows(png_ptr, info_ptr); int n; for (n = 0; n < i->height; n++) { memcpy(i->buf + row_bytes * n, row_pointers[n], row_bytes); } png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return i; }
int image_png_read_header(MediaScanImage *i, MediaScanResult *r) { int x; PNGData *p = malloc(sizeof(PNGData)); i->_png = (void *)p; LOG_MEM("new PNGData @ %p\n", i->_png); p->buf = (Buffer *)r->_buf; p->fp = r->_fp; p->path = r->path; p->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp) p, image_png_error, image_png_warning); if (!p->png_ptr) FATAL("Could not initialize libpng\n"); p->info_ptr = png_create_info_struct(p->png_ptr); if (!p->info_ptr) { png_destroy_read_struct(&p->png_ptr, (png_infopp) NULL, (png_infopp) NULL); FATAL("Could not initialize libpng\n"); } if (setjmp(png_jmpbuf(p->png_ptr))) { image_png_destroy(i); return 0; } png_set_read_fn(p->png_ptr, p, image_png_read_buf); png_read_info(p->png_ptr, p->info_ptr); i->width = png_get_image_width(p->png_ptr, p->info_ptr); i->height = png_get_image_height(p->png_ptr, p->info_ptr); i->channels = png_get_channels(p->png_ptr, p->info_ptr); i->has_alpha = 1; r->mime_type = MIME_IMAGE_PNG; // Match with DLNA profile // DLNA does not support interlaced images if (png_get_interlace_type(p->png_ptr, p->info_ptr) == PNG_INTERLACE_NONE) { for (x = 0; png_profiles_mapping[x].profile; x++) { if (i->width <= png_profiles_mapping[x].max_width && i->height <= png_profiles_mapping[x].max_height) { r->dlna_profile = png_profiles_mapping[x].profile->id; break; } } } return 1; }
static VALUE write_scanline(VALUE scan_line, png_structp png_ptr, png_infop info_ptr) { png_uint_32 width; png_byte components; if (TYPE(scan_line) != T_STRING) scan_line = rb_obj_as_string(scan_line); width = png_get_image_width(png_ptr, info_ptr); components = png_get_channels(png_ptr, info_ptr); if ((png_uint_32)RSTRING_LEN(scan_line) != width * components) rb_raise(rb_eRuntimeError, "Scanline has a bad size. Expected %d * %d but got %d.", (int)width, (int)components, (int)RSTRING_LEN(scan_line)); png_write_row(png_ptr, (png_bytep)RSTRING_PTR(scan_line)); return Qnil; }
QImage::Format QPngHandlerPrivate::readImageFormat() { QImage::Format format = QImage::Format_Invalid; png_uint_32 width, height; int bit_depth, color_type; png_colorp palette; int num_palette; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0); if (color_type == PNG_COLOR_TYPE_GRAY) { // Black & White or 8-bit grayscale if (bit_depth == 1 && png_get_channels(png_ptr, info_ptr) == 1) { format = QImage::Format_Mono; } else if (bit_depth == 16 && png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { format = QImage::Format_ARGB32; } else { format = QImage::Format_Indexed8; } } else if (color_type == PNG_COLOR_TYPE_PALETTE && png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette) && num_palette <= 256) { // 1-bit and 8-bit color if (bit_depth != 1) png_set_packing(png_ptr); png_read_update_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0); format = bit_depth == 1 ? QImage::Format_Mono : QImage::Format_Indexed8; } else { // 32-bit if (bit_depth == 16) png_set_strip_16(png_ptr); format = QImage::Format_ARGB32; // Only add filler if no alpha, or we can get 5 channel data. if (!(color_type & PNG_COLOR_MASK_ALPHA) && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { // We want 4 bytes, but it isn't an alpha channel format = QImage::Format_RGB32; } } return format; }
void setformat_rgba8( png_structp png, png_infop info, int bitdepth, int colortype ) { double gamma; if( png_get_gAMA( png, info, &gamma ) ) { png_set_gamma( png, 2.2, gamma ); } else { png_set_gamma( png, 2.2, 0.45455 ); } if( colortype == PNG_COLOR_TYPE_PALETTE ) { png_set_palette_to_rgb( png ); } if( colortype == PNG_COLOR_TYPE_GRAY && bitdepth < 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 ); } else { int channels = png_get_channels( png, info ); if( channels == 1 || channels == 3 ) { png_set_add_alpha( png, 255, PNG_FILLER_AFTER ); } } if( colortype == PNG_COLOR_TYPE_GRAY || colortype == PNG_COLOR_TYPE_GRAY_ALPHA ) { png_set_gray_to_rgb( png ); } if( bitdepth == 16 ) { png_set_scale_16( png ); } }
/* This function is called (as set by png_set_progressive_read_fn() above) when enough data has been supplied so all of the header has been read. */ void info_callback(png_structp png_ptr, png_infop info) { file_end=0; width = png_get_image_width(png_ptr,info); height = png_get_image_height(png_ptr,info); pixel_depth = png_get_bit_depth(png_ptr,info); channels = png_get_channels(png_ptr,info); color_type = png_get_color_type(png_ptr,info); if(color_type == PNG_COLOR_TYPE_GRAY) {} if(color_type == PNG_COLOR_TYPE_GRAY_ALPHA){} if(color_type == PNG_COLOR_TYPE_RGB) {} if(color_type == PNG_COLOR_TYPE_RGB_ALPHA) {} if(color_type == PNG_COLOR_TYPE_PALETTE ) { int r = png_get_PLTE(png_ptr,info,&palette,&num_palette); if(r == 0) { } png_uint_16p histogram = NULL; png_get_hIST(png_ptr, info, &histogram); png_set_expand(png_ptr); png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER); png_read_update_info(png_ptr, info); pixel_depth = 8; } int row_bytes = png_get_rowbytes(png_ptr,info); row_pointers = malloc(sizeof(png_bytep *) * height); for(size_t n=0;n<height;n++) { row_pointers[n] = malloc(row_bytes); } png_start_read_image(png_ptr); }
static void pngToPixels(png_structp png, png_infop info, Pixel** pixels, int* width, int* height) { const int w = png_get_image_width(png, info); const int h = png_get_image_height(png, info); const int channels = png_get_channels(png, info); Pixel* const px = malloc(w * h * sizeof(Pixel)); png_bytepp rows = png_get_rows(png, info); for(int i = 0; i < h; i++) { for(int j = 0; j < w; j++) { *(px + i * w + j) = a_pixel_make( rows[i][j * channels + 0], rows[i][j * channels + 1], rows[i][j * channels + 2] ); } } *width = w; *height = h; *pixels = px; }
static void pngToPixels(png_structp Png, png_infop Info, APixel** Pixels, int* Width, int* Height) { const int w = png_get_image_width(Png, Info); const int h = png_get_image_height(Png, Info); const int channels = png_get_channels(Png, Info); APixel* const px = a_mem_malloc(w * h * sizeof(APixel)); png_bytepp rows = png_get_rows(Png, Info); for(int i = 0; i < h; i++) { for(int j = 0; j < w; j++) { *(px + i * w + j) = a_pixel_make( rows[i][j * channels + 0], rows[i][j * channels + 1], rows[i][j * channels + 2] ); } } *Width = w; *Height = h; *Pixels = px; }
void PNGImageDecoder::headerAvailable() { png_structp png = m_reader->pngPtr(); png_infop info = m_reader->infoPtr(); png_uint_32 width = png_get_image_width(png, info); png_uint_32 height = png_get_image_height(png, info); // Protect against large PNGs. See http://bugzil.la/251381 for more details. const unsigned long maxPNGSize = 1000000UL; if (width > maxPNGSize || height > maxPNGSize) { longjmp(JMPBUF(png), 1); return; } // Set the image size now that the image header is available. if (!setSize(width, height)) { longjmp(JMPBUF(png), 1); return; } int bitDepth, colorType, interlaceType, compressionType, filterType, channels; png_get_IHDR(png, info, &width, &height, &bitDepth, &colorType, &interlaceType, &compressionType, &filterType); // The options we set here match what Mozilla does. // Expand to ensure we use 24-bit for RGB and 32-bit for RGBA. if (colorType == PNG_COLOR_TYPE_PALETTE || (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8)) png_set_expand(png); png_bytep trns = 0; int trnsCount = 0; if (png_get_valid(png, info, PNG_INFO_tRNS)) { png_get_tRNS(png, info, &trns, &trnsCount, 0); png_set_expand(png); } if (bitDepth == 16) png_set_strip_16(png); if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png); #if USE(QCMSLIB) if ((colorType & PNG_COLOR_MASK_COLOR) && !m_ignoreGammaAndColorProfile) { // We only support color profiles for color PALETTE and RGB[A] PNG. Supporting // color profiles for gray-scale images is slightly tricky, at least using the // CoreGraphics ICC library, because we expand gray-scale images to RGB but we // do not similarly transform the color profile. We'd either need to transform // the color profile or we'd need to decode into a gray-scale image buffer and // hand that to CoreGraphics. bool sRGB = false; ColorProfile colorProfile; getColorProfile(png, info, colorProfile, sRGB); bool imageHasAlpha = (colorType & PNG_COLOR_MASK_ALPHA) || trnsCount; m_reader->createColorTransform(colorProfile, imageHasAlpha, sRGB); m_hasColorProfile = !!m_reader->colorTransform(); } #endif if (!m_hasColorProfile) { // Deal with gamma and keep it under our control. const double inverseGamma = 0.45455; const double defaultGamma = 2.2; double gamma; if (!m_ignoreGammaAndColorProfile && png_get_gAMA(png, info, &gamma)) { const double maxGamma = 21474.83; if ((gamma <= 0.0) || (gamma > maxGamma)) { gamma = inverseGamma; png_set_gAMA(png, info, gamma); } png_set_gamma(png, defaultGamma, gamma); } else { png_set_gamma(png, defaultGamma, inverseGamma); } } // Tell libpng to send us rows for interlaced pngs. if (interlaceType == PNG_INTERLACE_ADAM7) png_set_interlace_handling(png); // Update our info now. png_read_update_info(png, info); channels = png_get_channels(png, info); ASSERT(channels == 3 || channels == 4); m_reader->setHasAlpha(channels == 4); if (m_reader->decodingSizeOnly()) { // If we only needed the size, halt the reader. #if PNG_LIBPNG_VER_MAJOR > 1 || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 5) // '0' argument to png_process_data_pause means: Do not cache unprocessed data. m_reader->setReadOffset(m_reader->currentBufferSize() - png_process_data_pause(png, 0)); #else m_reader->setReadOffset(m_reader->currentBufferSize() - png->buffer_size); png->buffer_size = 0; #endif } }
static int open_png(const char* name, png_structp* png_ptr, png_infop* info_ptr, png_uint_32* width, png_uint_32* height, png_byte* channels, FILE** fpp) { char resPath[256]; unsigned char header[8]; int result = 0; snprintf(resPath, sizeof(resPath)-1, TWRES "images/%s.png", name); printf("open_png %s\n", resPath); resPath[sizeof(resPath)-1] = '\0'; FILE* fp = fopen(resPath, "rb"); if (fp == NULL) { fp = fopen(name, "rb"); if (fp == NULL) { result = -1; goto exit; } } size_t bytesRead = fread(header, 1, sizeof(header), fp); if (bytesRead != sizeof(header)) { result = -2; goto exit; } if (png_sig_cmp(header, 0, sizeof(header))) { result = -3; goto exit; } *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!*png_ptr) { result = -4; goto exit; } *info_ptr = png_create_info_struct(*png_ptr); if (!*info_ptr) { result = -5; goto exit; } if (setjmp(png_jmpbuf(*png_ptr))) { result = -6; goto exit; } png_init_io(*png_ptr, fp); png_set_sig_bytes(*png_ptr, sizeof(header)); png_read_info(*png_ptr, *info_ptr); int color_type, bit_depth; png_get_IHDR(*png_ptr, *info_ptr, width, height, &bit_depth, &color_type, NULL, NULL, NULL); *channels = png_get_channels(*png_ptr, *info_ptr); /*if (bit_depth == 8 && *channels == 3 && color_type == PNG_COLOR_TYPE_RGB) { // 8-bit RGB images: great, nothing to do. } else if (bit_depth <= 8 && *channels == 1 && color_type == PNG_COLOR_TYPE_GRAY) { // 1-, 2-, 4-, or 8-bit gray images: expand to 8-bit gray. png_set_expand_gray_1_2_4_to_8(*png_ptr); } else if (bit_depth <= 8 && *channels == 1 && color_type == PNG_COLOR_TYPE_PALETTE) { // paletted images: expand to 8-bit RGB. Note that we DON'T // currently expand the tRNS chunk (if any) to an alpha // channel, because minui doesn't support alpha channels in // general. png_set_palette_to_rgb(*png_ptr); *channels = 3; } else { fprintf(stderr, "minui doesn't support PNG depth %d channels %d color_type %d\n", bit_depth, *channels, color_type); result = -7; goto exit; }*/ if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } *fpp = fp; return result; exit: if (result < 0) { png_destroy_read_struct(png_ptr, info_ptr, NULL); } if (fp != NULL) { fclose(fp); } return result; }
int Map::loadMapPng(std::string filename, const double& left, const double& top) { double x, y; size_t width, height; png_structp png_ptr; png_infop info_ptr; int number_of_passes; png_bytep * row_pointers; unsigned char header[8]; // 8 is the maximum size that can be checked /* open file and test for it being a png */ FILE *fp = fopen(filename.c_str(), "rb"); if (!fp) abort_("[read_png_file] File %s could not be opened for reading", filename.c_str()); fread(header, 1, 8, fp); if (png_sig_cmp(header, 0, 8)) abort_("[read_png_file] File %s is not recognized as a PNG file", filename.c_str()); /* initialize stuff */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) abort_("[read_png_file] png_create_read_struct failed"); info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) abort_("[read_png_file] png_create_info_struct failed"); if (setjmp(png_jmpbuf(png_ptr))) abort_("[read_png_file] Error during init_io"); png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); width = png_get_image_width(png_ptr, info_ptr); height = png_get_image_height(png_ptr, info_ptr); number_of_passes = png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); /* read file */ if (setjmp(png_jmpbuf(png_ptr))) abort_("[read_png_file] Error during read_image"); row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height); for (size_t yi = 0; yi < height; yi++) row_pointers[yi] = (png_byte*) malloc(png_get_rowbytes(png_ptr, info_ptr)); png_read_image(png_ptr, row_pointers); fclose(fp); double o; int c = png_get_channels(png_ptr, info_ptr); int rowbytes = png_get_rowbytes(png_ptr, info_ptr); //std::cout << "channels: " << c << std::endl; //std::cout << "rowbytes: " << rowbytes << std::endl; size_t n = 0; unsigned char v; for (size_t yi = 0; yi < height; ++yi) { y = top - (yi * gridRes() + gridRes() / 2.0); for (size_t xi = 0; xi < rowbytes; xi += c) { x = left + xi * gridRes() + gridRes() / 2.0; v = row_pointers[yi][xi]; if (v == 0) { o = MAX_ODDS; } else { o = PtoO(1.0 - (v / 255.0)); } //std::cout << "(" << x << ", " << y << ") = " << o << " : " << v << std::endl; set(x, y, o); } } /* cleanup heap allocation */ for (size_t yi = 0; yi < height; ++yi) free(row_pointers[yi]); free(row_pointers); return 0; }
// TODO: clean up error handling, too much dupe code right now bool PNG::_read_file(string const & file_name) { // unfortunately, we need to break down to the C-code level here, since // libpng is written in C itself // we need to open the file in binary mode FILE * fp = fopen(file_name.c_str(), "rb"); if (!fp) { epng_err("Failed to open " + file_name); return false; } // read in the header (max size of 8), use it to validate this as a PNG file png_byte header[8]; fread(header, 1, 8, fp); if (png_sig_cmp(header, 0, 8)) { epng_err("File is not a valid PNG file"); fclose(fp); _init(); return false; } // set up libpng structs for reading info png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { epng_err("Failed to create read struct"); fclose(fp); _init(); return false; } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { epng_err("Failed to create info struct"); png_destroy_read_struct(&png_ptr, NULL, NULL); fclose(fp); _init(); return false; } // set error handling to not abort the entire program if (setjmp(png_jmpbuf(png_ptr))) { epng_err("Error initializing libpng io"); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); _init(); return false; } // initialize png reading png_init_io(png_ptr, fp); // let it know we've already read the first 8 bytes png_set_sig_bytes(png_ptr, 8); // read in the basic image info png_read_info(png_ptr, info_ptr); // convert to 8 bits png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr); if (bit_depth == 16) png_set_strip_16(png_ptr); // verify this is in RGBA format, and if not, convert it to RGBA png_byte color_type = png_get_color_type(png_ptr, info_ptr); if (color_type != PNG_COLOR_TYPE_RGBA && color_type != PNG_COLOR_TYPE_RGB) { if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { if (bit_depth < 8) png_set_expand(png_ptr); png_set_gray_to_rgb(png_ptr); } if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); } // convert tRNS to alpha channel if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); _width = png_get_image_width(png_ptr, info_ptr); _height = png_get_image_height(png_ptr, info_ptr); png_read_update_info(png_ptr, info_ptr); // begin reading in the image if (setjmp(png_jmpbuf(png_ptr))) { epng_err("Error reading image with libpng"); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); _init(); return false; } int bpr = png_get_rowbytes(png_ptr, info_ptr); // number of bytes in a row int numchannels = png_get_channels(png_ptr, info_ptr); // initialie our image storage _pixels = new RGBAPixel[_height * _width]; png_byte * row = new png_byte[bpr]; for (size_t y = 0; y < _height; y++) { png_read_row(png_ptr, row, NULL); png_byte * pix = row; for (size_t x = 0; x < _width; x++) { RGBAPixel & pixel = _pixel(x,y); if (numchannels == 1 || numchannels == 2) { // monochrome unsigned char color = (unsigned char) *pix++; pixel.red = color; pixel.green = color; pixel.blue = color; if (numchannels == 2) pixel.alpha = (unsigned char) *pix++; else pixel.alpha = 255; } else if (numchannels == 3 || numchannels == 4) { pixel.red = (unsigned char) *pix++; pixel.green = (unsigned char) *pix++; pixel.blue = (unsigned char) *pix++; if (numchannels == 4) pixel.alpha = (unsigned char) *pix++; else pixel.alpha = 255; } } } // cleanup delete [] row; png_read_end(png_ptr, NULL); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); return true; }
void PNGImageDecoder::headerAvailable() { png_structp png = m_reader->pngPtr(); png_infop info = m_reader->infoPtr(); png_uint_32 width = png_get_image_width(png, info); png_uint_32 height = png_get_image_height(png, info); // Protect against large images. if (width > cMaxPNGSize || height > cMaxPNGSize) { longjmp(JMPBUF(png), 1); return; } // We can fill in the size now that the header is available. Avoid memory // corruption issues by neutering setFailed() during this call; if we don't // do this, failures will cause |m_reader| to be deleted, and our jmpbuf // will cease to exist. Note that we'll still properly set the failure flag // in this case as soon as we longjmp(). m_doNothingOnFailure = true; bool result = setSize(width, height); m_doNothingOnFailure = false; if (!result) { longjmp(JMPBUF(png), 1); return; } int bitDepth, colorType, interlaceType, compressionType, filterType, channels; png_get_IHDR(png, info, &width, &height, &bitDepth, &colorType, &interlaceType, &compressionType, &filterType); if ((colorType == PNG_COLOR_TYPE_RGB || colorType == PNG_COLOR_TYPE_RGB_ALPHA) && !m_ignoreGammaAndColorProfile) { // We currently support color profiles only for RGB and RGBA PNGs. Supporting // color profiles for gray-scale images is slightly tricky, at least using the // CoreGraphics ICC library, because we expand gray-scale images to RGB but we // don't similarly transform the color profile. We'd either need to transform // the color profile or we'd need to decode into a gray-scale image buffer and // hand that to CoreGraphics. m_colorProfile = readColorProfile(png, info); } // The options we set here match what Mozilla does. // Expand to ensure we use 24-bit for RGB and 32-bit for RGBA. if (colorType == PNG_COLOR_TYPE_PALETTE || (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8)) png_set_expand(png); png_bytep trns = 0; int trnsCount = 0; if (png_get_valid(png, info, PNG_INFO_tRNS)) { png_get_tRNS(png, info, &trns, &trnsCount, 0); png_set_expand(png); } if (bitDepth == 16) png_set_strip_16(png); if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png); // Deal with gamma and keep it under our control. double gamma; if (!m_ignoreGammaAndColorProfile && png_get_gAMA(png, info, &gamma)) { if ((gamma <= 0.0) || (gamma > cMaxGamma)) { gamma = cInverseGamma; png_set_gAMA(png, info, gamma); } png_set_gamma(png, cDefaultGamma, gamma); } else png_set_gamma(png, cDefaultGamma, cInverseGamma); // Tell libpng to send us rows for interlaced pngs. if (interlaceType == PNG_INTERLACE_ADAM7) png_set_interlace_handling(png); // Update our info now. png_read_update_info(png, info); channels = png_get_channels(png, info); ASSERT(channels == 3 || channels == 4); m_reader->setHasAlpha(channels == 4); if (m_reader->decodingSizeOnly()) { // If we only needed the size, halt the reader. #if defined(PNG_LIBPNG_VER_MAJOR) && defined(PNG_LIBPNG_VER_MINOR) && (PNG_LIBPNG_VER_MAJOR > 1 || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 5)) // '0' argument to png_process_data_pause means: Do not cache unprocessed data. m_reader->setReadOffset(m_reader->currentBufferSize() - png_process_data_pause(png, 0)); #else m_reader->setReadOffset(m_reader->currentBufferSize() - png->buffer_size); png->buffer_size = 0; #endif } }
/** * PNG File to RGB byte buffer (8 bits per channel). * * @param char *path * @param int *width * @param int *height * @return pointer or NULL **/ uint8_t *buffer_from_png(char *path, int *width, int *height) { int x, y, i; int bytes_per_row; uint8_t *buffer; /* libpng stuff */ png_structp png_ptr; png_infop info_ptr; png_byte channels; png_bytep *row_pointers; /* Open file */ FILE *fp = fopen(path, "rb"); if (!fp) { return NULL; } /* Initialize */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); return NULL; } /* Error handling */ if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); if (fp) { fclose(fp); } return NULL; } /* Init PNG stuff */ png_init_io(png_ptr, fp); png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY | PNG_TRANSFORM_EXPAND, NULL); fclose(fp); fp = NULL; /* Get width / height, channels */ *width = png_get_image_width(png_ptr, info_ptr); *height = png_get_image_height(png_ptr, info_ptr); channels = png_get_channels(png_ptr, info_ptr); /* Setup buffers */ row_pointers = png_get_rows(png_ptr, info_ptr); buffer = malloc(((*width) * 3) * (*height)); if (!buffer) { return NULL; } /*printf("Channels: %d\n", channels);*/ /* Copy to buffer, removing alpha */ bytes_per_row = (*width) * channels; i = 0; for (y = 0; y < (*height); ++y) { for (x = 0; x < bytes_per_row; ++x) { /* Skip over alpha channel, if present */ if (channels < 4 || ((x + 1) % 4)) { buffer[i] = row_pointers[y][x]; ++i; } } } png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return buffer; }
/** * Read PNG file to RGB24 Buffer * * @param char *path * @param int *width * @param int *height * @return pointer or NULL **/ uint32_t *rgb24_from_png(const char *path, int *width, int *height) { int x, y; uint8_t r, g, b; uint32_t *buffer, *out; /* libpng stuff */ png_structp png_ptr; png_infop info_ptr; png_byte channels; png_bytep *row_pointers; /* Open file */ FILE *fp = fopen(path, "rb"); if (!fp) { return NULL; } /* Initialize */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); return NULL; } /* Error handling */ if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); if (fp) { fclose(fp); } return NULL; } /* Init PNG stuff */ png_init_io(png_ptr, fp); png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY | PNG_TRANSFORM_EXPAND, NULL); fclose(fp); fp = NULL; /* Get width / height, channels */ *width = png_get_image_width(png_ptr, info_ptr); *height = png_get_image_height(png_ptr, info_ptr); channels = png_get_channels(png_ptr, info_ptr); /* Setup buffers */ row_pointers = png_get_rows(png_ptr, info_ptr); buffer = malloc(sizeof(*buffer) * (*width) * (*height)); if (!buffer) { return NULL; } /*printf("Channels: %d\n", channels);*/ /* Copy to buffer, removing alpha */ out = buffer; for (y = 0; y < *height; y++) { for (x = 0; x < *width; x++) { r = row_pointers[y][(x * channels) + 0], g = row_pointers[y][(x * channels) + 1], b = row_pointers[y][(x * channels) + 2]; PACK_RGB(r, g, b, tvxx_rgb_format_rgb24, *out); out++; } } png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return buffer; }