FloatPixMapRef FPMCreateWithPNGCustom(png_voidp ioPtr, png_rw_ptr readDataFn, FPMGammaFactor desiredGamma, FPMPNGErrorHandler errorHandler) { png_structp png = NULL; png_infop pngInfo = NULL; png_infop pngEndInfo = NULL; FloatPixMapRef result = NULL; png_uint_32 i, width, height, rowBytes; int depth, colorType; png_bytepp rows = NULL; void *data = NULL; png = png_create_read_struct(PNG_LIBPNG_VER_STRING, errorHandler, PNGError, PNGWarning); if (png == NULL) goto FAIL; pngInfo = png_create_info_struct(png); if (pngInfo == NULL) goto FAIL; pngEndInfo = png_create_info_struct(png); if (pngEndInfo == NULL) goto FAIL; if (setjmp(png_jmpbuf(png))) { // libpng will jump here on error. goto FAIL; } png_set_read_fn(png, ioPtr, readDataFn); png_read_info(png, pngInfo); if (!png_get_IHDR(png, pngInfo, &width, &height, &depth, &colorType, NULL, NULL, NULL)) goto FAIL; #if __LITTLE_ENDIAN__ if (depth == 16) png_set_swap(png); #endif if (depth <= 8 && !(colorType & PNG_COLOR_MASK_ALPHA)) { png_set_filler(png, 0xFF, PNG_FILLER_AFTER); } png_set_gray_to_rgb(png); if (depth < 8) { png_set_packing(png); png_set_expand(png); } png_read_update_info(png, pngInfo); rowBytes = png_get_rowbytes(png, pngInfo); rows = malloc(sizeof *rows * height); data = malloc(rowBytes * height); if (rows == NULL || data == NULL) goto FAIL; // Set up row pointers. for (i = 0; i < height; i++) { rows[i] = (png_bytep)data + i * rowBytes; } png_read_image(png, rows); png_read_end(png, pngEndInfo); free(rows); result = ConvertPNGData(data, width, height, rowBytes, png_get_bit_depth(png, pngInfo), png_get_color_type(png, pngInfo)); if (result != NULL) { double invGamma = 1.0/kFPMGammaSRGB; png_get_gAMA(png, pngInfo, &invGamma); FPMApplyGamma(result, 1.0/invGamma, desiredGamma, png_get_bit_depth(png, pngInfo) == 16 ? 65536 : 256); } png_destroy_read_struct(&png, &pngInfo, &pngEndInfo); free(data); return result; FAIL: FPMRelease(&result); if (png != NULL) png_destroy_read_struct(&png, &pngInfo, &pngEndInfo); free(rows); free(data); return NULL; }
FloatPixMapRef FPMCreateWithPNGCustom(png_voidp ioPtr, png_rw_ptr readDataFn, FPMGammaFactor desiredGamma, FPMPNGErrorHandler errorHandler, FPMPNGProgressHandler progressHandler, void *callbackContext) { png_structp png = NULL; png_infop pngInfo = NULL; png_infop pngEndInfo = NULL; FloatPixMapRef result = NULL; png_uint_32 i, width, height, rowBytes; int depth, colorType; void *data = NULL; ErrorInfo errInfo = { errorHandler, callbackContext }; png = png_create_read_struct(PNG_LIBPNG_VER_STRING, &errInfo, PNGError, PNGWarning); if (png == NULL) goto FAIL; pngInfo = png_create_info_struct(png); if (pngInfo == NULL) goto FAIL; pngEndInfo = png_create_info_struct(png); if (pngEndInfo == NULL) goto FAIL; if (setjmp(png_jmpbuf(png))) { // libpng will jump here on error. goto FAIL; } png_set_read_fn(png, ioPtr, readDataFn); png_read_info(png, pngInfo); if (!png_get_IHDR(png, pngInfo, &width, &height, &depth, &colorType, NULL, NULL, NULL)) goto FAIL; #if FPM_LITTLE_ENDIAN if (depth == 16) png_set_swap(png); #endif if (depth <= 8 && !(colorType & PNG_COLOR_MASK_ALPHA)) { png_set_filler(png, 0xFF, PNG_FILLER_AFTER); } png_set_gray_to_rgb(png); if (depth < 8) { png_set_packing(png); png_set_expand(png); } if (colorType & PNG_COLOR_MASK_PALETTE) { png_set_palette_to_rgb(png); } png_read_update_info(png, pngInfo); rowBytes = png_get_rowbytes(png, pngInfo); data = malloc(rowBytes * height); if (data == NULL) goto FAIL; // Set up row pointers. for (i = 0; i < height; i++) { png_read_row(png, (png_bytep)data + i * rowBytes, NULL); if (progressHandler) progressHandler((float)(i + 1) / (float)height, callbackContext); } png_read_end(png, pngEndInfo); result = ConvertPNGData(data, width, height, rowBytes, png_get_bit_depth(png, pngInfo), png_get_color_type(png, pngInfo)); if (result != NULL) { double invGamma = 1.0/kFPMGammaSRGB; png_get_gAMA(png, pngInfo, &invGamma); FPMApplyGamma(result, 1.0/invGamma, desiredGamma, png_get_bit_depth(png, pngInfo) == 16 ? 65536 : 256); } else { if (errorHandler != NULL) errorHandler("Could not convert PNG data to native representation.", true, callbackContext); } png_destroy_read_struct(&png, &pngInfo, &pngEndInfo); free(data); return result; FAIL: FPMRelease(&result); if (png != NULL) png_destroy_read_struct(&png, &pngInfo, &pngEndInfo); free(data); return NULL; }