static HRESULT WINAPI PngFrameEncode_WritePixels(IWICBitmapFrameEncode *iface, UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels) { PngEncoder *This = encoder_from_frame(iface); png_byte **row_pointers=NULL; UINT i; jmp_buf jmpbuf; TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels); if (!This->frame_initialized || !This->width || !This->height || !This->format) return WINCODEC_ERR_WRONGSTATE; if (lineCount == 0 || lineCount + This->lines_written > This->height) return E_INVALIDARG; /* set up setjmp/longjmp error handling */ if (setjmp(jmpbuf)) { HeapFree(GetProcessHeap(), 0, row_pointers); return E_FAIL; } ppng_set_error_fn(This->png_ptr, &jmpbuf, user_error_fn, user_warning_fn); if (!This->info_written) { ppng_set_IHDR(This->png_ptr, This->info_ptr, This->width, This->height, This->format->bit_depth, This->format->color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); if (This->xres != 0.0 && This->yres != 0.0) { ppng_set_pHYs(This->png_ptr, This->info_ptr, (This->xres+0.0127) / 0.0254, (This->yres+0.0127) / 0.0254, PNG_RESOLUTION_METER); } ppng_write_info(This->png_ptr, This->info_ptr); if (This->format->remove_filler) ppng_set_filler(This->png_ptr, 0, PNG_FILLER_AFTER); if (This->format->swap_rgb) ppng_set_bgr(This->png_ptr); This->info_written = TRUE; } row_pointers = HeapAlloc(GetProcessHeap(), 0, lineCount * sizeof(png_byte*)); if (!row_pointers) return E_OUTOFMEMORY; for (i=0; i<lineCount; i++) row_pointers[i] = pbPixels + cbStride * i; ppng_write_rows(This->png_ptr, row_pointers, lineCount); This->lines_written += lineCount; HeapFree(GetProcessHeap(), 0, row_pointers); return S_OK; }
static HRESULT WINAPI PngFrameEncode_Commit(IWICBitmapFrameEncode *iface) { PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface); jmp_buf jmpbuf; TRACE("(%p)\n", iface); EnterCriticalSection(&This->lock); if (!This->info_written || This->lines_written != This->height || This->frame_committed) { LeaveCriticalSection(&This->lock); return WINCODEC_ERR_WRONGSTATE; } /* set up setjmp/longjmp error handling */ if (setjmp(jmpbuf)) { LeaveCriticalSection(&This->lock); return E_FAIL; } ppng_set_error_fn(This->png_ptr, jmpbuf, user_error_fn, user_warning_fn); ppng_write_end(This->png_ptr, This->info_ptr); This->frame_committed = TRUE; LeaveCriticalSection(&This->lock); return S_OK; }
static HRESULT WINAPI PngEncoder_Initialize(IWICBitmapEncoder *iface, IStream *pIStream, WICBitmapEncoderCacheOption cacheOption) { PngEncoder *This = impl_from_IWICBitmapEncoder(iface); jmp_buf jmpbuf; TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOption); EnterCriticalSection(&This->lock); if (This->png_ptr) { LeaveCriticalSection(&This->lock); return WINCODEC_ERR_WRONGSTATE; } /* initialize libpng */ This->png_ptr = ppng_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!This->png_ptr) { LeaveCriticalSection(&This->lock); return E_FAIL; } This->info_ptr = ppng_create_info_struct(This->png_ptr); if (!This->info_ptr) { ppng_destroy_write_struct(&This->png_ptr, NULL); This->png_ptr = NULL; LeaveCriticalSection(&This->lock); return E_FAIL; } IStream_AddRef(pIStream); This->stream = pIStream; /* set up setjmp/longjmp error handling */ if (setjmp(jmpbuf)) { ppng_destroy_write_struct(&This->png_ptr, &This->info_ptr); This->png_ptr = NULL; IStream_Release(This->stream); This->stream = NULL; LeaveCriticalSection(&This->lock); return E_FAIL; } ppng_set_error_fn(This->png_ptr, jmpbuf, user_error_fn, user_warning_fn); /* set up custom i/o handling */ ppng_set_write_fn(This->png_ptr, This, user_write_data, user_flush); LeaveCriticalSection(&This->lock); return S_OK; }
static HRESULT WINAPI PngFrameEncode_Commit(IWICBitmapFrameEncode *iface) { PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface); png_byte **row_pointers=NULL; jmp_buf jmpbuf; TRACE("(%p)\n", iface); EnterCriticalSection(&This->lock); if (!This->info_written || This->lines_written != This->height || This->frame_committed) { LeaveCriticalSection(&This->lock); return WINCODEC_ERR_WRONGSTATE; } /* set up setjmp/longjmp error handling */ if (setjmp(jmpbuf)) { LeaveCriticalSection(&This->lock); HeapFree(GetProcessHeap(), 0, row_pointers); return E_FAIL; } ppng_set_error_fn(This->png_ptr, jmpbuf, user_error_fn, user_warning_fn); if (This->interlace) { int i; row_pointers = HeapAlloc(GetProcessHeap(), 0, This->height * sizeof(png_byte*)); if (!row_pointers) { LeaveCriticalSection(&This->lock); return E_OUTOFMEMORY; } for (i=0; i<This->height; i++) row_pointers[i] = This->data + This->stride * i; for (i=0; i<This->passes; i++) ppng_write_rows(This->png_ptr, row_pointers, This->height); } ppng_write_end(This->png_ptr, This->info_ptr); This->frame_committed = TRUE; HeapFree(GetProcessHeap(), 0, row_pointers); LeaveCriticalSection(&This->lock); return S_OK; }
static HRESULT WINAPI PngDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream, WICDecodeOptions cacheOptions) { PngDecoder *This = (PngDecoder*)iface; LARGE_INTEGER seek; HRESULT hr; png_bytep *row_pointers=NULL; UINT image_size; UINT i; int color_type, bit_depth; png_bytep trans; int num_trans; png_uint_32 transparency; png_color_16p trans_values; jmp_buf jmpbuf; TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions); /* initialize libpng */ This->png_ptr = ppng_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!This->png_ptr) return E_FAIL; This->info_ptr = ppng_create_info_struct(This->png_ptr); if (!This->info_ptr) { ppng_destroy_read_struct(&This->png_ptr, NULL, NULL); This->png_ptr = NULL; return E_FAIL; } This->end_info = ppng_create_info_struct(This->png_ptr); if (!This->info_ptr) { ppng_destroy_read_struct(&This->png_ptr, &This->info_ptr, NULL); This->png_ptr = NULL; return E_FAIL; } /* set up setjmp/longjmp error handling */ if (setjmp(jmpbuf)) { ppng_destroy_read_struct(&This->png_ptr, &This->info_ptr, &This->end_info); HeapFree(GetProcessHeap(), 0, row_pointers); This->png_ptr = NULL; return E_FAIL; } ppng_set_error_fn(This->png_ptr, &jmpbuf, user_error_fn, user_warning_fn); /* seek to the start of the stream */ seek.QuadPart = 0; hr = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL); if (FAILED(hr)) return hr; /* set up custom i/o handling */ ppng_set_read_fn(This->png_ptr, pIStream, user_read_data); /* read the header */ ppng_read_info(This->png_ptr, This->info_ptr); /* choose a pixel format */ color_type = ppng_get_color_type(This->png_ptr, This->info_ptr); bit_depth = ppng_get_bit_depth(This->png_ptr, This->info_ptr); /* check for color-keyed alpha */ transparency = ppng_get_tRNS(This->png_ptr, This->info_ptr, &trans, &num_trans, &trans_values); if (transparency && color_type != PNG_COLOR_TYPE_PALETTE) { /* expand to RGBA */ if (color_type == PNG_COLOR_TYPE_GRAY) { if (bit_depth < 8) { #if HAVE_PNG_SET_EXPAND_GRAY_1_2_4_TO_8 ppng_set_expand_gray_1_2_4_to_8(This->png_ptr); #else ppng_set_gray_1_2_4_to_8(This->png_ptr); #endif bit_depth = 8; } ppng_set_gray_to_rgb(This->png_ptr); } ppng_set_tRNS_to_alpha(This->png_ptr); color_type = PNG_COLOR_TYPE_RGB_ALPHA; } switch (color_type) { case PNG_COLOR_TYPE_GRAY: This->bpp = bit_depth; switch (bit_depth) { case 1: This->format = &GUID_WICPixelFormatBlackWhite; break; case 2: This->format = &GUID_WICPixelFormat2bppGray; break; case 4: This->format = &GUID_WICPixelFormat4bppGray; break; case 8: This->format = &GUID_WICPixelFormat8bppGray; break; case 16: This->format = &GUID_WICPixelFormat16bppGray; break; default: ERR("invalid grayscale bit depth: %i\n", bit_depth); return E_FAIL; } break; case PNG_COLOR_TYPE_GRAY_ALPHA: /* WIC does not support grayscale alpha formats so use RGBA */ ppng_set_gray_to_rgb(This->png_ptr); case PNG_COLOR_TYPE_RGB_ALPHA: This->bpp = bit_depth * 4; switch (bit_depth) { case 8: ppng_set_bgr(This->png_ptr); This->format = &GUID_WICPixelFormat32bppBGRA; break; case 16: This->format = &GUID_WICPixelFormat64bppRGBA; break; default: ERR("invalid RGBA bit depth: %i\n", bit_depth); return E_FAIL; } break; case PNG_COLOR_TYPE_PALETTE: This->bpp = bit_depth; switch (bit_depth) { case 1: This->format = &GUID_WICPixelFormat1bppIndexed; break; case 2: This->format = &GUID_WICPixelFormat2bppIndexed; break; case 4: This->format = &GUID_WICPixelFormat4bppIndexed; break; case 8: This->format = &GUID_WICPixelFormat8bppIndexed; break; default: ERR("invalid indexed color bit depth: %i\n", bit_depth); return E_FAIL; } break; case PNG_COLOR_TYPE_RGB: This->bpp = bit_depth * 3; switch (bit_depth) { case 8: ppng_set_bgr(This->png_ptr); This->format = &GUID_WICPixelFormat24bppBGR; break; case 16: This->format = &GUID_WICPixelFormat48bppRGB; break; default: ERR("invalid RGB color bit depth: %i\n", bit_depth); return E_FAIL; } break; default: ERR("invalid color type %i\n", color_type); return E_FAIL; } /* read the image data */ This->width = ppng_get_image_width(This->png_ptr, This->info_ptr); This->height = ppng_get_image_height(This->png_ptr, This->info_ptr); This->stride = This->width * This->bpp; image_size = This->stride * This->height; This->image_bits = HeapAlloc(GetProcessHeap(), 0, image_size); if (!This->image_bits) return E_OUTOFMEMORY; row_pointers = HeapAlloc(GetProcessHeap(), 0, sizeof(png_bytep)*This->height); if (!row_pointers) return E_OUTOFMEMORY; for (i=0; i<This->height; i++) row_pointers[i] = This->image_bits + i * This->stride; ppng_read_image(This->png_ptr, row_pointers); HeapFree(GetProcessHeap(), 0, row_pointers); row_pointers = NULL; ppng_read_end(This->png_ptr, This->end_info); This->initialized = TRUE; return S_OK; }
static HRESULT WINAPI PngFrameEncode_WritePixels(IWICBitmapFrameEncode *iface, UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels) { PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface); png_byte **row_pointers=NULL; UINT i; jmp_buf jmpbuf; TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels); EnterCriticalSection(&This->lock); if (!This->frame_initialized || !This->width || !This->height || !This->format) { LeaveCriticalSection(&This->lock); return WINCODEC_ERR_WRONGSTATE; } if (lineCount == 0 || lineCount + This->lines_written > This->height) { LeaveCriticalSection(&This->lock); return E_INVALIDARG; } /* set up setjmp/longjmp error handling */ if (setjmp(jmpbuf)) { LeaveCriticalSection(&This->lock); HeapFree(GetProcessHeap(), 0, row_pointers); return E_FAIL; } ppng_set_error_fn(This->png_ptr, jmpbuf, user_error_fn, user_warning_fn); if (!This->info_written) { if (This->interlace) { /* libpng requires us to write all data multiple times in this case. */ This->stride = (This->format->bpp * This->width + 7)/8; This->data = HeapAlloc(GetProcessHeap(), 0, This->height * This->stride); if (!This->data) { LeaveCriticalSection(&This->lock); return E_OUTOFMEMORY; } } ppng_set_IHDR(This->png_ptr, This->info_ptr, This->width, This->height, This->format->bit_depth, This->format->color_type, This->interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); if (This->xres != 0.0 && This->yres != 0.0) { ppng_set_pHYs(This->png_ptr, This->info_ptr, (This->xres+0.0127) / 0.0254, (This->yres+0.0127) / 0.0254, PNG_RESOLUTION_METER); } ppng_write_info(This->png_ptr, This->info_ptr); if (This->format->remove_filler) ppng_set_filler(This->png_ptr, 0, PNG_FILLER_AFTER); if (This->format->swap_rgb) ppng_set_bgr(This->png_ptr); if (This->interlace) This->passes = ppng_set_interlace_handling(This->png_ptr); This->info_written = TRUE; } if (This->interlace) { /* Just store the data so we can write it in multiple passes in Commit. */ for (i=0; i<lineCount; i++) memcpy(This->data + This->stride * (This->lines_written + i), pbPixels + cbStride * i, This->stride); This->lines_written += lineCount; LeaveCriticalSection(&This->lock); return S_OK; } row_pointers = HeapAlloc(GetProcessHeap(), 0, lineCount * sizeof(png_byte*)); if (!row_pointers) { LeaveCriticalSection(&This->lock); return E_OUTOFMEMORY; } for (i=0; i<lineCount; i++) row_pointers[i] = pbPixels + cbStride * i; ppng_write_rows(This->png_ptr, row_pointers, lineCount); This->lines_written += lineCount; LeaveCriticalSection(&This->lock); HeapFree(GetProcessHeap(), 0, row_pointers); return S_OK; }