Image* Image::create(const char* path) { GP_ASSERT(path); // Open the file. std::unique_ptr<Stream> stream(FileSystem::open(path)); if (stream.get() == NULL || !stream->canRead()) { GP_ERROR("Failed to open image file '%s' - %d.", path, errno); return NULL; } // Verify PNG signature. unsigned char sig[8]; if (stream->read(sig, 1, 8) != 8 || png_sig_cmp(sig, 0, 8) != 0) { GP_ERROR("Failed to load file '%s'; not a valid PNG.", path); return NULL; } // Initialize png read struct (last three parameters use stderr+longjump if NULL). png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png == NULL) { GP_ERROR("Failed to create PNG structure for reading PNG file '%s'.", path); return NULL; } // Initialize info struct. png_infop info = png_create_info_struct(png); if (info == NULL) { GP_ERROR("Failed to create PNG info structure for PNG file '%s'.", path); png_destroy_read_struct(&png, NULL, NULL); return NULL; } // Set up error handling (required without using custom error handlers above). if (setjmp(png_jmpbuf(png))) { GP_ERROR("Failed to set up error handling for reading PNG file '%s'.", path); png_destroy_read_struct(&png, &info, NULL); return NULL; } // Initialize file io. png_set_read_fn(png, stream.get(), readStream); // Indicate that we already read the first 8 bytes (signature). png_set_sig_bytes(png, 8); // Read the entire image into memory. png_read_png(png, info, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_GRAY_TO_RGB, NULL); Image* image = new Image(); image->_width = png_get_image_width(png, info); image->_height = png_get_image_height(png, info); png_byte colorType = png_get_color_type(png, info); switch (colorType) { case PNG_COLOR_TYPE_RGBA: image->_format = Image::RGBA; break; case PNG_COLOR_TYPE_RGB: image->_format = Image::RGB; break; default: GP_ERROR("Unsupported PNG color type (%d) for image file '%s'.", (int)colorType, path); png_destroy_read_struct(&png, &info, NULL); return NULL; } size_t stride = png_get_rowbytes(png, info); // Allocate image data. image->_data = new unsigned char[stride * image->_height]; //GP_INFO("File[%s] ColorType : %d height : %d width : %d size : %d", path, image->_format, image->_height, image->_width, stride * image->_height); // Read rows into image data. png_bytepp rows = png_get_rows(png, info); for (unsigned int i = 0; i < image->_height; ++i) { memcpy(image->_data+(stride * (image->_height-1-i)), rows[i], stride); } //if (0 == strcmp(path, "res/hello_jpg.png")) //{ // std::string strTmp; // for (int i = 0; i < stride * image->_height; i++) // { // char szTmp[10] = { 0 }; // sprintf(szTmp, "%02X", image->_data[i]); // strTmp.append(szTmp); // if (i % 20 == 0) // { // GP_INFO("DATA : %s", strTmp.c_str()); // strTmp.assign(""); // } // } // if (strTmp.length()) // { // GP_INFO("DATA : %s", strTmp.c_str()); // } //} // Clean up. png_destroy_read_struct(&png, &info, NULL); return image; }
bool Image::initWithPngData(const unsigned char * data, ssize_t dataLen) { #if CC_USE_WIC return decodeWithWIC(data, dataLen); #else // length of bytes to check if it is a valid png file #define PNGSIGSIZE 8 bool ret = false; png_byte header[PNGSIGSIZE] = { 0 }; png_structp png_ptr = 0; png_infop info_ptr = 0; do { // png header len is 8 bytes CC_BREAK_IF(dataLen < PNGSIGSIZE); // check the data is png or not memcpy(header, data, PNGSIGSIZE); CC_BREAK_IF(png_sig_cmp(header, 0, PNGSIGSIZE)); // init png_struct png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); CC_BREAK_IF(!png_ptr); // init png_info info_ptr = png_create_info_struct(png_ptr); CC_BREAK_IF(!info_ptr); #if (PARA_TARGET_PLATFORM != PARA_PLATFORM_BADA && PARA_TARGET_PLATFORM != PARA_PLATFORM_NACL && PARA_TARGET_PLATFORM != PARA_PLATFORM_TIZEN) CC_BREAK_IF(setjmp(png_jmpbuf(png_ptr))); #endif // set the read call back function tImageSource imageSource; imageSource.data = (unsigned char*)data; imageSource.size = dataLen; imageSource.offset = 0; png_set_read_fn(png_ptr, &imageSource, pngReadCallback); // read png header info // read png file info 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); png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr); png_uint_32 color_type = png_get_color_type(png_ptr, info_ptr); //OUTPUT_LOG("color type %u", color_type); // force palette images to be expanded to 24-bit RGB // it may include alpha channel if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } // low-bit-depth grayscale images are to be expanded to 8 bits if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { bit_depth = 8; png_set_expand_gray_1_2_4_to_8(png_ptr); } // expand any tRNS chunk data into a full alpha channel if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); } // reduce images with 16-bit samples to 8 bits if (bit_depth == 16) { png_set_strip_16(png_ptr); } // Expanded earlier for grayscale, now take care of palette and rgb if (bit_depth < 8) { png_set_packing(png_ptr); } // update info png_read_update_info(png_ptr, info_ptr); bit_depth = png_get_bit_depth(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); switch (color_type) { case PNG_COLOR_TYPE_GRAY: _renderFormat = Texture2D::PixelFormat::I8; break; case PNG_COLOR_TYPE_GRAY_ALPHA: _renderFormat = Texture2D::PixelFormat::AI88; break; case PNG_COLOR_TYPE_RGB: _renderFormat = Texture2D::PixelFormat::RGB888; break; case PNG_COLOR_TYPE_RGB_ALPHA: _renderFormat = Texture2D::PixelFormat::RGBA8888; break; default: break; } // read png data png_size_t rowbytes; png_bytep* row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * _height); rowbytes = png_get_rowbytes(png_ptr, info_ptr); _dataLen = rowbytes * _height; _data = static_cast<unsigned char*>(malloc(_dataLen * sizeof(unsigned char))); if (!_data) { if (row_pointers != nullptr) { free(row_pointers); } break; } for (unsigned short i = 0; i < _height; ++i) { row_pointers[i] = _data + i*rowbytes; } png_read_image(png_ptr, row_pointers); png_read_end(png_ptr, nullptr); // premultiplied alpha for RGBA8888 if (PNG_PREMULTIPLIED_ALPHA_ENABLED && color_type == PNG_COLOR_TYPE_RGB_ALPHA) { premultipliedAlpha(); } if (row_pointers != nullptr) { free(row_pointers); } ret = true; } while (0); if (png_ptr) { png_destroy_read_struct(&png_ptr, (info_ptr) ? &info_ptr : 0, 0); } return ret; #endif }
/* * Magical PNG loader. You probably shouldn't edit this. */ int loadTextureFromPNG(char* filename , TextureInfo* t){ //Required structs and file pointers. png_structp png_ptr; png_infop info_ptr; unsigned int sig_read = 0; FILE *fp; //Again, this should return an error code instead of exiting, //but for this assignment, it should work anyway. if ((fp = fopen(filename, "rb")) == NULL){ printf("Error opening %s\n",filename); exit(1); } //Magic, do not touch. png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { printf("LibPNG did something terrible!\n"); fclose(fp); exit(1); } //Allocate the struct we're going to read the data into. info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { printf("LibPNG did something terrible!\n"); fclose(fp); png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); exit(1); } //Error handling magic. Do not touch. if (setjmp(png_jmpbuf(png_ptr))) { printf("LibPNG did something terrible!\n"); png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); fclose(fp); exit(1); } //Point libPNG to the right place png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, sig_read); //Yet more magic you shouldn't touch. We -probably- have enough memory to read it all in one go. png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND, png_voidp_NULL); //Start setting values in the textureinfo struct //Note that PNGs -can- have alpha. t->width = png_get_image_width(png_ptr,info_ptr); t->height = png_get_image_height(png_ptr,info_ptr); switch (png_get_color_type(png_ptr,info_ptr)) { case PNG_COLOR_TYPE_RGBA: t->hasAlpha = true; break; case PNG_COLOR_TYPE_RGB: t->hasAlpha = false; break; default: printf("Invalid PNG.\n"); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); exit(1); } //How long is a row? unsigned int row_bytes = png_get_rowbytes(png_ptr, info_ptr); //Allocate some space! t->textureData = (unsigned char*) malloc(row_bytes * t->height); //Read the image data into the texture array, in reverse row order. Because GL. png_bytepp row_pointers = png_get_rows(png_ptr, info_ptr); for (int i = 0; i < t->height; i++) { memcpy(t->textureData+(row_bytes * (t->height-1-i)), row_pointers[i], row_bytes); } //Clean up png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); fclose(fp); return 0; }
unsigned char* load_png_data(char *filename, int *w, int *h) { FILE *fp = fopen(filename, "rb"); if(!fp) { return NULL; } png_byte header[8]; fread(header, 1, 8, fp); if(png_sig_cmp(header, 0, 8)) { return NULL; } png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(!png_ptr) { return NULL; } png_infop info_ptr = png_create_info_struct(png_ptr); if(!info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); fclose(fp); return NULL; } png_infop end_ptr = png_create_info_struct(png_ptr); if(!end_ptr) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); return NULL; } if(setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_ptr); fclose(fp); return NULL; } png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); int bit_depth = png_get_bit_depth(png_ptr, info_ptr); switch(png_get_color_type(png_ptr, info_ptr)) { case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb(png_ptr); png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); break; case PNG_COLOR_TYPE_GRAY: png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); case PNG_COLOR_TYPE_GRAY_ALPHA: if(bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); if(bit_depth==16) png_set_strip_16(png_ptr); png_set_gray_to_rgb(png_ptr); break; case PNG_COLOR_TYPE_RGB: if(bit_depth < 8 ) png_set_packing(png_ptr); if(bit_depth == 16) png_set_strip_16(png_ptr); png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); break; default: break; } png_read_update_info(png_ptr, info_ptr); *w = png_get_image_width(png_ptr, info_ptr); *h = png_get_image_height(png_ptr, info_ptr); int rowbytes = (int)png_get_rowbytes(png_ptr, info_ptr); png_bytep data = malloc((*h)*rowbytes*sizeof(*data)); png_bytep row_pointers[*h]; int i; for(i=0; i<(*h); ++i) { row_pointers[i] = &data[i*rowbytes]; } png_read_image(png_ptr, row_pointers); png_destroy_read_struct(&png_ptr, &info_ptr, &end_ptr); fclose(fp); return data; }
//----------------------------------------------------------------- Image::Ptr ReadPNG(File* file) { assert(file); if (!file) { return 0; } // initialize the necessary libpng data structures png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if (!png_ptr) { return 0; } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, 0, 0); return 0; } // check if the file is actually a PNG file u8 sig_buf[8]; if (file->read(sig_buf, 8) != 8 || png_sig_cmp(sig_buf, 0, 8) != 0) { png_destroy_read_struct(&png_ptr, &info_ptr, 0); return 0; } // libpng uses SJLJ for error handling, so we need to define // any automatic variables before the call to setjmp() Image::Ptr image; ArrayAutoPtr<png_bytep> rows; // establish a return point if (setjmp(png_jmpbuf(png_ptr)) != 0) { png_destroy_read_struct(&png_ptr, &info_ptr, 0); return 0; } // tell libpng that we are already 8 bytes into the image file png_set_sig_bytes(png_ptr, 8); // tell libpng that we are going to use our own io functions png_set_read_fn(png_ptr, file, read_callback); // read the png header png_read_info(png_ptr, info_ptr); // get the image attributes int img_width = png_get_image_width(png_ptr, info_ptr); int img_height = png_get_image_height(png_ptr, info_ptr); int img_bit_depth = png_get_bit_depth(png_ptr, info_ptr); int img_color_type = png_get_color_type(png_ptr, info_ptr); // if the color channel bit depth is 16 bit, strip it to 8 bit if (img_bit_depth == 16) { png_set_strip_16(png_ptr); } // Note: Not sure if we need this, or if it's correct what we are doing here. // if the image has a tRNS chunk, use it for the alpha channel //if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { // png_set_tRNS_to_alpha(png_ptr); //} switch (img_color_type) { case PNG_COLOR_TYPE_PALETTE: { image = new ImageImpl(img_width, img_height, PixelFormat::RGB_P8); // get palette png_colorp palette = 0; int num_palette = 0; png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); // copy palette over to image std::memcpy(image->getPalette(), palette, num_palette * sizeof(RGB)); break; } case PNG_COLOR_TYPE_GRAY: { png_set_gray_to_rgb(png_ptr); image = new ImageImpl(img_width, img_height, PixelFormat::RGB); break; } case PNG_COLOR_TYPE_GRAY_ALPHA: { png_set_gray_to_rgb(png_ptr); image = new ImageImpl(img_width, img_height, PixelFormat::RGBA); break; } case PNG_COLOR_TYPE_RGB: { image = new ImageImpl(img_width, img_height, PixelFormat::RGB); break; } case PNG_COLOR_TYPE_RGB_ALPHA: { image = new ImageImpl(img_width, img_height, PixelFormat::RGBA); break; } default: // shouldn't happen png_destroy_read_struct(&png_ptr, &info_ptr, 0); return 0; } // prepare an array of row pointers for libpng PixelFormatDescriptor pfd = Image::GetPixelFormatDescriptor(image->getPixelFormat()); rows = new png_bytep[img_height]; for (int i = 0; i < img_height; ++i) { rows[i] = (png_bytep)(image->getPixels() + i * img_width * pfd.bytesPerPixel); } // read the image data png_read_image(png_ptr, rows.get()); // finish the read process png_read_end(png_ptr, 0); // clean up png_destroy_read_struct(&png_ptr, &info_ptr, 0); return image; }
static bool loadPng(const uint8_t *inputData, size_t size, Bytes &outputData, Color &color, Alpha &alpha, uint32_t &width, uint32_t &height, uint32_t &stride, const Bitmap::StrideFn &strideFn) { auto png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { log::text("libpng", "fail to create read struct"); return false; } auto info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { log::text("libpng", "fail to create info struct"); png_destroy_read_struct(&png_ptr, NULL, NULL); return false; } if (setjmp(png_jmpbuf(png_ptr))) { log::text("libpng", "error in processing (setjmp return)"); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return false; } Bitmap_readState state; state.data = inputData; state.offset = 0; png_set_read_fn(png_ptr,(png_voidp)&state, Bitmap_readDynamicData); 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); png_byte bitdepth = png_get_bit_depth(png_ptr, info_ptr); png_uint_32 color_type = png_get_color_type(png_ptr, info_ptr); if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } if (color_type == PNG_COLOR_TYPE_GRAY && bitdepth < 8) { bitdepth = 8; png_set_expand_gray_1_2_4_to_8(png_ptr); } if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); } if (bitdepth == 16) { png_set_strip_16(png_ptr); } if (bitdepth < 8) { png_set_packing(png_ptr); } png_read_update_info(png_ptr, info_ptr); bitdepth = png_get_bit_depth(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); auto rowbytes = png_get_rowbytes(png_ptr, info_ptr); if (color_type == PNG_COLOR_TYPE_GRAY) { color = (color == Color::A8?Color::A8:Color::I8); } else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { color = Color::IA88; } else if (color_type == PNG_COLOR_TYPE_RGB) { color = Color::RGB888; } else if (color_type == PNG_COLOR_TYPE_RGBA) { color = Color::RGBA8888; } else { width = 0; height = 0; stride = 0; outputData.clear(); log::format("Bitmap", "unsupported color type: %u", (unsigned int)color_type); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return false; } if (strideFn) { stride = max((uint32_t)strideFn(color, width), (uint32_t)rowbytes); } else { stride = (uint32_t)rowbytes; } if (color == Color::I8 || color == Color::RGB888) { alpha = Alpha::Opaque; } else { alpha = Alpha::Unpremultiplied; } // read png data png_bytep* row_pointers = new png_bytep[height]; auto dataLen = stride * height; outputData.resize(dataLen); for (unsigned short i = 0; i < height; ++i) { row_pointers[i] = outputData.data() + i*stride; } png_read_image(png_ptr, row_pointers); png_read_end(png_ptr, nullptr); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); delete [] row_pointers; if (!outputData.empty()) { return true; } return false; }
int ShapeWipeMain::read_pattern_image(int new_frame_width, int new_frame_height) { png_byte header[8]; int is_png; int row; int col; int scaled_row; int scaled_col; int pixel_width; unsigned char value; png_uint_32 width; png_uint_32 height; png_byte color_type; png_byte bit_depth; png_structp png_ptr; png_infop info_ptr; png_infop end_info; png_bytep *image; frame_width = new_frame_width; frame_height = new_frame_height; // Convert name to filename for(int i = 0; i < shape_paths.size(); i++) { if(!strcmp(shape_titles.get(i), shape_name)) { strcpy(filename, shape_paths.get(i)); break; } } FILE *fp = fopen(filename, "rb"); if (!fp) { return 1; } fread(header, 1, 8, fp); is_png = !png_sig_cmp(header, 0, 8); if (!is_png) { return 1; } png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { return 1; } /* Tell libpng we already checked the first 8 bytes */ png_set_sig_bytes(png_ptr, 8); info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); return 1; } end_info = png_create_info_struct(png_ptr); if (!end_info) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return 1; } png_init_io(png_ptr, fp); png_read_info(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); bit_depth = png_get_bit_depth(png_ptr, info_ptr); width = png_get_image_width (png_ptr, info_ptr); height = png_get_image_height(png_ptr, info_ptr); /* Skip the alpha channel if present * stripping alpha currently doesn't work in conjunction with * converting to grayscale in libpng */ if (color_type & PNG_COLOR_MASK_ALPHA) pixel_width = 2; else pixel_width = 1; /* Convert 16 bit data to 8 bit */ if (bit_depth == 16) png_set_strip_16(png_ptr); /* Expand to 1 pixel per byte if necessary */ if (bit_depth < 8) png_set_packing(png_ptr); /* Convert to grayscale */ if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) png_set_rgb_to_gray_fixed(png_ptr, 1, -1, -1); /* Allocate memory to hold the original png image */ image = (png_bytep*)malloc(sizeof(png_bytep)*height); for (row = 0; row < height; row++) { image[row] = (png_byte*)malloc(sizeof(png_byte)*width*pixel_width); } /* Allocate memory for the pattern image that will actually be * used for the wipe */ pattern_image = (unsigned char**)malloc(sizeof(unsigned char*)*frame_height); png_read_image(png_ptr, image); png_read_end(png_ptr, end_info); double row_factor, col_factor; double row_offset = 0.5, col_offset = 0.5; // for rounding if (preserve_aspect && aspect_w != 0 && aspect_h != 0) { row_factor = (height-1)/aspect_h; col_factor = (width-1)/aspect_w; if (row_factor < col_factor) col_factor = row_factor; else row_factor = col_factor; row_factor *= aspect_h/(double)(frame_height-1); col_factor *= aspect_w/(double)(frame_width-1); // center the pattern over the frame row_offset += (height-1-(frame_height-1)*row_factor)/2; col_offset += (width-1-(frame_width-1)*col_factor)/2; } else { // Stretch (or shrink) the pattern image to fill the frame row_factor = (double)(height-1)/(double)(frame_height-1); col_factor = (double)(width-1)/(double)(frame_width-1); } for (scaled_row = 0; scaled_row < frame_height; scaled_row++) { row = (int)(row_factor*scaled_row + row_offset); pattern_image[scaled_row] = (unsigned char*)malloc(sizeof(unsigned char)*frame_width); for (scaled_col = 0; scaled_col < frame_width; scaled_col++) { col = (int)(col_factor*scaled_col + col_offset)*pixel_width; value = image[row][col]; pattern_image[scaled_row][scaled_col] = value; if (value < min_value) min_value = value; if (value > max_value) max_value = value; } } png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(fp); /* Deallocate the original image as it is no longer needed */ for (row = 0; row < height; row++) { free(image[row]); } free (image); return 0; }
static GstFlowReturn gst_pngdec_caps_create_and_set (GstPngDec * pngdec) { GstFlowReturn ret = GST_FLOW_OK; gint bpc = 0, color_type; png_uint_32 width, height; GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN; g_return_val_if_fail (GST_IS_PNGDEC (pngdec), GST_FLOW_ERROR); /* Get bits per channel */ bpc = png_get_bit_depth (pngdec->png, pngdec->info); /* Get Color type */ color_type = png_get_color_type (pngdec->png, pngdec->info); /* Add alpha channel if 16-bit depth, but not for GRAY images */ if ((bpc > 8) && (color_type != PNG_COLOR_TYPE_GRAY)) { png_set_add_alpha (pngdec->png, 0xffff, PNG_FILLER_BEFORE); png_set_swap (pngdec->png); } #if 0 /* We used to have this HACK to reverse the outgoing bytes, but the problem * that originally required the hack seems to have been in videoconvert's * RGBA descriptions. It doesn't seem needed now that's fixed, but might * still be needed on big-endian systems, I'm not sure. J.S. 6/7/2007 */ if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) png_set_bgr (pngdec->png); #endif /* Gray scale with alpha channel converted to RGB */ if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { GST_LOG_OBJECT (pngdec, "converting grayscale png with alpha channel to RGB"); png_set_gray_to_rgb (pngdec->png); } /* Gray scale converted to upscaled to 8 bits */ if ((color_type == PNG_COLOR_TYPE_GRAY_ALPHA) || (color_type == PNG_COLOR_TYPE_GRAY)) { if (bpc < 8) { /* Convert to 8 bits */ GST_LOG_OBJECT (pngdec, "converting grayscale image to 8 bits"); #if PNG_LIBPNG_VER < 10400 png_set_gray_1_2_4_to_8 (pngdec->png); #else png_set_expand_gray_1_2_4_to_8 (pngdec->png); #endif } } /* Palette converted to RGB */ if (color_type == PNG_COLOR_TYPE_PALETTE) { GST_LOG_OBJECT (pngdec, "converting palette png to RGB"); png_set_palette_to_rgb (pngdec->png); } png_set_interlace_handling (pngdec->png); /* Update the info structure */ png_read_update_info (pngdec->png, pngdec->info); /* Get IHDR header again after transformation settings */ png_get_IHDR (pngdec->png, pngdec->info, &width, &height, &bpc, &pngdec->color_type, NULL, NULL, NULL); GST_LOG_OBJECT (pngdec, "this is a %dx%d PNG image", (gint) width, (gint) height); switch (pngdec->color_type) { case PNG_COLOR_TYPE_RGB: GST_LOG_OBJECT (pngdec, "we have no alpha channel, depth is 24 bits"); if (bpc == 8) format = GST_VIDEO_FORMAT_RGB; break; case PNG_COLOR_TYPE_RGB_ALPHA: GST_LOG_OBJECT (pngdec, "we have an alpha channel, depth is 32 or 64 bits"); if (bpc == 8) format = GST_VIDEO_FORMAT_RGBA; else if (bpc == 16) format = GST_VIDEO_FORMAT_ARGB64; break; case PNG_COLOR_TYPE_GRAY: GST_LOG_OBJECT (pngdec, "We have an gray image, depth is 8 or 16 (be) bits"); if (bpc == 8) format = GST_VIDEO_FORMAT_GRAY8; else if (bpc == 16) format = GST_VIDEO_FORMAT_GRAY16_BE; break; default: break; } if (format == GST_VIDEO_FORMAT_UNKNOWN) { GST_ELEMENT_ERROR (pngdec, STREAM, NOT_IMPLEMENTED, (NULL), ("pngdec does not support this color type")); ret = GST_FLOW_NOT_SUPPORTED; goto beach; } /* Check if output state changed */ if (pngdec->output_state) { GstVideoInfo *info = &pngdec->output_state->info; if (width == GST_VIDEO_INFO_WIDTH (info) && height == GST_VIDEO_INFO_HEIGHT (info) && GST_VIDEO_INFO_FORMAT (info) == format) { goto beach; } gst_video_codec_state_unref (pngdec->output_state); } pngdec->output_state = gst_video_decoder_set_output_state (GST_VIDEO_DECODER (pngdec), format, width, height, pngdec->input_state); gst_video_decoder_negotiate (GST_VIDEO_DECODER (pngdec)); GST_DEBUG ("Final %d %d", GST_VIDEO_INFO_WIDTH (&pngdec->output_state->info), GST_VIDEO_INFO_HEIGHT (&pngdec->output_state->info)); beach: return ret; }
unsigned char* PPGame_LoadPNG(const char* fileName,unsigned long* imageWidth,unsigned long* imageHeight,unsigned long* bytesPerRow) { FILE *PNG_file = fopen(fileName, "rb"); // fprintf(stderr, "open PNG file %s\n", fileName); if (PNG_file == NULL) { fprintf(stderr, "Can't open PNG file %s\n", fileName); return NULL; } unsigned char PNG_header[PNG_HEADER_SIZE]; fread(PNG_header, 1, PNG_HEADER_SIZE, PNG_file); if (png_sig_cmp(PNG_header, 0, PNG_HEADER_SIZE) != 0) { fprintf(stderr, "%s is not a PNG file\n", fileName); fclose(PNG_file); return NULL; } /* { for (int i=0;i<8;i++) { printf("%02X,",PNG_header[i]); } printf("\n"); } */ png_structp PNG_reader = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (PNG_reader == NULL) { fprintf(stderr, "Can't start reading PNG file %s\n", fileName); fclose(PNG_file); return NULL; } png_infop PNG_info = png_create_info_struct(PNG_reader); if (PNG_info == NULL) { fprintf(stderr, "Can't get info for PNG file %s\n", fileName); png_destroy_read_struct(&PNG_reader, NULL, NULL); fclose(PNG_file); return NULL; } png_infop PNG_end_info = png_create_info_struct(PNG_reader); if (PNG_end_info == NULL) { fprintf(stderr, "Can't get end info for PNG file %s\n", fileName); png_destroy_read_struct(&PNG_reader, &PNG_info, NULL); fclose(PNG_file); return NULL; } if (setjmp(png_jmpbuf(PNG_reader))) { fprintf(stderr, "Can't load PNG file %s\n", fileName); png_destroy_read_struct(&PNG_reader, &PNG_info, &PNG_end_info); fclose(PNG_file); return NULL; } png_init_io(PNG_reader, PNG_file); png_set_sig_bytes(PNG_reader, PNG_HEADER_SIZE); png_read_info(PNG_reader, PNG_info); if (PNG_reader == NULL) { fclose(PNG_file); return NULL; } png_uint_32 width, height; width = png_get_image_width(PNG_reader, PNG_info); height = png_get_image_height(PNG_reader, PNG_info); //printf("width %d\n",width); //printf("height %d\n",height); png_uint_32 bit_depth, color_type; bit_depth = png_get_bit_depth(PNG_reader, PNG_info); color_type = png_get_color_type(PNG_reader, PNG_info); //printf("bit_depth %d\n",bit_depth); //printf("rowbytes %d\n",png_get_rowbytes(PNG_reader, PNG_info)); if (color_type == PNG_COLOR_TYPE_PALETTE) { //png_set_palette_to_rgb(PNG_reader); png_set_palette_to_rgb(PNG_reader); } /* if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { png_set_gray_1_2_4_to_8(PNG_reader); } */ if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(PNG_reader); } if (png_get_valid(PNG_reader, PNG_info, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(PNG_reader); } else { png_set_filler(PNG_reader, 0xff, PNG_FILLER_AFTER); } if (bit_depth == 16) { png_set_strip_16(PNG_reader); } png_read_update_info(PNG_reader, PNG_info); png_byte* PNG_image_buffer = (png_byte*)malloc(4 * width * height); png_byte** PNG_rows = (png_byte**)malloc(height * sizeof(png_byte*)); unsigned int row; for (row = 0; row < height; ++row) { //PNG_rows[height - 1 - row] = PNG_image_buffer + (row * 4 * width); PNG_rows[row] = PNG_image_buffer + (row * 4 * width); } png_read_image(PNG_reader, PNG_rows); free(PNG_rows); png_destroy_read_struct(&PNG_reader, &PNG_info, &PNG_end_info); fclose(PNG_file); *imageWidth = width; *imageHeight = height; *bytesPerRow = width*4; return convert(PNG_image_buffer,width,height); }
gavl_video_frame_t * read_png(const char * filename, gavl_video_format_t * format, gavl_pixelformat_t pixelformat) { int i; unsigned char ** rows; gavl_video_converter_t * cnv; gavl_video_options_t * opt; gavl_video_format_t format_1; gavl_video_frame_t * frame, * frame_1; int bit_depth; int color_type; int has_alpha = 0; png_structp png_ptr; png_infop info_ptr; png_infop end_info; FILE * file; file = fopen(filename, "rb"); if(!file) { fprintf(stderr, "Cannot open file %s\n", filename); return NULL; } png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); setjmp(png_jmpbuf(png_ptr)); info_ptr = png_create_info_struct(png_ptr); end_info = png_create_info_struct(png_ptr); png_init_io(png_ptr, file); png_read_info(png_ptr, info_ptr); format->frame_width = png_get_image_width(png_ptr, info_ptr); format->frame_height = png_get_image_height(png_ptr, info_ptr); format->image_width = format->frame_width; format->image_height = format->frame_height; format->pixel_width = 1; format->pixel_height = 1; bit_depth = png_get_bit_depth(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); switch(color_type) { case PNG_COLOR_TYPE_GRAY: /* (bit depths 1, 2, 4, 8, 16) */ if(bit_depth < 8) #if GAVL_MAKE_BUILD(PNG_LIBPNG_VER_MAJOR, PNG_LIBPNG_VER_MINOR, PNG_LIBPNG_VER_RELEASE) < GAVL_MAKE_BUILD(1,2,9) png_set_gray_1_2_4_to_8(png_ptr); #else png_set_expand_gray_1_2_4_to_8(png_ptr); #endif if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); has_alpha = 1; } png_set_gray_to_rgb(png_ptr); break; case PNG_COLOR_TYPE_GRAY_ALPHA: /* (bit depths 8, 16) */ if(bit_depth == 16) png_set_strip_16(png_ptr); png_set_gray_to_rgb(png_ptr); break; case PNG_COLOR_TYPE_PALETTE: /* (bit depths 1, 2, 4, 8) */ png_set_palette_to_rgb(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); has_alpha = 1; } break; case PNG_COLOR_TYPE_RGB: /* (bit_depths 8, 16) */ if(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); has_alpha = 1; } if(bit_depth == 16) png_set_strip_16(png_ptr); break; case PNG_COLOR_TYPE_RGB_ALPHA: /* (bit_depths 8, 16) */ if(bit_depth == 16) png_set_strip_16(png_ptr); has_alpha = 1; break; } if(has_alpha) format->pixelformat = GAVL_RGBA_32; else format->pixelformat = GAVL_RGB_24; frame = gavl_video_frame_create(format); rows = malloc(format->frame_height * sizeof(*rows)); for(i = 0; i < format->frame_height; i++) rows[i] = frame->planes[0] + i * frame->strides[0]; png_read_image(png_ptr, rows); png_read_end(png_ptr, end_info); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(file); free(rows); /* Check wether to set up the converter */ if(format->pixelformat != pixelformat) { cnv = gavl_video_converter_create(); opt = gavl_video_converter_get_options(cnv); gavl_video_options_set_alpha_mode(opt, GAVL_ALPHA_BLEND_COLOR); gavl_video_format_copy(&format_1, format); format_1.pixelformat = pixelformat; frame_1 = gavl_video_frame_create(&format_1); gavl_video_converter_init(cnv, format, &format_1); gavl_video_convert(cnv, frame, frame_1); gavl_video_converter_destroy(cnv); format->pixelformat = pixelformat; } else frame_1 = NULL; if(frame_1) { gavl_video_frame_destroy(frame); return frame_1; } else return frame; }
void readPngFile(char* file_name) { //printf("%s\n", file_name); char header[8]; // 8 is the maximum size that can be checked /* open file and test for it being a png */ FILE *fp = fopen(file_name, "rb"); if (!fp){ printf("Unable to open file '%s'\n", file_name); exit(-1); //abort_("[read_png_file] File %s could not be opened for reading", file_name); } 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", file_name); // /* initialize stuff */ pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!pngPtr) abort_("[read_png_file] png_create_read_struct failed"); infoPtr = png_create_info_struct(pngPtr); if (!infoPtr) abort_("[read_png_file] png_create_info_struct failed"); if (setjmp(png_jmpbuf(pngPtr))) abort_("[read_png_file] Error during init_io"); png_init_io(pngPtr, fp); png_set_sig_bytes(pngPtr, 8); png_read_info(pngPtr, infoPtr); imageWidth = png_get_image_width(pngPtr, infoPtr); imageLength = png_get_image_height(pngPtr, infoPtr); config = png_get_color_type(pngPtr, infoPtr); bitsPerSample = png_get_bit_depth(pngPtr, infoPtr); // = 8 bits numberOfPasses = png_set_interlace_handling(pngPtr); png_read_update_info(pngPtr, infoPtr); imageWidth = png_get_image_width(pngPtr, infoPtr); imageLength = png_get_image_height(pngPtr, infoPtr); samplesPerPixel = png_get_channels(pngPtr, infoPtr); // = 4 bytes bitsPerPixel = samplesPerPixel*bitsPerSample; linebytes = samplesPerPixel * imageWidth; // = 640 //linebytes = png_get_rowbytes(pngPtr, infoPtr); = 640 imageBitSize = (sizeof(uint8) * imageWidth * imageLength * samplesPerPixel); imageSize = imageWidth * imageLength * samplesPerPixel; //printf("linebytes = %i, expected %i\n",linebytes,png_get_rowbytes(pngPtr, infoPtr)); //printf("Image Height is %d", sizeof(png_bytep) * imageLength); /* read file */ if (setjmp(png_jmpbuf(pngPtr))) abort_("[read_png_file] Error during read_image"); rowPointers = (png_bytep*) malloc(sizeof(png_bytep) * imageLength); for (y=0; y<imageLength; y++) rowPointers[y] = (png_byte*) malloc(png_get_rowbytes(pngPtr,infoPtr)); png_read_image(pngPtr, rowPointers); fclose(fp); }
// ref: http://zarb.org/~gc/html/libpng.html bool read_image_from_png_file(const char *filepath, image_t &image) { FILE *fp = fopen(filepath, "rb"); if (!fp) { log("[read_png_file] File %s could not be opened for reading", filepath); return false; } unsigned char header[8]; fread(header, 1, 8, fp); if (png_sig_cmp(header, 0, 8)) { log("[read_png_file] File %s is not recognized as a PNG file", filepath); return false; } png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { log("[read_png_file] png_create_read_struct failed"); return false; } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { log("[read_png_file] png_create_info_struct failed"); return false; } if (setjmp(png_jmpbuf(png_ptr))) { log("[read_png_file] Error during init_io"); return false; } png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); int width = png_get_image_width(png_ptr, info_ptr); int height = png_get_image_height(png_ptr, info_ptr); png_byte color_type = png_get_color_type(png_ptr, info_ptr); png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr); png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); if (setjmp(png_jmpbuf(png_ptr))) { log("[read_png_file] Error during read_image"); return false; } png_byte byte_depth = png_get_channels(png_ptr, info_ptr); if (bit_depth == 16) byte_depth *= 2; png_byte *buf = new png_byte[width * height * byte_depth]; int offset = 0; for (int y = 0; y < height; y++) { png_read_row(png_ptr, buf + offset, NULL); offset += width * byte_depth; } png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); image.width = width; image.height = height; image.byte_depth = byte_depth; image.data = (unsigned char *)buf; switch (color_type) { case PNG_COLOR_TYPE_GRAY: image.format = GL_LUMINANCE; break; case PNG_COLOR_TYPE_RGB: image.format = GL_RGB; break; case PNG_COLOR_TYPE_RGBA: image.format = GL_RGBA; break; case PNG_COLOR_TYPE_GA: image.format = GL_LUMINANCE_ALPHA; break; default: log("Non-support color type"); return false; } return true; }
/* * Function : libaroma_png_ex * Return Value: LIBAROMA_CANVASP * Descriptions: read png - extended */ LIBAROMA_CANVASP libaroma_png_ex( LIBAROMA_STREAMP stream, byte freeStream, byte hicolor) { if (!stream) { return NULL; } /* init adapter */ _LIBAROMA_PNG_ADAPTERP adapter = (_LIBAROMA_PNG_ADAPTERP) malloc(sizeof(_LIBAROMA_PNG_ADAPTER)); if (!adapter) { if (freeStream){ libaroma_stream_close(stream); } ALOGW("libaroma_png_ex cannot allocating adapter"); return NULL; } adapter->data = stream->data; adapter->n = stream->size; adapter->p = 0; /* png structures */ png_structp png_ptr = NULL; png_infop info_ptr = NULL; volatile LIBAROMA_CANVASP cv = NULL; byte header[8]; /* headers */ memcpy(header, adapter->data, sizeof(header)); adapter->p += sizeof(header); /* compare signature */ if (png_sig_cmp(header, 0, sizeof(header))) { ALOGW("libaroma_png_ex signature error"); goto exit; } /* read structure */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { ALOGW("libaroma_png_ex png_ptr is invalid"); goto exit; } /* info structure */ info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { ALOGW("libaroma_png_ex info_ptr is invalid"); goto exit; } /* jmp */ if (setjmp(png_jmpbuf(png_ptr))) { ALOGW("libaroma_png_ex jmp error"); goto exit; } /* callback */ png_set_read_fn(png_ptr, adapter, _libaroma_png_reader); png_set_sig_bytes(png_ptr, sizeof(header)); png_read_info(png_ptr, info_ptr); /* check color */ int bit_depth = png_get_bit_depth(png_ptr, info_ptr); int color_type = png_get_color_type(png_ptr, info_ptr); int channels = png_get_channels(png_ptr, info_ptr); if ((color_type == PNG_COLOR_TYPE_GRAY)|| (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)){ png_set_gray_to_rgb(png_ptr); png_read_update_info(png_ptr, info_ptr); } else if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); png_read_update_info(png_ptr, info_ptr); } else if (!((bit_depth == 8 && ( (channels == 3 && color_type == PNG_COLOR_TYPE_RGB) || (channels == 4 && color_type == PNG_COLOR_TYPE_RGBA) )) || (channels == 1 && color_type == PNG_COLOR_TYPE_PALETTE) )) { ALOGW("libaroma_png_ex mode not supported (c:%i, t:%i, d:%i)", channels, color_type, bit_depth); goto exit; } /* init main info */ int pcv_w = png_get_image_width(png_ptr, info_ptr); int pcv_h = png_get_image_height(png_ptr, info_ptr); int pcv_c = png_get_channels(png_ptr, info_ptr); /* verbose */ ALOGV("load png \"%s\" (%ix%ix%i)", stream->uri, pcv_w, pcv_h, pcv_c); /* new canvas */ cv = libaroma_canvas_new( pcv_w, pcv_h, (pcv_c==4)?1:0, hicolor); if (!cv) { ALOGW("libaroma_png_ex cannot create canvas"); goto exit; } /* switch to abgr */ if (pcv_c == 4) { png_set_bgr(png_ptr); } /* read row size*/ int row_sz = (int) png_get_rowbytes(png_ptr, info_ptr); /* loop */ int y, x; if (pcv_c == 4) { int z; png_bytep row_data = (png_bytep) malloc(row_sz); if (hicolor) { for (y = 0; y < pcv_h; ++y) { int ypos = (y * cv->l); wordp line = cv->data + ypos; bytep alph = cv->alpha + ypos; bytep hicl = cv->hicolor + ypos; png_read_row(png_ptr, row_data, NULL); for (x = 0, z = pcv_w * pcv_c; x < z; x += 4) { *line++ = libaroma_rgb( row_data[x + 2], row_data[x + 1], row_data[x]); *hicl++ = libaroma_color_left( row_data[x + 2], row_data[x + 1], row_data[x]); *alph++ = row_data[x + 3]; } } } else { for (y = 0; y < pcv_h; ++y) { int ypos = (y * cv->l); wordp line = cv->data + ypos; bytep alph = cv->alpha + ypos; png_read_row(png_ptr, row_data, NULL); libaroma_dither_line(y, pcv_w, line, (dwordp) row_data); for (x = 0, z = pcv_w * pcv_c; x < z; x += 4) { *alph++ = row_data[x + 3]; } } } free(row_data); } else if (pcv_c == 3) { int z; png_bytep row_data = (png_bytep) malloc(row_sz); if (hicolor) { for (y = 0; y < pcv_h; ++y) { wordp line = cv->data + (y * cv->l); bytep hicl = cv->hicolor + (y * cv->l); png_read_row(png_ptr, row_data, NULL); for (x = 0, z = pcv_w * pcv_c; x < z; x += 3) { *line++ = libaroma_rgb(row_data[x], row_data[x + 1], row_data[x + 2]); *hicl++ = libaroma_color_left( row_data[x + 2], row_data[x + 1], row_data[x]); } } } else { for (y = 0; y < pcv_h; ++y) { wordp line = cv->data + (y * cv->l); png_read_row(png_ptr, row_data, NULL); libaroma_dither_24to16(y, pcv_w, line, row_data); /* for (x = 0, z = pcv_w * pcv_c; x < z; x += 3) { *line++ = libaroma_dither_rgb( x, y, row_data[x + 2], row_data[x + 1], row_data[x]); }*/ } } free(row_data); } exit: png_destroy_read_struct(&png_ptr, &info_ptr, NULL); if (freeStream) { libaroma_stream_close(stream); } free(adapter); return cv; } /* End of libaroma_png_ex */
image_t* imagelib_load_png_from_mem( char* buffer, size_t size, const imageloadersettings_t settings ) { png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL); if ( !png_ptr ) { return NULL; } png_infop info = png_create_info_struct(png_ptr); if ( !info ) { png_destroy_read_struct(&png_ptr, NULL, NULL); return NULL; } if ( setjmp(png_jmpbuf(png_ptr)) ) { png_destroy_read_struct(&png_ptr, &info, NULL); return NULL; } png_memory_buffer membuffer = { .data = buffer, .size = size, .offset = 0 }; //png_init_io(png_ptr,fp); png_set_read_fn(png_ptr,&membuffer,png_read_data); png_set_sig_bytes(png_ptr,0); int png_transforms = PNG_TRANSFORM_STRIP_16|PNG_TRANSFORM_SWAP_ENDIAN|PNG_TRANSFORM_PACKING|PNG_TRANSFORM_EXPAND|(settings.swaprb?PNG_TRANSFORM_BGR:0); png_read_png(png_ptr, info, png_transforms, NULL); int rowbytes = png_get_rowbytes(png_ptr, info); int width = png_get_image_width(png_ptr, info); int height = png_get_image_height(png_ptr, info); int bit_depth = png_get_bit_depth(png_ptr, info); int color_type = png_get_color_type(png_ptr, info); // convert bit_depth + color_type to image format int bytepp = 0; if ( bit_depth==8 ) { switch( color_type ) { case PNG_COLOR_TYPE_GRAY: bytepp = 1; break; case PNG_COLOR_TYPE_GRAY_ALPHA: bytepp = 2; break; case PNG_COLOR_TYPE_RGB: bytepp = 3; break; case PNG_COLOR_TYPE_RGBA: bytepp = 4; break; } } if ( bytepp==0 ) { png_destroy_read_struct(&png_ptr, &info, NULL); return NULL; } int forcergba = settings.forcergba && color_type!=PNG_COLOR_TYPE_RGBA; image_t* image = malloc(sizeof(image_t)); image->data = malloc(sizeof(unsigned char)*width*height*(forcergba?4:bytepp)); image->width = width; image->height = height; image->bpp = bytepp; int stride = width*(forcergba?4:bytepp); png_bytepp row_pointers = png_get_rows(png_ptr, info); int x,y; if (!forcergba) { if (settings.swapy) { for ( y=0; y<image->height; y++ ) memcpy(image->data+stride*(image->height-1-y), row_pointers[y], rowbytes); } else { for ( y=0; y<image->height; y++ ) memcpy(image->data+stride*y, row_pointers[y], rowbytes); } } else { if (color_type==PNG_COLOR_TYPE_RGB) { for ( y=0;y<image->height;y++ ) { unsigned char* src = row_pointers[y]; unsigned char* trg = image->data+stride*y; for ( x=0; x<image->width; x++ ) { int tx = x*4; int sx = x*bytepp; trg[tx+0] = src[sx+0]; trg[tx+1] = src[sx+1]; trg[tx+2] = src[sx+2]; trg[tx+3] = settings.alpha; } } } else if (color_type==PNG_COLOR_TYPE_GRAY) { for ( y=0;y<image->height;y++ ) { unsigned char* src = row_pointers[y]; unsigned char* trg = image->data+stride*y; for ( x=0; x<image->width; x++ ) { int tx = x*4; int sx = x*bytepp; trg[tx+0] = src[sx]; trg[tx+1] = src[sx]; trg[tx+2] = src[sx]; trg[tx+3] = settings.alpha; } } } else if (color_type==PNG_COLOR_TYPE_GRAY_ALPHA) { for ( y=0;y<image->height;y++ ) { unsigned char* src = row_pointers[y]; unsigned char* trg = image->data+stride*y; for ( x=0; x<image->width; x++ ) { int tx = x*4; int sx = x*bytepp; trg[tx+0] = src[sx]; trg[tx+1] = src[sx]; trg[tx+2] = src[sx]; trg[tx+3] = src[sx+1]; } } } } png_destroy_read_struct(&png_ptr, &info, NULL); return image; }
static FIBITMAP * DLL_CALLCONV Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { png_structp png_ptr = NULL; png_infop info_ptr; png_uint_32 width, height; png_colorp png_palette = NULL; int color_type, palette_entries = 0; int bit_depth, pixel_depth; // pixel_depth = bit_depth * channels FIBITMAP *dib = NULL; RGBQUAD *palette = NULL; // pointer to dib palette png_bytepp row_pointers = NULL; int i; fi_ioStructure fio; fio.s_handle = handle; fio.s_io = io; if (handle) { BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS; try { // check to see if the file is in fact a PNG file BYTE png_check[PNG_BYTES_TO_CHECK]; io->read_proc(png_check, PNG_BYTES_TO_CHECK, 1, handle); if (png_sig_cmp(png_check, (png_size_t)0, PNG_BYTES_TO_CHECK) != 0) { return NULL; // Bad signature } // create the chunk manage structure png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, error_handler, warning_handler); if (!png_ptr) { return NULL; } // create the info structure info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return NULL; } // init the IO png_set_read_fn(png_ptr, &fio, _ReadProc); if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return NULL; } // because we have already read the signature... png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); // read the IHDR chunk png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); pixel_depth = png_get_bit_depth(png_ptr, info_ptr) * png_get_channels(png_ptr, info_ptr); // get image data type (assume standard image type) FREE_IMAGE_TYPE image_type = FIT_BITMAP; if (bit_depth == 16) { if ((pixel_depth == 16) && (color_type == PNG_COLOR_TYPE_GRAY)) { image_type = FIT_UINT16; } else if ((pixel_depth == 48) && (color_type == PNG_COLOR_TYPE_RGB)) { image_type = FIT_RGB16; } else if ((pixel_depth == 64) && (color_type == PNG_COLOR_TYPE_RGB_ALPHA)) { image_type = FIT_RGBA16; } else { // tell libpng to strip 16 bit/color files down to 8 bits/color png_set_strip_16(png_ptr); bit_depth = 8; } } #ifndef FREEIMAGE_BIGENDIAN if((image_type == FIT_UINT16) || (image_type == FIT_RGB16) || (image_type == FIT_RGBA16)) { // turn on 16 bit byte swapping png_set_swap(png_ptr); } #endif // set some additional flags switch(color_type) { case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_RGB_ALPHA: #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR // flip the RGB pixels to BGR (or RGBA to BGRA) if(image_type == FIT_BITMAP) { png_set_bgr(png_ptr); } #endif break; case PNG_COLOR_TYPE_PALETTE: // expand palette images to the full 8 bits from 2 bits/pixel if (pixel_depth == 2) { png_set_packing(png_ptr); pixel_depth = 8; } break; case PNG_COLOR_TYPE_GRAY: // expand grayscale images to the full 8 bits from 2 bits/pixel // but *do not* expand fully transparent palette entries to a full alpha channel if (pixel_depth == 2) { png_set_expand_gray_1_2_4_to_8(png_ptr); pixel_depth = 8; } break; case PNG_COLOR_TYPE_GRAY_ALPHA: // expand 8-bit greyscale + 8-bit alpha to 32-bit png_set_gray_to_rgb(png_ptr); #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR // flip the RGBA pixels to BGRA png_set_bgr(png_ptr); #endif pixel_depth = 32; break; default: throw FI_MSG_ERROR_UNSUPPORTED_FORMAT; } // unlike the example in the libpng documentation, we have *no* idea where // this file may have come from--so if it doesn't have a file gamma, don't // do any correction ("do no harm") if (png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) { double gamma = 0; double screen_gamma = 2.2; if (png_get_gAMA(png_ptr, info_ptr, &gamma) && ( flags & PNG_IGNOREGAMMA ) != PNG_IGNOREGAMMA) { png_set_gamma(png_ptr, screen_gamma, gamma); } } // all transformations have been registered; now update info_ptr data png_read_update_info(png_ptr, info_ptr); // color type may have changed, due to our transformations color_type = png_get_color_type(png_ptr,info_ptr); // create a DIB and write the bitmap header // set up the DIB palette, if needed switch (color_type) { case PNG_COLOR_TYPE_RGB: png_set_invert_alpha(png_ptr); if(image_type == FIT_BITMAP) { dib = FreeImage_AllocateHeader(header_only, width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); } else { dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth); } break; case PNG_COLOR_TYPE_RGB_ALPHA: if(image_type == FIT_BITMAP) { dib = FreeImage_AllocateHeader(header_only, width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); } else { dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth); } break; case PNG_COLOR_TYPE_PALETTE: dib = FreeImage_AllocateHeader(header_only, width, height, pixel_depth); png_get_PLTE(png_ptr,info_ptr, &png_palette, &palette_entries); palette_entries = MIN((unsigned)palette_entries, FreeImage_GetColorsUsed(dib)); palette = FreeImage_GetPalette(dib); // store the palette for (i = 0; i < palette_entries; i++) { palette[i].rgbRed = png_palette[i].red; palette[i].rgbGreen = png_palette[i].green; palette[i].rgbBlue = png_palette[i].blue; } break; case PNG_COLOR_TYPE_GRAY: dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth); if(pixel_depth <= 8) { palette = FreeImage_GetPalette(dib); palette_entries = 1 << pixel_depth; for (i = 0; i < palette_entries; i++) { palette[i].rgbRed = palette[i].rgbGreen = palette[i].rgbBlue = (BYTE)((i * 255) / (palette_entries - 1)); } } break; default: throw FI_MSG_ERROR_UNSUPPORTED_FORMAT; } // store the transparency table if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { // array of alpha (transparency) entries for palette png_bytep trans_alpha = NULL; // number of transparent entries int num_trans = 0; // graylevel or color sample values of the single transparent color for non-paletted images png_color_16p trans_color = NULL; png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color); if((color_type == PNG_COLOR_TYPE_GRAY) && trans_color) { // single transparent color if (trans_color->gray < palette_entries) { BYTE table[256]; memset(table, 0xFF, palette_entries); table[trans_color->gray] = 0; FreeImage_SetTransparencyTable(dib, table, palette_entries); } } else if((color_type == PNG_COLOR_TYPE_PALETTE) && trans_alpha) { // transparency table FreeImage_SetTransparencyTable(dib, (BYTE *)trans_alpha, num_trans); } } // store the background color if (png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) { // Get the background color to draw transparent and alpha images over. // Note that even if the PNG file supplies a background, you are not required to // use it - you should use the (solid) application background if it has one. png_color_16p image_background = NULL; RGBQUAD rgbBkColor; if (png_get_bKGD(png_ptr, info_ptr, &image_background)) { rgbBkColor.rgbRed = (BYTE)image_background->red; rgbBkColor.rgbGreen = (BYTE)image_background->green; rgbBkColor.rgbBlue = (BYTE)image_background->blue; rgbBkColor.rgbReserved = 0; FreeImage_SetBackgroundColor(dib, &rgbBkColor); } } // get physical resolution if (png_get_valid(png_ptr, info_ptr, PNG_INFO_pHYs)) { png_uint_32 res_x, res_y; // we'll overload this var and use 0 to mean no phys data, // since if it's not in meters we can't use it anyway int res_unit_type = PNG_RESOLUTION_UNKNOWN; png_get_pHYs(png_ptr,info_ptr, &res_x, &res_y, &res_unit_type); if (res_unit_type == PNG_RESOLUTION_METER) { FreeImage_SetDotsPerMeterX(dib, res_x); FreeImage_SetDotsPerMeterY(dib, res_y); } } // get possible ICC profile if (png_get_valid(png_ptr, info_ptr, PNG_INFO_iCCP)) { png_charp profile_name = NULL; png_bytep profile_data = NULL; png_uint_32 profile_length = 0; int compression_type; png_get_iCCP(png_ptr, info_ptr, &profile_name, &compression_type, &profile_data, &profile_length); // copy ICC profile data (must be done after FreeImage_AllocateHeader) FreeImage_CreateICCProfile(dib, profile_data, profile_length); } // --- header only mode => clean-up and return if (header_only) { // get possible metadata (it can be located both before and after the image data) ReadMetadata(png_ptr, info_ptr, dib); if (png_ptr) { // clean up after the read, and free any memory allocated - REQUIRED png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); } return dib; } // set the individual row_pointers to point at the correct offsets row_pointers = (png_bytepp)malloc(height * sizeof(png_bytep)); if (!row_pointers) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); FreeImage_Unload(dib); return NULL; } // read in the bitmap bits via the pointer table // allow loading of PNG with minor errors (such as images with several IDAT chunks) for (png_uint_32 k = 0; k < height; k++) { row_pointers[height - 1 - k] = FreeImage_GetScanLine(dib, k); } png_set_benign_errors(png_ptr, 1); png_read_image(png_ptr, row_pointers); // check if the bitmap contains transparency, if so enable it in the header if (FreeImage_GetBPP(dib) == 32) { if (FreeImage_GetColorType(dib) == FIC_RGBALPHA) { FreeImage_SetTransparent(dib, TRUE); } else { FreeImage_SetTransparent(dib, FALSE); } } // cleanup if (row_pointers) { free(row_pointers); row_pointers = NULL; } // read the rest of the file, getting any additional chunks in info_ptr png_read_end(png_ptr, info_ptr); // get possible metadata (it can be located both before and after the image data) ReadMetadata(png_ptr, info_ptr, dib); if (png_ptr) { // clean up after the read, and free any memory allocated - REQUIRED png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); } return dib; } catch (const char *text) { if (png_ptr) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); } if (row_pointers) { free(row_pointers); } if (dib) { FreeImage_Unload(dib); } FreeImage_OutputMessageProc(s_format_id, text); return NULL; } } return NULL; }
unsigned char* PPGame_DecodePNG(unsigned char* bytes,unsigned long size,unsigned long* imageWidth,unsigned long* imageHeight,unsigned long* bytesPerRow) { if (bytes == NULL || size == 0) return NULL; my_png_buffer png_buff; memset(&png_buff,0,sizeof(png_buff)); png_buff.data_len = size; png_buff.data = bytes; int is_png = png_check_sig((png_bytep)png_buff.data, 8); if (!is_png) { fprintf(stderr, "is not PNG!\n"); free(png_buff.data); return NULL; } png_structp PNG_reader = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,NULL,NULL); if (!PNG_reader) { fprintf(stderr, "can't create read_struct\n"); free(png_buff.data); return NULL; } png_infop PNG_info = png_create_info_struct(PNG_reader); if (!PNG_info) { fprintf(stderr, "can't create info_struct\n"); png_destroy_read_struct (&PNG_reader, NULL, NULL); free(png_buff.data); return NULL; } png_infop PNG_end_info = png_create_info_struct(PNG_reader); if (PNG_end_info == NULL) { fprintf(stderr, "Can't get end info for PNG data\n"); png_destroy_read_struct(&PNG_reader, &PNG_info, NULL); free(png_buff.data); return NULL; } if (setjmp(png_jmpbuf(PNG_reader))) { fprintf(stderr, "Can't decode PNG data\n"); png_destroy_read_struct(&PNG_reader, &PNG_info, &PNG_end_info); free(png_buff.data); return NULL; } png_data_read(PNG_reader,&png_buff); png_read_info(PNG_reader,PNG_info); png_uint_32 width, height; width = png_get_image_width(PNG_reader, PNG_info); height = png_get_image_height(PNG_reader, PNG_info); //printf("width %ld\n",width); //printf("height %ld\n",height); png_uint_32 bit_depth, color_type; bit_depth = png_get_bit_depth(PNG_reader, PNG_info); color_type = png_get_color_type(PNG_reader, PNG_info); //printf("bit_depth %ld\n",bit_depth); //printf("rowbytes %ld\n",png_get_rowbytes(PNG_reader, PNG_info)); if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(PNG_reader); } if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(PNG_reader); } if (png_get_valid(PNG_reader, PNG_info, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(PNG_reader); } else { png_set_filler(PNG_reader, 0xff, PNG_FILLER_AFTER); } if (bit_depth == 16) { png_set_strip_16(PNG_reader); } png_read_update_info(PNG_reader, PNG_info); png_byte* PNG_image_buffer = (png_byte*)malloc(4 * width * height); png_byte** PNG_rows = (png_byte**)malloc(height * sizeof(png_byte*)); unsigned int row; for (row = 0; row < height; ++row) { //PNG_rows[height - 1 - row] = PNG_image_buffer + (row * 4 * width); PNG_rows[row] = PNG_image_buffer + (row * 4 * width); } png_read_image(PNG_reader, PNG_rows); free(PNG_rows); png_destroy_read_struct(&PNG_reader, &PNG_info, &PNG_end_info); if (png_buff.data) free(png_buff.data); *imageWidth = width; *imageHeight = height; *bytesPerRow = width*4; return convert(PNG_image_buffer,width,height); }
int main(int argc, char **argv) { static char *usage="Usage:\n\t%s png__file\n"; int i; FILE *fp_in = NULL; png_structp png_p; png_infop info_p; char header[8]; int bit_depth; int color_type; png_color_16p input_backgrd; double gammaval; int file_width, file_height; png_int_32 xoff, yoff; png_uint_32 xres, yres; int unit_type; int rgb_intent; double white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y; png_timep mod_time; png_textp text; int num_text; unsigned char *image; unsigned char **rows; if (argc != 2) { bu_log(usage, argv[0]); bu_exit(EXIT_FAILURE, "Incorrect number of arguments!!\n"); } else { if ((fp_in = fopen(argv[1], "rb")) == NULL) { perror(argv[1]); bu_log("png_onfo: cannot open \"%s\" for reading\n", argv[1]); bu_exit(EXIT_FAILURE, "Cannot open input file\n"); } } if (fread(header, 8, 1, fp_in) != 1) bu_exit(EXIT_FAILURE, "ERROR: Failed while reading file header!!!\n"); if (png_sig_cmp((png_bytep)header, 0, 8)) bu_exit(EXIT_FAILURE, "This is not a PNG file!!!\n"); png_p = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_p) bu_exit(EXIT_FAILURE, "png_create_read_struct() failed!!\n"); info_p = png_create_info_struct(png_p); if (!info_p) bu_exit(EXIT_FAILURE, "png_create_info_struct() failed!!\n"); png_init_io(png_p, fp_in); png_set_sig_bytes(png_p, 8); png_read_info(png_p, info_p); color_type = png_get_color_type(png_p, info_p); bit_depth = png_get_bit_depth(png_p, info_p); switch (color_type) { case PNG_COLOR_TYPE_GRAY: bu_log("color type: b/w (bit depth=%d)\n", bit_depth); break; case PNG_COLOR_TYPE_GRAY_ALPHA: bu_log("color type: b/w with alpha channel (bit depth=%d)\n", bit_depth); break; case PNG_COLOR_TYPE_PALETTE: bu_log("color type: color palette (bit depth=%d)\n", bit_depth); break; case PNG_COLOR_TYPE_RGB: bu_log("color type: RGB (bit depth=%d)\n", bit_depth); break; case PNG_COLOR_TYPE_RGB_ALPHA: bu_log("color type: RGB with alpha channel (bit depth=%d)\n", bit_depth); break; default: bu_log("Unrecognized color type (bit depth=%d)\n", bit_depth); break; } file_width = png_get_image_width(png_p, info_p); file_height = png_get_image_height(png_p, info_p); bu_log("Image size: %d X %d\n", file_width, file_height); /* allocate memory for image */ image = (unsigned char *)bu_calloc(1, file_width*file_height*3, "image"); /* create rows array */ rows = (unsigned char **)bu_calloc(file_height, sizeof(unsigned char *), "rows"); for (i=0; i<file_height; i++) rows[file_height-1-i] = image+(i*file_width*3); png_read_image(png_p, rows); if (png_get_oFFs(png_p, info_p, &xoff, &yoff, &unit_type)) { if (unit_type == PNG_OFFSET_PIXEL) bu_log("X Offset: %d pixels\nY Offset: %d pixels\n", (int)xoff, (int)yoff); else if (unit_type == PNG_OFFSET_MICROMETER) bu_log("X Offset: %d um\nY Offset: %d um\n", (int)xoff, (int)yoff); } if (png_get_pHYs(png_p, info_p, &xres, &yres, &unit_type)) { if (unit_type == PNG_RESOLUTION_UNKNOWN) bu_log("Aspect ratio: %g (width/height)\n", (double)xres/(double)yres); else if (unit_type == PNG_RESOLUTION_METER) bu_log("pixel density:\n\t%d pixels/m horizontal\n\t%d pixels/m vertical\n", (int)xres, (int)yres); } if (png_get_interlace_type(png_p, info_p) == PNG_INTERLACE_NONE) bu_log("not interlaced\n"); else bu_log("interlaced\n"); if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA || color_type == PNG_COLOR_TYPE_RGB_ALPHA) if (png_get_bKGD(png_p, info_p, &input_backgrd)) bu_log("background color: %d %d %d\n", input_backgrd->red, input_backgrd->green, input_backgrd->blue); if (png_get_sRGB(png_p, info_p, &rgb_intent)) { bu_log("rendering intent: "); switch (rgb_intent) { case PNG_sRGB_INTENT_SATURATION: bu_log("saturation\n"); break; case PNG_sRGB_INTENT_PERCEPTUAL: bu_log("perceptual\n"); break; case PNG_sRGB_INTENT_ABSOLUTE: bu_log("absolute\n"); break; case PNG_sRGB_INTENT_RELATIVE: bu_log("relative\n"); break; } } if (png_get_gAMA(png_p, info_p, &gammaval)) bu_log("gamma: %g\n", gammaval); #if defined(PNG_READ_cHRM_SUPPORTED) if (png_get_cHRM(png_p, info_p, &white_x, &white_y, &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y)) { bu_log("Chromaticity:\n"); bu_log("\twhite point\t(%g %g)\n\tred\t(%g %g)\n\tgreen\t(%g %g)\n\tblue\t(%g %g)\n", white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y); } #endif if (png_get_text(png_p, info_p, &text, &num_text)) for (i=0; i<num_text; i++) bu_log("%s: %s\n", text[i].key, text[i].text); if (png_get_tIME(png_p, info_p, &mod_time)) bu_log("Last modified: %d/%d/%d %d:%d:%d\n", mod_time->month, mod_time->day, mod_time->year, mod_time->hour, mod_time->minute, mod_time->second); return 0; }
void input_png_file(struct Options opts, struct PNGImage *img) { FILE *f; int i, y, num_trans; bool has_palette = false; png_byte *trans_alpha; png_color_16 *trans_values; bool *full_alpha; png_color *palette; f = fopen(opts.infile, "rb"); if (!f) { err(1, "Opening input png file '%s' failed", opts.infile); } img->png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!img->png) { errx(1, "Creating png structure failed"); } img->info = png_create_info_struct(img->png); if (!img->info) { errx(1, "Creating png info structure failed"); } /* Better error handling here? */ if (setjmp(png_jmpbuf(img->png))) { exit(1); } png_init_io(img->png, f); png_read_info(img->png, img->info); img->width = png_get_image_width(img->png, img->info); img->height = png_get_image_height(img->png, img->info); img->depth = png_get_bit_depth(img->png, img->info); img->type = png_get_color_type(img->png, img->info); if (img->type & PNG_COLOR_MASK_ALPHA) { png_set_strip_alpha(img->png); } if (img->depth != depth) { if (opts.verbose) { warnx("Image bit depth is not %i (is %i).", depth, img->depth); } } if (img->type == PNG_COLOR_TYPE_GRAY) { if (img->depth < 8) { png_set_expand_gray_1_2_4_to_8(img->png); } png_set_gray_to_rgb(img->png); } else { if (img->depth < 8) { png_set_expand_gray_1_2_4_to_8(img->png); } has_palette = png_get_PLTE(img->png, img->info, &palette, &colors); } if (png_get_tRNS(img->png, img->info, &trans_alpha, &num_trans, &trans_values)) { if (img->type == PNG_COLOR_TYPE_PALETTE) { full_alpha = malloc(sizeof(bool) * num_trans); for (i = 0; i < num_trans; i++) { if (trans_alpha[i] > 0) { full_alpha[i] = false; } else { full_alpha[i] = true; } } for (i = 0; i < num_trans; i++) { if (full_alpha[i]) { palette[i].red = 0xFF; palette[i].green = 0x00; palette[i].blue = 0xFF; /* * Set to the lightest color in the * palette. */ } } free(full_alpha); } else { /* Set to the lightest color in the image. */ } png_free_data(img->png, img->info, PNG_FREE_TRNS, -1); } if (has_palette) { /* Make sure palette only has the amount of colors you want. */ } else { /* * Eventually when this copies colors from the image itself, * make sure order is lightest to darkest. */ palette = malloc(sizeof(png_color) * colors); if (strcmp(opts.infile, "rgb.png") == 0) { palette[0].red = 0xFF; palette[0].green = 0xEF; palette[0].blue = 0xFF; palette[1].red = 0xF7; palette[1].green = 0xF7; palette[1].blue = 0x8C; palette[2].red = 0x94; palette[2].green = 0x94; palette[2].blue = 0xC6; palette[3].red = 0x39; palette[3].green = 0x39; palette[3].blue = 0x84; } else { palette[0].red = 0xFF; palette[0].green = 0xFF; palette[0].blue = 0xFF; palette[1].red = 0xA9; palette[1].green = 0xA9; palette[1].blue = 0xA9; palette[2].red = 0x55; palette[2].green = 0x55; palette[2].blue = 0x55; palette[3].red = 0x00; palette[3].green = 0x00; palette[3].blue = 0x00; } } /* * Also unfortunately, this sets it at 8 bit, and I can't find any * option to reduce to 2 or 1 bit. */ #if PNG_LIBPNG_VER < 10402 png_set_dither(img->png, palette, colors, colors, NULL, 1); #else png_set_quantize(img->png, palette, colors, colors, NULL, 1); #endif if (!has_palette) { png_set_PLTE(img->png, img->info, palette, colors); free(palette); } /* * If other useless chunks exist (sRGB, bKGD, pHYs, gAMA, cHRM, iCCP, * etc.) offer to remove? */ png_read_update_info(img->png, img->info); img->data = malloc(sizeof(png_byte *) * img->height); for (y = 0; y < img->height; y++) { img->data[y] = malloc(png_get_rowbytes(img->png, img->info)); } png_read_image(img->png, img->data); png_read_end(img->png, img->info); fclose(f); }
// // validate our input // static void s_PngReadValidate(png_structp png_ptr, png_infop info_ptr, size_t& width, size_t& height, size_t& depth, size_t& x, size_t& y, size_t& w, size_t& h) { // store and validate our image's parameters width = png_get_image_width(png_ptr, info_ptr); height = png_get_image_height(png_ptr, info_ptr); depth = png_get_channels(png_ptr, info_ptr); png_byte color_type = png_get_color_type(png_ptr, info_ptr); png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr); // we support only RGB and RGBA images if ( color_type != PNG_COLOR_TYPE_RGB && color_type != PNG_COLOR_TYPE_RGB_ALPHA ) { string msg("CImageIOPng::ReadImage(): unhandled color type: "); msg += NStr::NumericToString((int)color_type); NCBI_THROW(CImageException, eReadError, msg); } // ...and only with a bit depth of 8 if (bit_depth != 8) { string msg("CImageIOPng::ReadImage(): unhandled bit depth: "); msg += NStr::NumericToString((int)bit_depth); NCBI_THROW(CImageException, eReadError, msg); } // this goes along with RGB or RGBA if (depth != 3 && depth != 4) { string msg("CImageIOPng::ReadImage(): unhandled image channels: "); msg += NStr::NumericToString((int)depth); NCBI_THROW(CImageException, eReadError, msg); } if (x != (size_t)-1 && y != (size_t)-1 && w != (size_t)-1 && h != (size_t)-1) { // further validation: make sure we're actually on the image if (x >= width || y >= height) { string msg("CImageIOPng::ReadImage(): invalid starting position: "); msg += NStr::NumericToString(x); msg += ", "; msg += NStr::NumericToString(y); NCBI_THROW(CImageException, eReadError, msg); } // clamp our width and height to the image size if (x + w >= width) { w = width - x; LOG_POST_X(27, Warning << "CImageIOPng::ReadImage(): clamped width to " << w); } if (y + h >= height) { h = height - y; LOG_POST_X(28, Warning << "CImageIOPng::ReadImage(): clamped height to " << h); } } png_read_update_info(png_ptr, info_ptr); }
bool DecodePNG ( Image& aImage, size_t aBufferSize, const void* aBuffer ) { if ( png_sig_cmp ( static_cast<uint8_t*> ( const_cast<void*> ( aBuffer ) ), 0, 8 ) != 0 ) { return false; } try { png_structp png_ptr = png_create_read_struct ( PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr ); if ( png_ptr == nullptr ) { throw std::runtime_error ( "png_create_read_struct failed." ); } png_infop info_ptr = png_create_info_struct ( png_ptr ); if ( info_ptr == nullptr ) { throw std::runtime_error ( "png_create_info_struct failed." ); } if ( setjmp ( png_jmpbuf ( png_ptr ) ) ) { throw std::runtime_error ( "Error during init_io." ); } png_read_memory_struct read_memory_struct = {static_cast<const uint8_t*> ( aBuffer ), static_cast<const uint8_t*> ( aBuffer ) + 8, static_cast<png_size_t> ( aBufferSize * sizeof ( uint8_t ) ) }; png_set_read_fn ( png_ptr, &read_memory_struct, png_read_memory_data ); png_set_sig_bytes ( png_ptr, 8 ); png_read_info ( png_ptr, info_ptr ); uint32_t width = png_get_image_width ( png_ptr, info_ptr ); uint32_t height = png_get_image_height ( png_ptr, info_ptr ); png_byte color_type = png_get_color_type ( png_ptr, info_ptr ); png_byte bit_depth = png_get_bit_depth ( png_ptr, info_ptr ); Image::ImageFormat format; Image::ImageType type; if ( ( color_type == PNG_COLOR_TYPE_RGB ) || ( color_type == PNG_COLOR_TYPE_RGBA ) ) { format = ( color_type == PNG_COLOR_TYPE_RGB ) ? Image::ImageFormat::RGB : Image::ImageFormat::RGBA; type = ( bit_depth == 8 ) ? Image::ImageType::UNSIGNED_BYTE : Image::ImageType::UNSIGNED_SHORT; } else { throw std::runtime_error ( "PNG image color type not supported...yet" ); } /*int 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 ) ) ) { throw std::runtime_error ( "Error during read_image." ); } // -------------------------------------- png_size_t rowbytes = png_get_rowbytes ( png_ptr, info_ptr ); std::vector<uint8_t*> row_pointers ( sizeof ( png_bytep ) * height ); std::vector<uint8_t> pixels ( width * height * GetPixelSize ( format, type ) ); for ( png_uint_32 y = 0; y < height; ++y ) { row_pointers[y] = pixels.data() + ( rowbytes * y ); } // -------------------------------------- png_read_image ( png_ptr, row_pointers.data() ); png_destroy_read_struct ( &png_ptr, &info_ptr, ( png_infopp ) nullptr ); aImage.Initialize ( width, height, format, type, pixels.data() ); } catch ( std::runtime_error& e ) { std::cout << e.what() << std::endl; return false; } return true; }
PyObject* _png_module::_read_png(const Py::Object& py_fileobj, const bool float_result, int result_bit_depth) { png_byte header[8]; // 8 is the maximum size that can be checked FILE* fp = NULL; bool close_file = false; bool close_dup_file = false; PyObject *py_file = NULL; if (py_fileobj.isString()) { if ((py_file = npy_PyFile_OpenFile(py_fileobj.ptr(), (char *)"rb")) == NULL) { throw Py::Exception(); } close_file = true; } else { py_file = py_fileobj.ptr(); } if ((fp = npy_PyFile_Dup(py_file, "rb"))) { close_dup_file = true; } else { PyErr_Clear(); PyObject* read_method = PyObject_GetAttrString(py_file, "read"); if (!(read_method && PyCallable_Check(read_method))) { Py_XDECREF(read_method); throw Py::TypeError( "Object does not appear to be a 8-bit string path or a Python " "file-like object"); } Py_XDECREF(read_method); } if (fp) { if (fread(header, 1, 8, fp) != 8) { throw Py::RuntimeError( "_image_module::readpng: error reading PNG header"); } } else { _read_png_data(py_file, header, 8); } if (png_sig_cmp(header, 0, 8)) { throw Py::RuntimeError( "_image_module::readpng: file not recognized as a PNG file"); } /* initialize stuff */ png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { throw Py::RuntimeError( "_image_module::readpng: png_create_read_struct failed"); } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { throw Py::RuntimeError( "_image_module::readpng: png_create_info_struct failed"); } if (setjmp(png_jmpbuf(png_ptr))) { throw Py::RuntimeError( "_image_module::readpng: error during init_io"); } if (fp) { png_init_io(png_ptr, fp); } else { png_set_read_fn(png_ptr, (void*)py_file, &read_png_data); } png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); png_uint_32 width = png_get_image_width(png_ptr, info_ptr); png_uint_32 height = png_get_image_height(png_ptr, info_ptr); int bit_depth = png_get_bit_depth(png_ptr, info_ptr); // Unpack 1, 2, and 4-bit images if (bit_depth < 8) png_set_packing(png_ptr); // If sig bits are set, shift data png_color_8p sig_bit; if ((png_get_color_type(png_ptr, info_ptr) != PNG_COLOR_TYPE_PALETTE) && png_get_sBIT(png_ptr, info_ptr, &sig_bit)) { png_set_shift(png_ptr, sig_bit); } // Convert big endian to little if (bit_depth == 16) { png_set_swap(png_ptr); } // Convert palletes to full RGB if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); bit_depth = 8; } // If there's an alpha channel convert gray to RGB if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); } png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); /* read file */ if (setjmp(png_jmpbuf(png_ptr))) { throw Py::RuntimeError( "_image_module::readpng: error during read_image"); } png_bytep *row_pointers = new png_bytep[height]; png_uint_32 row; for (row = 0; row < height; row++) { row_pointers[row] = new png_byte[png_get_rowbytes(png_ptr,info_ptr)]; } png_read_image(png_ptr, row_pointers); npy_intp dimensions[3]; dimensions[0] = height; //numrows dimensions[1] = width; //numcols if (png_get_color_type(png_ptr, info_ptr) & PNG_COLOR_MASK_ALPHA) { dimensions[2] = 4; //RGBA images } else if (png_get_color_type(png_ptr, info_ptr) & PNG_COLOR_MASK_COLOR) { dimensions[2] = 3; //RGB images } else { dimensions[2] = 1; //Greyscale images } //For gray, return an x by y array, not an x by y by 1 int num_dims = (png_get_color_type(png_ptr, info_ptr) & PNG_COLOR_MASK_COLOR) ? 3 : 2; PyArrayObject *A = NULL; if (float_result) { double max_value = (1 << bit_depth) - 1; A = (PyArrayObject *) PyArray_SimpleNew(num_dims, dimensions, NPY_FLOAT); if (A == NULL) { throw Py::MemoryError("Could not allocate image array"); } for (png_uint_32 y = 0; y < height; y++) { png_byte* row = row_pointers[y]; for (png_uint_32 x = 0; x < width; x++) { size_t offset = y * A->strides[0] + x * A->strides[1]; if (bit_depth == 16) { png_uint_16* ptr = &reinterpret_cast<png_uint_16*>(row)[x * dimensions[2]]; for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++) { *(float*)(A->data + offset + p*A->strides[2]) = (float)(ptr[p]) / max_value; } } else { png_byte* ptr = &(row[x * dimensions[2]]); for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++) { *(float*)(A->data + offset + p*A->strides[2]) = (float)(ptr[p]) / max_value; } } } } } else { if (result_bit_depth < 0) { result_bit_depth = bit_depth; } if (result_bit_depth == 8) { A = (PyArrayObject *) PyArray_SimpleNew(num_dims, dimensions, NPY_UBYTE); } else if (result_bit_depth == 16) { A = (PyArrayObject *) PyArray_SimpleNew(num_dims, dimensions, NPY_UINT16); } else { throw Py::RuntimeError( "_image_module::readpng: image has unknown bit depth"); } if (A == NULL) { throw Py::MemoryError("Could not allocate image array"); } for (png_uint_32 y = 0; y < height; y++) { png_byte* row = row_pointers[y]; for (png_uint_32 x = 0; x < width; x++) { size_t offset = y * A->strides[0] + x * A->strides[1]; if (bit_depth == 16) { png_uint_16* ptr = &reinterpret_cast<png_uint_16*>(row)[x * dimensions[2]]; if (result_bit_depth == 16) { for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++) { *(png_uint_16*)(A->data + offset + p*A->strides[2]) = ptr[p]; } } else { for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++) { *(png_byte*)(A->data + offset + p*A->strides[2]) = ptr[p] >> 8; } } } else { png_byte* ptr = &(row[x * dimensions[2]]); if (result_bit_depth == 16) { for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++) { *(png_uint_16*)(A->data + offset + p*A->strides[2]) = ptr[p]; } } else { for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++) { *(png_byte*)(A->data + offset + p*A->strides[2]) = ptr[p]; } } } } }
ImageData ReadPNG(char* fileName) { ImageData meta; meta.valid = false; // Step 0: Make sure we can open the input file FILE* inFile = fopen(fileName, "rb"); if (!inFile) { abort_("ReadPNG: Can't open %s for reading\n", fileName); } // Step 1: initialize the reader png_structp png = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png) { abort_("ReadPNG: png_create_read_struct() failed\n"); } png_infop info = png_create_info_struct(png); if (!info) { abort_("ReadPNG: png_create_info_struct() failed\n"); } if (setjmp(png_jmpbuf(png))) { abort_("ReadPNG: Error during initialization.\n"); } png_init_io(png, inFile); png_read_info(png, info); // Step 2: Collect image statistics int width = png_get_image_width(png, info); int height = png_get_image_height(png, info); png_byte color_type = png_get_color_type(png, info); png_byte bit_depth = png_get_bit_depth(png, info); // Make some adjustments if (bit_depth == 16) { png_set_strip_16(png); } if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png); } 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); // Step 3: Read the data if (setjmp(png_jmpbuf(png))) { abort_("ReadPNG: Error during image data reading.\n"); } png_bytep row_pointers[height]; // This method gives a discontiguous array of rows // Each row is later copied to the destination image, RGB only. // There should be a more streamlined method, but this method works for lena.png for (int y = 0; y < height; y++) { row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png, info)); if (!row_pointers[y]) { abort_("ReadPNG: Couldn't allocate row %d\n", y); } } // Now we can read the image int row_bytes = png_get_rowbytes(png, info); png_read_image(png, row_pointers); // Convert the image from discontiguous rows to contiguous rows, discarding alpha Pixel* image = (Pixel*)malloc(height * width * 3); if (!image) { abort_("ReadPNG: Couldn't allocate image (%d, %d)\n", height, row_bytes); } // Brute force copy, skip over ALPHA channel for (int row = 0; row < height; row++) { for (int pixel = 0; pixel < width; pixel++) { image[(row * width + pixel)] = *(Pixel*)(row_pointers[row] + pixel * 4); } // As we use them, delete the pointers to the image rows. free(row_pointers[row]); } meta.xDim = width; meta.yDim = height; meta.valid = true; meta.pixels = (Pixel*)image; // Step 4: Tidy up. fclose(inFile); // Done. return meta; }
/*! * pixReadStreamPng() * * Input: stream * Return: pix, or null on error * * Notes: * (1) If called from pixReadStream(), the stream is positioned * at the beginning of the file. * (2) To do sequential reads of png format images from a stream, * use pixReadStreamPng() */ PIX * pixReadStreamPng(FILE *fp) { l_uint8 rval, gval, bval; l_int32 i, j, k; l_int32 wpl, d, spp, cindex; l_uint32 png_transforms; l_uint32 *data, *line, *ppixel; int num_palette, num_text; png_byte bit_depth, color_type, channels; png_uint_32 w, h, rowbytes; png_uint_32 xres, yres; png_bytep rowptr; png_bytep *row_pointers; png_structp png_ptr; png_infop info_ptr, end_info; png_colorp palette; png_textp text_ptr; /* ptr to text_chunk */ PIX *pix; PIXCMAP *cmap; PROCNAME("pixReadStreamPng"); if (!fp) return (PIX *)ERROR_PTR("fp not defined", procName, NULL); pix = NULL; /* Allocate the 3 data structures */ if ((png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL)) == NULL) return (PIX *)ERROR_PTR("png_ptr not made", procName, NULL); if ((info_ptr = png_create_info_struct(png_ptr)) == NULL) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return (PIX *)ERROR_PTR("info_ptr not made", procName, NULL); } if ((end_info = png_create_info_struct(png_ptr)) == NULL) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return (PIX *)ERROR_PTR("end_info not made", procName, NULL); } /* Set up png setjmp error handling */ if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return (PIX *)ERROR_PTR("internal png error", procName, NULL); } png_init_io(png_ptr, fp); /* ---------------------------------------------------------- * * Set the transforms flags. Whatever happens here, * NEVER invert 1 bpp using PNG_TRANSFORM_INVERT_MONO. * ---------------------------------------------------------- */ /* To strip 16 --> 8 bit depth, use PNG_TRANSFORM_STRIP_16 */ if (var_PNG_STRIP_16_TO_8 == 1) /* our default */ png_transforms = PNG_TRANSFORM_STRIP_16; else png_transforms = PNG_TRANSFORM_IDENTITY; /* To remove alpha channel, use PNG_TRANSFORM_STRIP_ALPHA */ if (var_PNG_STRIP_ALPHA == 1) /* our default */ png_transforms |= PNG_TRANSFORM_STRIP_ALPHA; /* Read it */ png_read_png(png_ptr, info_ptr, png_transforms, NULL); row_pointers = png_get_rows(png_ptr, info_ptr); w = png_get_image_width(png_ptr, info_ptr); h = png_get_image_height(png_ptr, info_ptr); bit_depth = png_get_bit_depth(png_ptr, info_ptr); rowbytes = png_get_rowbytes(png_ptr, info_ptr); color_type = png_get_color_type(png_ptr, info_ptr); channels = png_get_channels(png_ptr, info_ptr); spp = channels; if (spp == 1) d = bit_depth; else if (spp == 2) { d = 2 * bit_depth; L_WARNING("there shouldn't be 2 spp!", procName); } else /* spp == 3 (rgb), spp == 4 (rgba) */ d = 4 * bit_depth; /* Remove if/when this is implemented for all bit_depths */ if (spp == 3 && bit_depth != 8) { fprintf(stderr, "Help: spp = 3 and depth = %d != 8\n!!", bit_depth); return (PIX *)ERROR_PTR("not implemented for this depth", procName, NULL); } if (color_type == PNG_COLOR_TYPE_PALETTE || color_type == PNG_COLOR_MASK_PALETTE) { /* generate a colormap */ png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); cmap = pixcmapCreate(d); /* spp == 1 */ for (cindex = 0; cindex < num_palette; cindex++) { rval = palette[cindex].red; gval = palette[cindex].green; bval = palette[cindex].blue; pixcmapAddColor(cmap, rval, gval, bval); } } else cmap = NULL; if ((pix = pixCreate(w, h, d)) == NULL) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return (PIX *)ERROR_PTR("pix not made", procName, NULL); } wpl = pixGetWpl(pix); data = pixGetData(pix); pixSetColormap(pix, cmap); if (spp == 1) { /* copy straight from buffer to pix */ for (i = 0; i < h; i++) { line = data + i * wpl; rowptr = row_pointers[i]; for (j = 0; j < rowbytes; j++) { SET_DATA_BYTE(line, j, rowptr[j]); } } } else { /* spp == 3 or spp == 4 */ for (i = 0; i < h; i++) { ppixel = data + i * wpl; rowptr = row_pointers[i]; for (j = k = 0; j < w; j++) { SET_DATA_BYTE(ppixel, COLOR_RED, rowptr[k++]); SET_DATA_BYTE(ppixel, COLOR_GREEN, rowptr[k++]); SET_DATA_BYTE(ppixel, COLOR_BLUE, rowptr[k++]); if (spp == 4) SET_DATA_BYTE(ppixel, L_ALPHA_CHANNEL, rowptr[k++]); ppixel++; } } } #if DEBUG if (cmap) { for (i = 0; i < 16; i++) { fprintf(stderr, "[%d] = %d\n", i, ((l_uint8 *)(cmap->array))[i]); } } #endif /* DEBUG */ /* If there is no colormap, PNG defines black = 0 and * white = 1 by default for binary monochrome. Therefore, * since we use the opposite definition, we must invert * the image in either of these cases: * (i) there is no colormap (default) * (ii) there is a colormap which defines black to * be 0 and white to be 1. * We cannot use the PNG_TRANSFORM_INVERT_MONO flag * because that flag (since version 1.0.9) inverts 8 bpp * grayscale as well, which we don't want to do. * (It also doesn't work if there is a colormap.) * If there is a colormap that defines black = 1 and * white = 0, we don't need to do anything. * * How do we check the polarity of the colormap? * The colormap determines the values of black and * white pixels in the following way: * if black = 1 (255), white = 0 * 255, 255, 255, 0, 0, 0, 0, 0, 0 * if black = 0, white = 1 (255) * 0, 0, 0, 0, 255, 255, 255, 0 * So we test the first byte to see if it is 0; * if so, invert the data. */ if (d == 1 && (!cmap || (cmap && ((l_uint8 *)(cmap->array))[0] == 0x0))) { /* fprintf(stderr, "Inverting binary data on png read\n"); */ pixInvert(pix, pix); } xres = png_get_x_pixels_per_meter(png_ptr, info_ptr); yres = png_get_y_pixels_per_meter(png_ptr, info_ptr); pixSetXRes(pix, (l_int32)((l_float32)xres / 39.37 + 0.5)); /* to ppi */ pixSetYRes(pix, (l_int32)((l_float32)yres / 39.37 + 0.5)); /* to ppi */ /* Get the text if there is any */ png_get_text(png_ptr, info_ptr, &text_ptr, &num_text); if (num_text && text_ptr) pixSetText(pix, text_ptr->text); png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return pix; }
void read_png(const char* filename, int* w, int* h, GLenum* format, char*& pixels) { if(!w || !h || !format || !filename) return; FILE* fptr = fopen(filename,"rb"); if(!fptr) { printf("READ PNG: Can't open file %s\n", filename); return; } // png structures png_structp png_ptr; png_infop info_ptr; png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if( !png_ptr ) return; info_ptr = png_create_info_struct( png_ptr ); if( !info_ptr ) return; png_init_io(png_ptr, fptr); png_read_png( png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING, NULL); int components = 0; switch( png_get_color_type(png_ptr,info_ptr)) { case PNG_COLOR_TYPE_GRAY: *format = GL_LUMINANCE; components = 1; break; case PNG_COLOR_TYPE_RGB: *format = GL_RGB; components = 3; break; case PNG_COLOR_TYPE_RGB_ALPHA: *format = GL_RGBA; components = 4; break; default: break; } if( !components ) { printf("Unsupported PNG color mode\n"); png_destroy_read_struct( &png_ptr, &info_ptr, NULL); fclose(fptr); return; } if( info_ptr->bit_depth != 8 ) { printf("Unsupported PNG bit depth\n"); png_destroy_read_struct( &png_ptr, &info_ptr, NULL); fclose(fptr); return; } // try to get rows png_bytep *b = png_get_rows( png_ptr, info_ptr ); if( !b) { printf("Can't get pixels from PNG\n"); png_destroy_read_struct( &png_ptr, &info_ptr, NULL); fclose(fptr); return; } *w = (int) png_get_image_width( png_ptr, info_ptr); *h = (int) png_get_image_height( png_ptr, info_ptr); pixels = new char[ (*w) * (*h) * components ]; memset( pixels, 0, (*w) * (*h) * components ); for( int y = 0; y < *h; ++y) for( int x = 0; x < *w; ++x) for( int c = 0; c < components; ++c) { pixels[ y * (*w) * components + x * components + c] = (char) b[y][x * components + c]; } png_destroy_read_struct( &png_ptr, &info_ptr, NULL); fclose(fptr); // done }
static void png(FILE *input, FILE *output, int width, int height) { int i, in_width, in_height, ret; png_structp rpng, wpng; png_infop rinfo, winfo; png_byte ctype; struct oil_libpng ol; unsigned char *outbuf; rpng = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (setjmp(png_jmpbuf(rpng))) { fprintf(stderr, "PNG Decoding Error.\n"); exit(1); } rinfo = png_create_info_struct(rpng); png_init_io(rpng, input); png_read_info(rpng, rinfo); png_set_packing(rpng); png_set_strip_16(rpng); png_set_expand(rpng); png_set_interlace_handling(rpng); png_read_update_info(rpng, rinfo); in_width = png_get_image_width(rpng, rinfo); in_height = png_get_image_height(rpng, rinfo); oil_fix_ratio(in_width, in_height, &width, &height); wpng = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); winfo = png_create_info_struct(wpng); png_init_io(wpng, output); ret = oil_libpng_init(&ol, rpng, rinfo, width, height); if (ret!=0) { fprintf(stderr, "Unable to allocate buffers.\n"); exit(1); } ctype = png_get_color_type(rpng, rinfo); png_set_IHDR(wpng, winfo, width, height, 8, ctype, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_write_info(wpng, winfo); outbuf = malloc(width * OIL_CMP(ol.os.cs)); if (!outbuf) { fprintf(stderr, "Unable to allocate buffers.\n"); exit(1); } for(i=0; i<height; i++) { oil_libpng_read_scanline(&ol, outbuf); png_write_row(wpng, outbuf); } png_write_end(wpng, winfo); png_destroy_write_struct(&wpng, &winfo); png_destroy_read_struct(&rpng, &rinfo, NULL); free(outbuf); oil_libpng_free(&ol); }
plMipmap* plPNG::IRead(hsStream* inStream) { plMipmap* newMipmap = NULL; png_structp png_ptr; png_infop info_ptr; png_infop end_info; try { // Check PNG Signature png_byte sig[PNGSIGSIZE]; inStream->Read8Bytes((char*) sig); if (!png_sig_cmp(sig, 0, PNGSIGSIZE)) { // Allocate required structs png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { throw false; } info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); throw false; } end_info = png_create_info_struct(png_ptr); if (!end_info) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); throw false; } // Assign delegate function for reading from hsStream png_set_read_fn(png_ptr, (png_voidp)inStream, pngReadDelegate); // Get PNG Header information png_set_sig_bytes(png_ptr, PNGSIGSIZE); png_read_info(png_ptr, info_ptr); png_uint_32 imgWidth = png_get_image_width(png_ptr, info_ptr); png_uint_32 imgHeight = png_get_image_height(png_ptr, info_ptr); png_uint_32 bitdepth = png_get_bit_depth(png_ptr, info_ptr); png_uint_32 channels = png_get_channels(png_ptr, info_ptr); png_uint_32 color_type = png_get_color_type(png_ptr, info_ptr); // Convert images to RGB color space switch (color_type) { case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb(png_ptr); channels = 3; break; case PNG_COLOR_TYPE_GRAY: if (bitdepth < 8) { png_set_expand_gray_1_2_4_to_8(png_ptr); } bitdepth = 8; break; } // Convert transparency (if needed) to a full alpha channel if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); channels += 1; } else if (channels == 3) { // Add an opaque alpha channel if still none exists png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); channels = 4; } // Invert color byte-order as used by plMipmap for DirectX png_set_bgr(png_ptr); /// Construct a new mipmap to hold everything newMipmap = new plMipmap(imgWidth, imgHeight, plMipmap::kARGB32Config, 1, plMipmap::kUncompressed); char* destp = (char*)newMipmap->GetImage(); png_bytep* row_ptrs = new png_bytep[imgHeight]; const unsigned int stride = imgWidth * bitdepth * channels / 8; // Assign row pointers to the appropriate locations in the newly-created Mipmap for (size_t i = 0; i < imgHeight; i++) { row_ptrs[i] = (png_bytep)destp + (i * stride); } png_read_image(png_ptr, row_ptrs); png_read_end(png_ptr, end_info); // Clean up allocated structs png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); delete [] row_ptrs; } } catch (...) { delete newMipmap; newMipmap = nullptr; } return newMipmap; }
int main(int argc, char *argv[]) { unsigned char header[8]; if ( argc != 3 ) { printf( "usage: %s filename gamma_value", argv[0] ); } FILE *fp = fopen(argv[1],"rb"); float gamma ; sscanf(argv[2], "%f", &gamma); if(!fp) printf("not a file"); fread(header, 1, 8, fp); int is_png = !png_sig_cmp(header, 0, 8); //Quite weird. cmp return 0 if bytes match PNG signature if(!is_png) printf("not a png"); else printf("input file confirmed as png\n"); //Creating png_structp png_structp png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, //(png_voidp)user_error_ptr, NULL, //user_error_fn, NULL); //user_warning_fn); if(!png_ptr) printf("png_ptr construct error\n"); //Creating png_infop png_infop info_ptr = png_create_info_struct(png_ptr); if(!info_ptr) { png_destroy_read_struct(&png_ptr,(png_infopp) NULL,(png_infopp) NULL); printf("something wrong with pngInfo\n"); } //setjmp for error condition from libpng if(setjmp(png_jmpbuf(png_ptr))) printf("something wrong with jmp setting\n"); //eventually, we are reading the file :-) png_init_io(png_ptr, fp); //since we've sampled 8 byes for testing if it is png, we need to let libpng know png_set_sig_bytes(png_ptr, 8); //There're bunch of error handling from the manual... we skip as usual /* //High-level of reading interface, we'll read into memory directly png_read_png(png_ptr, info_ptr, 0, NULL); //third para as png_transforms bitwise OR mask png_bytep *row_pointers = png_get_rows(png_ptr, info_ptr); */ /* low level of reading, we need it to manipulate more detailed stuff*/ png_read_info(png_ptr, info_ptr); int width = png_get_image_width(png_ptr, info_ptr); int height = png_get_image_height(png_ptr, info_ptr); png_byte color_type = png_get_color_type(png_ptr, info_ptr); png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr); png_bytep *row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height); int x, y,k; k = (int)((log(bit_depth)/log(2))); printf("%d\n", k); for (y = 0; y < height; y++) row_pointers[y] = (png_bytep) malloc(width*k); png_read_image(png_ptr, row_pointers); printf("color_type:%d\nbit_depth: %d\n",color_type, bit_depth); //processing image for (y = 0; y< height; y++) { png_byte* row = row_pointers[y]; for(x = 0; x < width; x ++) { png_byte* ptr = &(row[x*k]); //ptr[0] = 255 - ptr[0]; //shouldn't invert alpha :) //ptr[0] = (int)(pow(ptr[0], 0.9)) ; ptr[1] = (int)(255 * pow((ptr[1]/255.0), gamma)) ; ptr[2] = (int)(255 * pow((ptr[2]/255.0), gamma)) ; ptr[3] = (int)(255 * pow((ptr[3]/255.0), gamma)) ; } } //output FILE *outfp = fopen("gammaout.png", "wb"); png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL); info_ptr = png_create_info_struct(png_ptr); png_init_io(png_ptr, outfp); png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_write_info(png_ptr, info_ptr); png_write_image(png_ptr, row_pointers); png_write_end(png_ptr, NULL); free(row_pointers); fclose(fp); }
bool CGLCG::loadPngImage(const TCHAR *name, int &outWidth, int &outHeight, bool &outHasAlpha, GLubyte **outData) { png_structp png_ptr; png_infop info_ptr; unsigned int sig_read = 0; int color_type, interlace_type; FILE *fp; if ((fp = _tfopen(name, TEXT("rb"))) == NULL) return false; /* Create and initialize the png_struct * with the desired error handler * functions. If you want to use the * default stderr and longjump method, * you can supply NULL for the last * three parameters. We also supply the * the compiler header file version, so * that we know if the application * was compiled with a compatible version * of the library. REQUIRED */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { fclose(fp); return false; } /* Allocate/initialize the memory * for image information. REQUIRED. */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { fclose(fp); png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return false; } /* Set error handling if you are * using the setjmp/longjmp method * (this is the normal method of * doing things with libpng). * REQUIRED unless you set up * your own error handlers in * the png_create_read_struct() * earlier. */ if (setjmp(png_jmpbuf(png_ptr))) { /* Free all of the memory associated * with the png_ptr and info_ptr */ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fp); /* If we get here, we had a * problem reading the file */ return false; } /* Set up the output control if * you are using standard C streams */ png_init_io(png_ptr, fp); /* If we have already * read some of the signature */ png_set_sig_bytes(png_ptr, sig_read); /* * If you have enough memory to read * in the entire image at once, and * you need to specify only * transforms that can be controlled * with one of the PNG_TRANSFORM_* * bits (this presently excludes * dithering, filling, setting * background, and doing gamma * adjustment), then you can read the * entire image (including pixels) * into the info structure with this * call * * PNG_TRANSFORM_STRIP_16 | * PNG_TRANSFORM_PACKING forces 8 bit * PNG_TRANSFORM_EXPAND forces to * expand a palette into RGB */ png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND, (png_voidp)NULL); outWidth = png_get_image_width(png_ptr, info_ptr); outHeight = png_get_image_height(png_ptr, info_ptr); switch (png_get_color_type(png_ptr, info_ptr)) { case PNG_COLOR_TYPE_RGBA: outHasAlpha = true; break; case PNG_COLOR_TYPE_RGB: outHasAlpha = false; break; default: png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); return false; } unsigned int row_bytes = png_get_rowbytes(png_ptr, info_ptr); *outData = (unsigned char*) malloc(row_bytes * outHeight); png_bytepp row_pointers = png_get_rows(png_ptr, info_ptr); for (int i = 0; i < outHeight; i++) { memcpy(*outData+(row_bytes * i), row_pointers[i], row_bytes); } /* Clean up after the read, * and free any memory allocated */ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); /* Close the file */ fclose(fp); /* That's it */ return true; }
s32 pngDecOpen(ppu_thread& ppu, PHandle handle, PPStream png_stream, PSrc source, POpenInfo open_info, PCbControlStream control_stream = vm::null, POpenParam open_param = vm::null) { // Check if partial image decoding is used if (control_stream || open_param) { fmt::throw_exception("Partial image decoding is not supported." HERE); } // Allocate memory for the stream structure auto stream = vm::ptr<PngStream>::make(handle->malloc(ppu, sizeof(PngStream), handle->malloc_arg).addr()); // Check if the allocation of memory for the stream structure failed if (!stream) { cellPngDec.error("PNG stream creation failed."); return CELL_PNGDEC_ERROR_FATAL; } // Set memory info open_info->initSpaceAllocated = sizeof(PngStream); // Set the stream source to the source give by the game stream->source = *source; // Indicate that a fixed alpha value isn't used, if not specified otherwise stream->fixed_alpha = false; // Use virtual memory address as a handle *png_stream = stream; // Allocate memory for the PNG buffer for decoding auto buffer = vm::ptr<PngBuffer>::make(handle->malloc(ppu, sizeof(PngBuffer), handle->malloc_arg).addr()); // Check for if the buffer structure allocation failed if (!buffer) { fmt::throw_exception("Memory allocation for the PNG buffer structure failed." HERE); } // We might not be reading from a file stream buffer->file = false; // Set the buffer pointer in the stream structure, so we can later deallocate it stream->buffer = buffer; // Open the buffer/file and check the header u8 header[8]; // Need to test it somewhere if (stream->source.fileOffset != 0) { fmt::throw_exception("Non-0 file offset not supported." HERE); } // Depending on the source type, get the first 8 bytes if (source->srcSelect == CELL_PNGDEC_FILE) { // Open a file stream fs::file file_stream(vfs::get(stream->source.fileName.get_ptr())); // Check if opening of the PNG file failed if (!file_stream) { cellPngDec.error("Opening of PNG failed. (%s)", stream->source.fileName.get_ptr()); return CELL_PNGDEC_ERROR_OPEN_FILE; } // Read the header if (file_stream.read(header, 8) != 8) { cellPngDec.error("PNG header is too small."); return CELL_PNGDEC_ERROR_HEADER; } // Get the file descriptor buffer->fd = idm::make<lv2_file>(stream->source.fileName.get_ptr(), std::move(file_stream), 0, 0); // Indicate that we need to read from a file stream buffer->file = true; } else { // We can simply copy the first 8 bytes memcpy(header, stream->source.streamPtr.get_ptr(), 8); } // Check if the header indicates a valid PNG file if (png_sig_cmp(header, 0, 8)) { cellPngDec.error("PNG signature is invalid."); return CELL_PNGDEC_ERROR_HEADER; } // Create a libpng structure, also pass our custom error/warning functions stream->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, pngDecError, pngDecWarning); // Check if the creation of the structure failed if (!stream->png_ptr) { cellPngDec.error("Creation of png_structp failed."); return CELL_PNGDEC_ERROR_FATAL; } // Create a libpng info structure stream->info_ptr = png_create_info_struct(stream->png_ptr); // Check if the creation of the structure failed if (!stream->info_ptr) { fmt::throw_exception("Creation of png_infop failed." HERE); } // Set a point to return to when an error occurs in libpng if (setjmp(png_jmpbuf(stream->png_ptr))) { fmt::throw_exception("Fatal error in libpng." HERE); } // We must indicate, that we allocated more memory open_info->initSpaceAllocated += sizeof(PngBuffer); // Init the IO for either reading from a file or a buffer if (source->srcSelect == CELL_PNGDEC_BUFFER) { // Set the data pointer and the file size buffer->length = stream->source.fileSize; buffer->data = stream->source.streamPtr; // Since we already read the header, we start reading from position 8 buffer->cursor = 8; } // Set the custom read function for decoding png_set_read_fn(stream->png_ptr, buffer.get_ptr(), pngDecReadBuffer); // We need to tell libpng, that we already read 8 bytes png_set_sig_bytes(stream->png_ptr, 8); // Read the basic info of the PNG file png_read_info(stream->png_ptr, stream->info_ptr); // Read the header info for future use 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); return CELL_OK; }
int VFrame::read_png(const unsigned char *data, long img_sz) { // Test for RAW format if(data[0] == 'R' && data[1] == 'A' && data[2] == 'W' && data[3] == ' ') { int new_color_model = BC_RGBA8888; w = data[4] | (data[5] << 8) | (data[6] << 16) | (data[7] << 24); h = data[8] | (data[9] << 8) | (data[10] << 16) | (data[11] << 24); int components = data[12]; new_color_model = components == 3 ? BC_RGB888 : BC_RGBA8888; // This shares the data directly // reallocate(data + 20, 0, 0, 0, w, h, new_color_model, -1); // Can't use shared data for theme since button constructions overlay the // images directly. reallocate(NULL, -1, 0, 0, 0, w, h, new_color_model, -1); memcpy(get_data(), data + 16, w * h * components); } else if(data[0] == 0x89 && data[1] == 'P' && data[2] == 'N' && data[3] == 'G') { int have_alpha = 0; png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); png_infop info_ptr = png_create_info_struct(png_ptr); int new_color_model; image_offset = 0; image = data; image_size = img_sz; png_set_read_fn(png_ptr, this, PngReadFunction::png_read_function); png_read_info(png_ptr, info_ptr); w = png_get_image_width(png_ptr, info_ptr); h = png_get_image_height(png_ptr, info_ptr); int src_color_model = png_get_color_type(png_ptr, info_ptr); /* tell libpng to strip 16 bit/color files down to 8 bits/color */ png_set_strip_16(png_ptr); /* extract multiple pixels with bit depths of 1, 2, and 4 from a single * byte into separate bytes (useful for paletted and grayscale images). */ png_set_packing(png_ptr); /* expand paletted colors into true RGB triplets */ if (src_color_model == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr); /* expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ if (src_color_model == PNG_COLOR_TYPE_GRAY && png_get_bit_depth(png_ptr, info_ptr) < 8) png_set_expand(png_ptr); if (src_color_model == PNG_COLOR_TYPE_GRAY || src_color_model == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); /* expand paletted or RGB images with transparency to full alpha channels * so the data will be available as RGBA quartets */ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)){ have_alpha = 1; png_set_expand(png_ptr); } switch(src_color_model) { case PNG_COLOR_TYPE_GRAY: case PNG_COLOR_TYPE_RGB: new_color_model = BC_RGB888; break; case PNG_COLOR_TYPE_GRAY_ALPHA: case PNG_COLOR_TYPE_RGB_ALPHA: default: new_color_model = BC_RGBA8888; break; case PNG_COLOR_TYPE_PALETTE: if(have_alpha) new_color_model = BC_RGBA8888; else new_color_model = BC_RGB888; } reallocate(NULL, -1, 0, 0, 0, w, h, new_color_model, -1); //printf("VFrame::read_png %d %d %d %p\n", __LINE__, w, h, get_rows()); png_read_image(png_ptr, get_rows()); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); } else { printf("VFrame::read_png %d: unknown file format" " 0x%02x 0x%02x 0x%02x 0x%02x\n", __LINE__, data[4], data[5], data[6], data[7]); } return 0; }