void set_user_transform_info(void* info, int bit_depth, int channels) { TRACE_IO_TRANSFORM("png_set_user_transform_info: bit_depth=%d," " channels=%d\n", bit_depth, channels); png_set_user_transform_info(m_png, info, bit_depth, channels); }
HGLOBAL CPng::PNGToDIB(png_structp png_ptr, png_infop info_ptr) { //Read the image png_read_info(png_ptr, info_ptr); int nBitDepth = 0; int nColorType = 0; png_uint_32 width = 0; png_uint_32 height = 0; png_get_IHDR(png_ptr, info_ptr, &width, &height, &nBitDepth, &nColorType, NULL, NULL, NULL); IMAGE img; img.width = (LONG)width; img.height = (LONG)height; //Determine the type of format if (nColorType==PNG_COLOR_TYPE_RGB || nColorType==PNG_COLOR_TYPE_RGB_ALPHA) { img.pixdepth = 24; // nBitDepth 8, 16 img.palnum = 0; } else { switch(nBitDepth) // bit depths 1, 2, 4, 8, 16 { case 2: img.pixdepth = 4; break; case 16: img.pixdepth = 8; break; default: img.pixdepth = nBitDepth; } img.palnum = 1 << img.pixdepth; } //Allocate the image struct that will be used to transport file info if (!AllocImageStruct(&img)) { longjmp(png_ptr->jmpbuf, 1); } //Not sure if we can take advantage of this info in a BMP, thus remove it. if (nColorType & PNG_COLOR_MASK_ALPHA) png_set_strip_alpha(png_ptr); //Set user transform function to deal with a Bitdepth of 2 if (nBitDepth == 2) { png_set_user_transform_info(png_ptr, NULL, 4, 1); png_set_read_user_transform_fn(png_ptr, ConvertTo4BitsPerPix); } //Tell libpng to strip 16 bit/color files down to 8 bits/color if (nBitDepth == 16) png_set_strip_16(png_ptr); if (nColorType==PNG_COLOR_TYPE_RGB || nColorType==PNG_COLOR_TYPE_RGB_ALPHA) { png_set_bgr(png_ptr); } png_read_update_info(png_ptr, info_ptr); //If palette, get it and fill our img struct if (img.palnum > 0) { if (nColorType == PNG_COLOR_TYPE_PALETTE) { png_colorp palette; int num_palette; png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); if (num_palette > (int)img.palnum) num_palette = img.palnum; memset(img.palette, 0, img.palnum * sizeof(png_color)); memcpy(img.palette, palette, num_palette * sizeof(png_color)); } else { int depth = (nBitDepth == 16)? 8 : nBitDepth ; png_build_grayscale_palette(depth, img.palette); } } png_read_image(png_ptr, img.rowptr); png_infop end_info = NULL; png_read_end(png_ptr, end_info); // Alloc the buffer to be big enough to hold all the bits DWORD dwLen = (DWORD)sizeof(BITMAPINFOHEADER) + (img.palnum * sizeof(RGBQUAD)) + img.imgbytes; // Allocate enough memory to hold the entire DIB HGLOBAL hMemory = ::GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, dwLen); if (!hMemory) return NULL; //Begin filling out DIB info BITMAPINFOHEADER* pDib = (BITMAPINFOHEADER*)::GlobalLock(hMemory); if (!pDib) { ::GlobalFree(hMemory); return NULL; } ::ZeroMemory(pDib, dwLen); pDib->biSize = sizeof(BITMAPINFOHEADER); pDib->biWidth = (DWORD)img.width; pDib->biHeight = (DWORD)img.height; pDib->biPlanes = 1; pDib->biCompression = BI_RGB; pDib->biXPelsPerMeter = 3937; // 100 pixels/inch pDib->biYPelsPerMeter = 3937; pDib->biSizeImage = img.imgbytes; pDib->biBitCount = img.pixdepth; pDib->biClrUsed = img.palnum; if (pDib->biBitCount >= 16) pDib->biBitCount = 24; if (pDib->biClrUsed) { RGBQUAD* pRgb = DibColors(pDib); BYTE rgbq[RGBQUAD_SIZE]; PALETTE* pal; UINT nIndex; memset(rgbq, 0, sizeof(rgbq)); for (pal = img.palette, nIndex = img.palnum ; nIndex > 0 ; nIndex--, pal++) { rgbq[RGBQ_RED] = pal->red; rgbq[RGBQ_GREEN] = pal->green; rgbq[RGBQ_BLUE] = pal->blue; rgbq[RGBQ_RESERVED] = 0; memcpy((LPVOID)pRgb, rgbq, sizeof(RGBQUAD)); pRgb++; } } memcpy(DibPtr(pDib), img.bmpbits, DibSizeImage(pDib)); FreeImageStruct(&img); ::GlobalUnlock(hMemory); return hMemory; }
static uint8_t png_write( png_structp writePtr, png_image * image, uint32_t flags ) { const uint32_t h = image->height; const uint32_t w = image->width; const uint8_t * p = image->data; const uint32_t bitDepth = 8; const uint32_t channels = 4; png_infop infoPtr = png_create_info_struct( writePtr ); if (!infoPtr) { pngio_error( "Couldn't initialize PNG info struct" ); png_destroy_write_struct( & writePtr, NULL ); return 0; } if (setjmp( png_jmpbuf( writePtr ) )) { png_destroy_write_struct( & writePtr, & infoPtr ); pngio_error( "An error occured while writing the PNG file." ); return 0; } png_set_filter( writePtr, 0, PNG_FILTER_NONE ); #ifdef PNG_APPLE_MODE_SUPPORTED if (png_get_apple_mode()) { png_write_sig( writePtr ); png_set_sig_bytes( writePtr, 8 ); png_set_compression_window_bits( writePtr, -15 ); png_set_write_user_transform_fn( writePtr, png_write_swap_and_premultiply_transform ); png_set_user_transform_info( writePtr, NULL, bitDepth, channels ); } #endif png_set_IHDR( writePtr, infoPtr, w, h, bitDepth, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); png_set_gAMA( writePtr, infoPtr, 0.45455 ); png_set_cHRM( writePtr, infoPtr, 0.312700, 0.329, 0.64, 0.33, 0.3, 0.6, 0.15, 0.06 ); png_set_sRGB( writePtr, infoPtr, 0); #ifdef PNG_APPLE_MODE_SUPPORTED if (png_get_apple_mode()) { png_byte cname[] = { 'C', 'g', 'B', 'I', '\0' }; png_byte cdata[] = { 0x50, 0x00, 0x20, 0x02 }; png_write_chunk( writePtr, cname, cdata, 4 ); } #endif png_write_info( writePtr, infoPtr ); const size_t bytesPerRow = w * 4; if (flags & PNG_IMAGE_FLIP_VERTICAL) { for (size_t i = 0; i < h; i++) { png_write_row( writePtr, p + (bytesPerRow * (h - i - 1)) ); } } else { for (size_t i = 0; i < h; i++) { png_write_row( writePtr, p + (bytesPerRow * i) ); } } png_write_end( writePtr, infoPtr ); png_destroy_write_struct( & writePtr, & infoPtr ); return 1; }
static uint8_t png_read( png_structp readPtr, png_image * image, uint32_t flags ) { // png_set_error_fn( readPtr, NULL, png_user_error, NULL ); png_infop infoPtr = png_create_info_struct( readPtr ); if (!infoPtr) { pngio_error( "Couldn't initialize PNG info struct." ); png_destroy_read_struct( & readPtr, NULL, NULL ); return 0; } if (setjmp( png_jmpbuf( readPtr ) )) { pngio_error( "An error occured while reading the PNG file." ); png_destroy_read_struct( & readPtr, & infoPtr, NULL ); png_image_free( image ); return 0; } png_set_sig_bytes( readPtr, 8 ); #ifdef PNG_APPLE_MODE_SUPPORTED if (png_get_apple_mode()) { png_set_keep_unknown_chunks( readPtr, PNG_HANDLE_CHUNK_ALWAYS, NULL, 0 ); png_set_read_user_chunk_fn( readPtr, NULL, png_read_user_chunk ); } #endif png_read_info( readPtr, infoPtr ); png_uint_32 w = png_get_image_width( readPtr, infoPtr ); png_uint_32 h = png_get_image_height( readPtr, infoPtr ); png_uint_32 bitDepth = png_get_bit_depth( readPtr, infoPtr ); png_uint_32 channels = png_get_channels( readPtr, infoPtr ); png_uint_32 interlaceType = png_get_interlace_type( readPtr, infoPtr ); png_uint_32 colorType = png_get_color_type( readPtr, infoPtr ); switch (colorType) { case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb( readPtr ); channels = 3; break; case PNG_COLOR_TYPE_GRAY: if (bitDepth < 8) { png_set_expand_gray_1_2_4_to_8( readPtr ); bitDepth = 8; } png_set_gray_to_rgb( readPtr ); break; } if (png_get_valid( readPtr, infoPtr, PNG_INFO_tRNS )) { png_set_tRNS_to_alpha( readPtr ); channels += 1; } else if (!(colorType & PNG_COLOR_MASK_ALPHA)) { png_set_add_alpha( readPtr, 0xff, PNG_FILLER_AFTER ); } if (bitDepth == 16) { png_set_strip_16( readPtr ); } #ifdef PNG_APPLE_MODE_SUPPORTED if (png_get_apple_mode()) { if (flags & PNG_IMAGE_PREMULTIPLY_ALPHA) { png_set_read_user_transform_fn( readPtr, png_read_swap_transform ); } else { png_set_read_user_transform_fn( readPtr, png_read_swap_and_unpremultiply_transform ); } png_set_user_transform_info( readPtr, NULL, bitDepth, channels ); png_read_update_info( readPtr, infoPtr ); } else #endif { if (flags & PNG_IMAGE_PREMULTIPLY_ALPHA) { png_set_read_user_transform_fn( readPtr, png_read_premultiply_transform ); } } png_image_alloc( image, w, h ); png_bytep p = image->data; const size_t passCount = interlaceType == PNG_INTERLACE_NONE ? 1 : png_set_interlace_handling( readPtr ); const size_t bytesPerRow = w * 4; if (flags & PNG_IMAGE_FLIP_VERTICAL) { for (size_t pass = 0; pass < passCount; pass++) { for (size_t i = 0; i < h; i++) { png_read_row( readPtr, p + (bytesPerRow * (h - i - 1)), NULL ); } } } else { // png_bytep rp[h]; // for (size_t i = 0; i < h; i++) // { // rp[i] = p + (bytesPerRow * i); // } // png_read_image( readPtr, rp ); for (size_t pass = 0; pass < passCount; pass++) { for (size_t i = 0; i < h; i++) { png_read_row( readPtr, p + (bytesPerRow * i), NULL ); } } } png_destroy_read_struct( & readPtr, & infoPtr, NULL ); return 1; }