Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenpngformat.c
Go to the documentation of this file.
00001 /* 00002 * Copyright 2009 Vincent Povirk for CodeWeavers 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Lesser General Public 00006 * License as published by the Free Software Foundation; either 00007 * version 2.1 of the License, or (at your option) any later version. 00008 * 00009 * This library is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 * Lesser General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU Lesser General Public 00015 * License along with this library; if not, write to the Free Software 00016 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00017 */ 00018 00019 #include "config.h" 00020 #include "wine/port.h" 00021 00022 #include <stdarg.h> 00023 00024 #ifdef HAVE_PNG_H 00025 #include <png.h> 00026 #endif 00027 00028 #define COBJMACROS 00029 00030 #include "windef.h" 00031 #include "winbase.h" 00032 #include "objbase.h" 00033 #include "wincodec.h" 00034 00035 #include "wincodecs_private.h" 00036 00037 #include "wine/debug.h" 00038 #include "wine/library.h" 00039 00040 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); 00041 00042 #ifdef SONAME_LIBPNG 00043 00044 static void *libpng_handle; 00045 #define MAKE_FUNCPTR(f) static typeof(f) * p##f 00046 MAKE_FUNCPTR(png_create_read_struct); 00047 MAKE_FUNCPTR(png_create_info_struct); 00048 MAKE_FUNCPTR(png_create_write_struct); 00049 MAKE_FUNCPTR(png_destroy_read_struct); 00050 MAKE_FUNCPTR(png_destroy_write_struct); 00051 MAKE_FUNCPTR(png_error); 00052 MAKE_FUNCPTR(png_get_bit_depth); 00053 MAKE_FUNCPTR(png_get_color_type); 00054 MAKE_FUNCPTR(png_get_error_ptr); 00055 MAKE_FUNCPTR(png_get_image_height); 00056 MAKE_FUNCPTR(png_get_image_width); 00057 MAKE_FUNCPTR(png_get_io_ptr); 00058 MAKE_FUNCPTR(png_get_pHYs); 00059 MAKE_FUNCPTR(png_get_PLTE); 00060 MAKE_FUNCPTR(png_get_tRNS); 00061 MAKE_FUNCPTR(png_set_bgr); 00062 MAKE_FUNCPTR(png_set_error_fn); 00063 #if HAVE_PNG_SET_EXPAND_GRAY_1_2_4_TO_8 00064 MAKE_FUNCPTR(png_set_expand_gray_1_2_4_to_8); 00065 #else 00066 MAKE_FUNCPTR(png_set_gray_1_2_4_to_8); 00067 #endif 00068 MAKE_FUNCPTR(png_set_filler); 00069 MAKE_FUNCPTR(png_set_gray_to_rgb); 00070 MAKE_FUNCPTR(png_set_IHDR); 00071 MAKE_FUNCPTR(png_set_pHYs); 00072 MAKE_FUNCPTR(png_set_read_fn); 00073 MAKE_FUNCPTR(png_set_strip_16); 00074 MAKE_FUNCPTR(png_set_tRNS_to_alpha); 00075 MAKE_FUNCPTR(png_set_write_fn); 00076 MAKE_FUNCPTR(png_read_end); 00077 MAKE_FUNCPTR(png_read_image); 00078 MAKE_FUNCPTR(png_read_info); 00079 MAKE_FUNCPTR(png_write_end); 00080 MAKE_FUNCPTR(png_write_info); 00081 MAKE_FUNCPTR(png_write_rows); 00082 #undef MAKE_FUNCPTR 00083 00084 static void *load_libpng(void) 00085 { 00086 if((libpng_handle = wine_dlopen(SONAME_LIBPNG, RTLD_NOW, NULL, 0)) != NULL) { 00087 00088 #define LOAD_FUNCPTR(f) \ 00089 if((p##f = wine_dlsym(libpng_handle, #f, NULL, 0)) == NULL) { \ 00090 libpng_handle = NULL; \ 00091 return NULL; \ 00092 } 00093 LOAD_FUNCPTR(png_create_read_struct); 00094 LOAD_FUNCPTR(png_create_info_struct); 00095 LOAD_FUNCPTR(png_create_write_struct); 00096 LOAD_FUNCPTR(png_destroy_read_struct); 00097 LOAD_FUNCPTR(png_destroy_write_struct); 00098 LOAD_FUNCPTR(png_error); 00099 LOAD_FUNCPTR(png_get_bit_depth); 00100 LOAD_FUNCPTR(png_get_color_type); 00101 LOAD_FUNCPTR(png_get_error_ptr); 00102 LOAD_FUNCPTR(png_get_image_height); 00103 LOAD_FUNCPTR(png_get_image_width); 00104 LOAD_FUNCPTR(png_get_io_ptr); 00105 LOAD_FUNCPTR(png_get_pHYs); 00106 LOAD_FUNCPTR(png_get_PLTE); 00107 LOAD_FUNCPTR(png_get_tRNS); 00108 LOAD_FUNCPTR(png_set_bgr); 00109 LOAD_FUNCPTR(png_set_error_fn); 00110 #if HAVE_PNG_SET_EXPAND_GRAY_1_2_4_TO_8 00111 LOAD_FUNCPTR(png_set_expand_gray_1_2_4_to_8); 00112 #else 00113 LOAD_FUNCPTR(png_set_gray_1_2_4_to_8); 00114 #endif 00115 LOAD_FUNCPTR(png_set_filler); 00116 LOAD_FUNCPTR(png_set_gray_to_rgb); 00117 LOAD_FUNCPTR(png_set_IHDR); 00118 LOAD_FUNCPTR(png_set_pHYs); 00119 LOAD_FUNCPTR(png_set_read_fn); 00120 LOAD_FUNCPTR(png_set_strip_16); 00121 LOAD_FUNCPTR(png_set_tRNS_to_alpha); 00122 LOAD_FUNCPTR(png_set_write_fn); 00123 LOAD_FUNCPTR(png_read_end); 00124 LOAD_FUNCPTR(png_read_image); 00125 LOAD_FUNCPTR(png_read_info); 00126 LOAD_FUNCPTR(png_write_end); 00127 LOAD_FUNCPTR(png_write_info); 00128 LOAD_FUNCPTR(png_write_rows); 00129 00130 #undef LOAD_FUNCPTR 00131 } 00132 return libpng_handle; 00133 } 00134 00135 static void user_error_fn(png_structp png_ptr, png_const_charp error_message) 00136 { 00137 jmp_buf *pjmpbuf; 00138 00139 /* This uses setjmp/longjmp just like the default. We can't use the 00140 * default because there's no way to access the jmp buffer in the png_struct 00141 * that works in 1.2 and 1.4 and allows us to dynamically load libpng. */ 00142 WARN("PNG error: %s\n", debugstr_a(error_message)); 00143 pjmpbuf = ppng_get_error_ptr(png_ptr); 00144 longjmp(*pjmpbuf, 1); 00145 } 00146 00147 static void user_warning_fn(png_structp png_ptr, png_const_charp warning_message) 00148 { 00149 WARN("PNG warning: %s\n", debugstr_a(warning_message)); 00150 } 00151 00152 typedef struct { 00153 const IWICBitmapDecoderVtbl *lpVtbl; 00154 const IWICBitmapFrameDecodeVtbl *lpFrameVtbl; 00155 LONG ref; 00156 png_structp png_ptr; 00157 png_infop info_ptr; 00158 png_infop end_info; 00159 BOOL initialized; 00160 int bpp; 00161 int width, height; 00162 UINT stride; 00163 const WICPixelFormatGUID *format; 00164 BYTE *image_bits; 00165 CRITICAL_SECTION lock; /* must be held when png structures are accessed or initialized is set */ 00166 } PngDecoder; 00167 00168 static inline PngDecoder *impl_from_frame(IWICBitmapFrameDecode *iface) 00169 { 00170 return CONTAINING_RECORD(iface, PngDecoder, lpFrameVtbl); 00171 } 00172 00173 static const IWICBitmapFrameDecodeVtbl PngDecoder_FrameVtbl; 00174 00175 static HRESULT WINAPI PngDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid, 00176 void **ppv) 00177 { 00178 PngDecoder *This = (PngDecoder*)iface; 00179 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 00180 00181 if (!ppv) return E_INVALIDARG; 00182 00183 if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICBitmapDecoder, iid)) 00184 { 00185 *ppv = This; 00186 } 00187 else 00188 { 00189 *ppv = NULL; 00190 return E_NOINTERFACE; 00191 } 00192 00193 IUnknown_AddRef((IUnknown*)*ppv); 00194 return S_OK; 00195 } 00196 00197 static ULONG WINAPI PngDecoder_AddRef(IWICBitmapDecoder *iface) 00198 { 00199 PngDecoder *This = (PngDecoder*)iface; 00200 ULONG ref = InterlockedIncrement(&This->ref); 00201 00202 TRACE("(%p) refcount=%u\n", iface, ref); 00203 00204 return ref; 00205 } 00206 00207 static ULONG WINAPI PngDecoder_Release(IWICBitmapDecoder *iface) 00208 { 00209 PngDecoder *This = (PngDecoder*)iface; 00210 ULONG ref = InterlockedDecrement(&This->ref); 00211 00212 TRACE("(%p) refcount=%u\n", iface, ref); 00213 00214 if (ref == 0) 00215 { 00216 if (This->png_ptr) 00217 ppng_destroy_read_struct(&This->png_ptr, &This->info_ptr, &This->end_info); 00218 This->lock.DebugInfo->Spare[0] = 0; 00219 DeleteCriticalSection(&This->lock); 00220 HeapFree(GetProcessHeap(), 0, This->image_bits); 00221 HeapFree(GetProcessHeap(), 0, This); 00222 } 00223 00224 return ref; 00225 } 00226 00227 static HRESULT WINAPI PngDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *pIStream, 00228 DWORD *pdwCapability) 00229 { 00230 FIXME("(%p,%p,%p): stub\n", iface, pIStream, pdwCapability); 00231 return E_NOTIMPL; 00232 } 00233 00234 static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t length) 00235 { 00236 IStream *stream = ppng_get_io_ptr(png_ptr); 00237 HRESULT hr; 00238 ULONG bytesread; 00239 00240 hr = IStream_Read(stream, data, length, &bytesread); 00241 if (FAILED(hr) || bytesread != length) 00242 { 00243 ppng_error(png_ptr, "failed reading data"); 00244 } 00245 } 00246 00247 static HRESULT WINAPI PngDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream, 00248 WICDecodeOptions cacheOptions) 00249 { 00250 PngDecoder *This = (PngDecoder*)iface; 00251 LARGE_INTEGER seek; 00252 HRESULT hr=S_OK; 00253 png_bytep *row_pointers=NULL; 00254 UINT image_size; 00255 UINT i; 00256 int color_type, bit_depth; 00257 png_bytep trans; 00258 int num_trans; 00259 png_uint_32 transparency; 00260 png_color_16p trans_values; 00261 jmp_buf jmpbuf; 00262 00263 TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions); 00264 00265 EnterCriticalSection(&This->lock); 00266 00267 /* initialize libpng */ 00268 This->png_ptr = ppng_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 00269 if (!This->png_ptr) 00270 { 00271 hr = E_FAIL; 00272 goto end; 00273 } 00274 00275 This->info_ptr = ppng_create_info_struct(This->png_ptr); 00276 if (!This->info_ptr) 00277 { 00278 ppng_destroy_read_struct(&This->png_ptr, NULL, NULL); 00279 This->png_ptr = NULL; 00280 hr = E_FAIL; 00281 goto end; 00282 } 00283 00284 This->end_info = ppng_create_info_struct(This->png_ptr); 00285 if (!This->info_ptr) 00286 { 00287 ppng_destroy_read_struct(&This->png_ptr, &This->info_ptr, NULL); 00288 This->png_ptr = NULL; 00289 hr = E_FAIL; 00290 goto end; 00291 } 00292 00293 /* set up setjmp/longjmp error handling */ 00294 if (setjmp(jmpbuf)) 00295 { 00296 ppng_destroy_read_struct(&This->png_ptr, &This->info_ptr, &This->end_info); 00297 HeapFree(GetProcessHeap(), 0, row_pointers); 00298 This->png_ptr = NULL; 00299 hr = E_FAIL; 00300 goto end; 00301 } 00302 ppng_set_error_fn(This->png_ptr, &jmpbuf, user_error_fn, user_warning_fn); 00303 00304 /* seek to the start of the stream */ 00305 seek.QuadPart = 0; 00306 hr = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL); 00307 if (FAILED(hr)) goto end; 00308 00309 /* set up custom i/o handling */ 00310 ppng_set_read_fn(This->png_ptr, pIStream, user_read_data); 00311 00312 /* read the header */ 00313 ppng_read_info(This->png_ptr, This->info_ptr); 00314 00315 /* choose a pixel format */ 00316 color_type = ppng_get_color_type(This->png_ptr, This->info_ptr); 00317 bit_depth = ppng_get_bit_depth(This->png_ptr, This->info_ptr); 00318 00319 /* check for color-keyed alpha */ 00320 transparency = ppng_get_tRNS(This->png_ptr, This->info_ptr, &trans, &num_trans, &trans_values); 00321 00322 if (transparency && color_type != PNG_COLOR_TYPE_PALETTE) 00323 { 00324 /* expand to RGBA */ 00325 if (color_type == PNG_COLOR_TYPE_GRAY) 00326 { 00327 if (bit_depth < 8) 00328 { 00329 #if HAVE_PNG_SET_EXPAND_GRAY_1_2_4_TO_8 00330 ppng_set_expand_gray_1_2_4_to_8(This->png_ptr); 00331 #else 00332 ppng_set_gray_1_2_4_to_8(This->png_ptr); 00333 #endif 00334 bit_depth = 8; 00335 } 00336 ppng_set_gray_to_rgb(This->png_ptr); 00337 } 00338 ppng_set_tRNS_to_alpha(This->png_ptr); 00339 color_type = PNG_COLOR_TYPE_RGB_ALPHA; 00340 } 00341 00342 switch (color_type) 00343 { 00344 case PNG_COLOR_TYPE_GRAY: 00345 This->bpp = bit_depth; 00346 switch (bit_depth) 00347 { 00348 case 1: This->format = &GUID_WICPixelFormatBlackWhite; break; 00349 case 2: This->format = &GUID_WICPixelFormat2bppGray; break; 00350 case 4: This->format = &GUID_WICPixelFormat4bppGray; break; 00351 case 8: This->format = &GUID_WICPixelFormat8bppGray; break; 00352 case 16: This->format = &GUID_WICPixelFormat16bppGray; break; 00353 default: 00354 ERR("invalid grayscale bit depth: %i\n", bit_depth); 00355 hr = E_FAIL; 00356 goto end; 00357 } 00358 break; 00359 case PNG_COLOR_TYPE_GRAY_ALPHA: 00360 /* WIC does not support grayscale alpha formats so use RGBA */ 00361 ppng_set_gray_to_rgb(This->png_ptr); 00362 case PNG_COLOR_TYPE_RGB_ALPHA: 00363 This->bpp = bit_depth * 4; 00364 switch (bit_depth) 00365 { 00366 case 8: 00367 ppng_set_bgr(This->png_ptr); 00368 This->format = &GUID_WICPixelFormat32bppBGRA; 00369 break; 00370 case 16: This->format = &GUID_WICPixelFormat64bppRGBA; break; 00371 default: 00372 ERR("invalid RGBA bit depth: %i\n", bit_depth); 00373 hr = E_FAIL; 00374 goto end; 00375 } 00376 break; 00377 case PNG_COLOR_TYPE_PALETTE: 00378 This->bpp = bit_depth; 00379 switch (bit_depth) 00380 { 00381 case 1: This->format = &GUID_WICPixelFormat1bppIndexed; break; 00382 case 2: This->format = &GUID_WICPixelFormat2bppIndexed; break; 00383 case 4: This->format = &GUID_WICPixelFormat4bppIndexed; break; 00384 case 8: This->format = &GUID_WICPixelFormat8bppIndexed; break; 00385 default: 00386 ERR("invalid indexed color bit depth: %i\n", bit_depth); 00387 hr = E_FAIL; 00388 goto end; 00389 } 00390 break; 00391 case PNG_COLOR_TYPE_RGB: 00392 This->bpp = bit_depth * 3; 00393 switch (bit_depth) 00394 { 00395 case 8: 00396 ppng_set_bgr(This->png_ptr); 00397 This->format = &GUID_WICPixelFormat24bppBGR; 00398 break; 00399 case 16: This->format = &GUID_WICPixelFormat48bppRGB; break; 00400 default: 00401 ERR("invalid RGB color bit depth: %i\n", bit_depth); 00402 hr = E_FAIL; 00403 goto end; 00404 } 00405 break; 00406 default: 00407 ERR("invalid color type %i\n", color_type); 00408 hr = E_FAIL; 00409 goto end; 00410 } 00411 00412 /* read the image data */ 00413 This->width = ppng_get_image_width(This->png_ptr, This->info_ptr); 00414 This->height = ppng_get_image_height(This->png_ptr, This->info_ptr); 00415 This->stride = This->width * This->bpp; 00416 image_size = This->stride * This->height; 00417 00418 This->image_bits = HeapAlloc(GetProcessHeap(), 0, image_size); 00419 if (!This->image_bits) 00420 { 00421 hr = E_OUTOFMEMORY; 00422 goto end; 00423 } 00424 00425 row_pointers = HeapAlloc(GetProcessHeap(), 0, sizeof(png_bytep)*This->height); 00426 if (!row_pointers) 00427 { 00428 hr = E_OUTOFMEMORY; 00429 goto end; 00430 } 00431 00432 for (i=0; i<This->height; i++) 00433 row_pointers[i] = This->image_bits + i * This->stride; 00434 00435 ppng_read_image(This->png_ptr, row_pointers); 00436 00437 HeapFree(GetProcessHeap(), 0, row_pointers); 00438 row_pointers = NULL; 00439 00440 ppng_read_end(This->png_ptr, This->end_info); 00441 00442 This->initialized = TRUE; 00443 00444 end: 00445 00446 LeaveCriticalSection(&This->lock); 00447 00448 return hr; 00449 } 00450 00451 static HRESULT WINAPI PngDecoder_GetContainerFormat(IWICBitmapDecoder *iface, 00452 GUID *pguidContainerFormat) 00453 { 00454 memcpy(pguidContainerFormat, &GUID_ContainerFormatPng, sizeof(GUID)); 00455 return S_OK; 00456 } 00457 00458 static HRESULT WINAPI PngDecoder_GetDecoderInfo(IWICBitmapDecoder *iface, 00459 IWICBitmapDecoderInfo **ppIDecoderInfo) 00460 { 00461 FIXME("(%p,%p): stub\n", iface, ppIDecoderInfo); 00462 return E_NOTIMPL; 00463 } 00464 00465 static HRESULT WINAPI PngDecoder_CopyPalette(IWICBitmapDecoder *iface, 00466 IWICPalette *pIPalette) 00467 { 00468 FIXME("(%p,%p): stub\n", iface, pIPalette); 00469 return E_NOTIMPL; 00470 } 00471 00472 static HRESULT WINAPI PngDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface, 00473 IWICMetadataQueryReader **ppIMetadataQueryReader) 00474 { 00475 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryReader); 00476 return E_NOTIMPL; 00477 } 00478 00479 static HRESULT WINAPI PngDecoder_GetPreview(IWICBitmapDecoder *iface, 00480 IWICBitmapSource **ppIBitmapSource) 00481 { 00482 FIXME("(%p,%p): stub\n", iface, ppIBitmapSource); 00483 return E_NOTIMPL; 00484 } 00485 00486 static HRESULT WINAPI PngDecoder_GetColorContexts(IWICBitmapDecoder *iface, 00487 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) 00488 { 00489 FIXME("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount); 00490 return E_NOTIMPL; 00491 } 00492 00493 static HRESULT WINAPI PngDecoder_GetThumbnail(IWICBitmapDecoder *iface, 00494 IWICBitmapSource **ppIThumbnail) 00495 { 00496 TRACE("(%p,%p)\n", iface, ppIThumbnail); 00497 return WINCODEC_ERR_CODECNOTHUMBNAIL; 00498 } 00499 00500 static HRESULT WINAPI PngDecoder_GetFrameCount(IWICBitmapDecoder *iface, 00501 UINT *pCount) 00502 { 00503 *pCount = 1; 00504 return S_OK; 00505 } 00506 00507 static HRESULT WINAPI PngDecoder_GetFrame(IWICBitmapDecoder *iface, 00508 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame) 00509 { 00510 PngDecoder *This = (PngDecoder*)iface; 00511 TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame); 00512 00513 if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED; 00514 00515 if (index != 0) return E_INVALIDARG; 00516 00517 IWICBitmapDecoder_AddRef(iface); 00518 00519 *ppIBitmapFrame = (void*)(&This->lpFrameVtbl); 00520 00521 return S_OK; 00522 } 00523 00524 static const IWICBitmapDecoderVtbl PngDecoder_Vtbl = { 00525 PngDecoder_QueryInterface, 00526 PngDecoder_AddRef, 00527 PngDecoder_Release, 00528 PngDecoder_QueryCapability, 00529 PngDecoder_Initialize, 00530 PngDecoder_GetContainerFormat, 00531 PngDecoder_GetDecoderInfo, 00532 PngDecoder_CopyPalette, 00533 PngDecoder_GetMetadataQueryReader, 00534 PngDecoder_GetPreview, 00535 PngDecoder_GetColorContexts, 00536 PngDecoder_GetThumbnail, 00537 PngDecoder_GetFrameCount, 00538 PngDecoder_GetFrame 00539 }; 00540 00541 static HRESULT WINAPI PngDecoder_Frame_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid, 00542 void **ppv) 00543 { 00544 if (!ppv) return E_INVALIDARG; 00545 00546 if (IsEqualIID(&IID_IUnknown, iid) || 00547 IsEqualIID(&IID_IWICBitmapSource, iid) || 00548 IsEqualIID(&IID_IWICBitmapFrameDecode, iid)) 00549 { 00550 *ppv = iface; 00551 } 00552 else 00553 { 00554 *ppv = NULL; 00555 return E_NOINTERFACE; 00556 } 00557 00558 IUnknown_AddRef((IUnknown*)*ppv); 00559 return S_OK; 00560 } 00561 00562 static ULONG WINAPI PngDecoder_Frame_AddRef(IWICBitmapFrameDecode *iface) 00563 { 00564 PngDecoder *This = impl_from_frame(iface); 00565 return IUnknown_AddRef((IUnknown*)This); 00566 } 00567 00568 static ULONG WINAPI PngDecoder_Frame_Release(IWICBitmapFrameDecode *iface) 00569 { 00570 PngDecoder *This = impl_from_frame(iface); 00571 return IUnknown_Release((IUnknown*)This); 00572 } 00573 00574 static HRESULT WINAPI PngDecoder_Frame_GetSize(IWICBitmapFrameDecode *iface, 00575 UINT *puiWidth, UINT *puiHeight) 00576 { 00577 PngDecoder *This = impl_from_frame(iface); 00578 *puiWidth = This->width; 00579 *puiHeight = This->height; 00580 TRACE("(%p)->(%u,%u)\n", iface, *puiWidth, *puiHeight); 00581 return S_OK; 00582 } 00583 00584 static HRESULT WINAPI PngDecoder_Frame_GetPixelFormat(IWICBitmapFrameDecode *iface, 00585 WICPixelFormatGUID *pPixelFormat) 00586 { 00587 PngDecoder *This = impl_from_frame(iface); 00588 TRACE("(%p,%p)\n", iface, pPixelFormat); 00589 00590 memcpy(pPixelFormat, This->format, sizeof(GUID)); 00591 00592 return S_OK; 00593 } 00594 00595 static HRESULT WINAPI PngDecoder_Frame_GetResolution(IWICBitmapFrameDecode *iface, 00596 double *pDpiX, double *pDpiY) 00597 { 00598 PngDecoder *This = impl_from_frame(iface); 00599 png_uint_32 ret, xres, yres; 00600 int unit_type; 00601 00602 EnterCriticalSection(&This->lock); 00603 00604 ret = ppng_get_pHYs(This->png_ptr, This->info_ptr, &xres, &yres, &unit_type); 00605 00606 if (ret && unit_type == PNG_RESOLUTION_METER) 00607 { 00608 *pDpiX = xres * 0.0254; 00609 *pDpiY = yres * 0.0254; 00610 } 00611 else 00612 { 00613 WARN("no pHYs block present\n"); 00614 *pDpiX = *pDpiY = 96.0; 00615 } 00616 00617 LeaveCriticalSection(&This->lock); 00618 00619 TRACE("(%p)->(%0.2f,%0.2f)\n", iface, *pDpiX, *pDpiY); 00620 00621 return S_OK; 00622 } 00623 00624 static HRESULT WINAPI PngDecoder_Frame_CopyPalette(IWICBitmapFrameDecode *iface, 00625 IWICPalette *pIPalette) 00626 { 00627 PngDecoder *This = impl_from_frame(iface); 00628 png_uint_32 ret; 00629 png_colorp png_palette; 00630 int num_palette; 00631 WICColor palette[256]; 00632 png_bytep trans; 00633 int num_trans; 00634 png_color_16p trans_values; 00635 int i; 00636 HRESULT hr=S_OK; 00637 00638 TRACE("(%p,%p)\n", iface, pIPalette); 00639 00640 EnterCriticalSection(&This->lock); 00641 00642 ret = ppng_get_PLTE(This->png_ptr, This->info_ptr, &png_palette, &num_palette); 00643 if (!ret) 00644 { 00645 hr = WINCODEC_ERR_PALETTEUNAVAILABLE; 00646 goto end; 00647 } 00648 00649 if (num_palette > 256) 00650 { 00651 ERR("palette has %i colors?!\n", num_palette); 00652 hr = E_FAIL; 00653 goto end; 00654 } 00655 00656 for (i=0; i<num_palette; i++) 00657 { 00658 palette[i] = (0xff000000| 00659 png_palette[i].red << 16| 00660 png_palette[i].green << 8| 00661 png_palette[i].blue); 00662 } 00663 00664 ret = ppng_get_tRNS(This->png_ptr, This->info_ptr, &trans, &num_trans, &trans_values); 00665 if (ret) 00666 { 00667 for (i=0; i<num_trans; i++) 00668 { 00669 palette[trans[i]] = 0x00000000; 00670 } 00671 } 00672 00673 end: 00674 00675 LeaveCriticalSection(&This->lock); 00676 00677 if (SUCCEEDED(hr)) 00678 hr = IWICPalette_InitializeCustom(pIPalette, palette, num_palette); 00679 00680 return hr; 00681 } 00682 00683 static HRESULT WINAPI PngDecoder_Frame_CopyPixels(IWICBitmapFrameDecode *iface, 00684 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer) 00685 { 00686 PngDecoder *This = impl_from_frame(iface); 00687 TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer); 00688 00689 return copy_pixels(This->bpp, This->image_bits, 00690 This->width, This->height, This->stride, 00691 prc, cbStride, cbBufferSize, pbBuffer); 00692 } 00693 00694 static HRESULT WINAPI PngDecoder_Frame_GetMetadataQueryReader(IWICBitmapFrameDecode *iface, 00695 IWICMetadataQueryReader **ppIMetadataQueryReader) 00696 { 00697 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryReader); 00698 return E_NOTIMPL; 00699 } 00700 00701 static HRESULT WINAPI PngDecoder_Frame_GetColorContexts(IWICBitmapFrameDecode *iface, 00702 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) 00703 { 00704 FIXME("(%p,%u,%p,%p): stub\n", iface, cCount, ppIColorContexts, pcActualCount); 00705 return E_NOTIMPL; 00706 } 00707 00708 static HRESULT WINAPI PngDecoder_Frame_GetThumbnail(IWICBitmapFrameDecode *iface, 00709 IWICBitmapSource **ppIThumbnail) 00710 { 00711 FIXME("(%p,%p): stub\n", iface, ppIThumbnail); 00712 return E_NOTIMPL; 00713 } 00714 00715 static const IWICBitmapFrameDecodeVtbl PngDecoder_FrameVtbl = { 00716 PngDecoder_Frame_QueryInterface, 00717 PngDecoder_Frame_AddRef, 00718 PngDecoder_Frame_Release, 00719 PngDecoder_Frame_GetSize, 00720 PngDecoder_Frame_GetPixelFormat, 00721 PngDecoder_Frame_GetResolution, 00722 PngDecoder_Frame_CopyPalette, 00723 PngDecoder_Frame_CopyPixels, 00724 PngDecoder_Frame_GetMetadataQueryReader, 00725 PngDecoder_Frame_GetColorContexts, 00726 PngDecoder_Frame_GetThumbnail 00727 }; 00728 00729 HRESULT PngDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv) 00730 { 00731 PngDecoder *This; 00732 HRESULT ret; 00733 00734 TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv); 00735 00736 *ppv = NULL; 00737 00738 if (pUnkOuter) return CLASS_E_NOAGGREGATION; 00739 00740 if (!libpng_handle && !load_libpng()) 00741 { 00742 ERR("Failed reading PNG because unable to find %s\n",SONAME_LIBPNG); 00743 return E_FAIL; 00744 } 00745 00746 This = HeapAlloc(GetProcessHeap(), 0, sizeof(PngDecoder)); 00747 if (!This) return E_OUTOFMEMORY; 00748 00749 This->lpVtbl = &PngDecoder_Vtbl; 00750 This->lpFrameVtbl = &PngDecoder_FrameVtbl; 00751 This->ref = 1; 00752 This->png_ptr = NULL; 00753 This->info_ptr = NULL; 00754 This->end_info = NULL; 00755 This->initialized = FALSE; 00756 This->image_bits = NULL; 00757 InitializeCriticalSection(&This->lock); 00758 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PngDecoder.lock"); 00759 00760 ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv); 00761 IUnknown_Release((IUnknown*)This); 00762 00763 return ret; 00764 } 00765 00766 struct png_pixelformat { 00767 const WICPixelFormatGUID *guid; 00768 UINT bpp; 00769 int bit_depth; 00770 int color_type; 00771 BOOL remove_filler; 00772 BOOL swap_rgb; 00773 }; 00774 00775 static const struct png_pixelformat formats[] = { 00776 {&GUID_WICPixelFormat24bppBGR, 24, 8, PNG_COLOR_TYPE_RGB, 0, 1}, 00777 {&GUID_WICPixelFormatBlackWhite, 1, 1, PNG_COLOR_TYPE_GRAY, 0, 0}, 00778 {&GUID_WICPixelFormat2bppGray, 2, 2, PNG_COLOR_TYPE_GRAY, 0, 0}, 00779 {&GUID_WICPixelFormat4bppGray, 4, 4, PNG_COLOR_TYPE_GRAY, 0, 0}, 00780 {&GUID_WICPixelFormat8bppGray, 8, 8, PNG_COLOR_TYPE_GRAY, 0, 0}, 00781 {&GUID_WICPixelFormat16bppGray, 16, 16, PNG_COLOR_TYPE_GRAY, 0, 0}, 00782 {&GUID_WICPixelFormat32bppBGR, 32, 8, PNG_COLOR_TYPE_RGB, 1, 1}, 00783 {&GUID_WICPixelFormat32bppBGRA, 32, 8, PNG_COLOR_TYPE_RGB_ALPHA, 0, 1}, 00784 {&GUID_WICPixelFormat48bppRGB, 48, 16, PNG_COLOR_TYPE_RGB, 0, 0}, 00785 {&GUID_WICPixelFormat64bppRGBA, 64, 16, PNG_COLOR_TYPE_RGB_ALPHA, 0, 0}, 00786 {NULL}, 00787 }; 00788 00789 typedef struct PngEncoder { 00790 const IWICBitmapEncoderVtbl *lpVtbl; 00791 const IWICBitmapFrameEncodeVtbl *lpFrameVtbl; 00792 LONG ref; 00793 IStream *stream; 00794 png_structp png_ptr; 00795 png_infop info_ptr; 00796 UINT frame_count; 00797 BOOL frame_initialized; 00798 const struct png_pixelformat *format; 00799 BOOL info_written; 00800 UINT width, height; 00801 double xres, yres; 00802 UINT lines_written; 00803 BOOL frame_committed; 00804 BOOL committed; 00805 CRITICAL_SECTION lock; 00806 } PngEncoder; 00807 00808 static inline PngEncoder *encoder_from_frame(IWICBitmapFrameEncode *iface) 00809 { 00810 return CONTAINING_RECORD(iface, PngEncoder, lpFrameVtbl); 00811 } 00812 00813 static HRESULT WINAPI PngFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid, 00814 void **ppv) 00815 { 00816 PngEncoder *This = encoder_from_frame(iface); 00817 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 00818 00819 if (!ppv) return E_INVALIDARG; 00820 00821 if (IsEqualIID(&IID_IUnknown, iid) || 00822 IsEqualIID(&IID_IWICBitmapFrameEncode, iid)) 00823 { 00824 *ppv = &This->lpFrameVtbl; 00825 } 00826 else 00827 { 00828 *ppv = NULL; 00829 return E_NOINTERFACE; 00830 } 00831 00832 IUnknown_AddRef((IUnknown*)*ppv); 00833 return S_OK; 00834 } 00835 00836 static ULONG WINAPI PngFrameEncode_AddRef(IWICBitmapFrameEncode *iface) 00837 { 00838 PngEncoder *This = encoder_from_frame(iface); 00839 return IUnknown_AddRef((IUnknown*)This); 00840 } 00841 00842 static ULONG WINAPI PngFrameEncode_Release(IWICBitmapFrameEncode *iface) 00843 { 00844 PngEncoder *This = encoder_from_frame(iface); 00845 return IUnknown_Release((IUnknown*)This); 00846 } 00847 00848 static HRESULT WINAPI PngFrameEncode_Initialize(IWICBitmapFrameEncode *iface, 00849 IPropertyBag2 *pIEncoderOptions) 00850 { 00851 PngEncoder *This = encoder_from_frame(iface); 00852 TRACE("(%p,%p)\n", iface, pIEncoderOptions); 00853 00854 EnterCriticalSection(&This->lock); 00855 00856 if (This->frame_initialized) 00857 { 00858 LeaveCriticalSection(&This->lock); 00859 return WINCODEC_ERR_WRONGSTATE; 00860 } 00861 00862 This->frame_initialized = TRUE; 00863 00864 LeaveCriticalSection(&This->lock); 00865 00866 return S_OK; 00867 } 00868 00869 static HRESULT WINAPI PngFrameEncode_SetSize(IWICBitmapFrameEncode *iface, 00870 UINT uiWidth, UINT uiHeight) 00871 { 00872 PngEncoder *This = encoder_from_frame(iface); 00873 TRACE("(%p,%u,%u)\n", iface, uiWidth, uiHeight); 00874 00875 EnterCriticalSection(&This->lock); 00876 00877 if (!This->frame_initialized || This->info_written) 00878 { 00879 LeaveCriticalSection(&This->lock); 00880 return WINCODEC_ERR_WRONGSTATE; 00881 } 00882 00883 This->width = uiWidth; 00884 This->height = uiHeight; 00885 00886 LeaveCriticalSection(&This->lock); 00887 00888 return S_OK; 00889 } 00890 00891 static HRESULT WINAPI PngFrameEncode_SetResolution(IWICBitmapFrameEncode *iface, 00892 double dpiX, double dpiY) 00893 { 00894 PngEncoder *This = encoder_from_frame(iface); 00895 TRACE("(%p,%0.2f,%0.2f)\n", iface, dpiX, dpiY); 00896 00897 EnterCriticalSection(&This->lock); 00898 00899 if (!This->frame_initialized || This->info_written) 00900 { 00901 LeaveCriticalSection(&This->lock); 00902 return WINCODEC_ERR_WRONGSTATE; 00903 } 00904 00905 This->xres = dpiX; 00906 This->yres = dpiY; 00907 00908 LeaveCriticalSection(&This->lock); 00909 00910 return S_OK; 00911 } 00912 00913 static HRESULT WINAPI PngFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface, 00914 WICPixelFormatGUID *pPixelFormat) 00915 { 00916 PngEncoder *This = encoder_from_frame(iface); 00917 int i; 00918 TRACE("(%p,%s)\n", iface, debugstr_guid(pPixelFormat)); 00919 00920 EnterCriticalSection(&This->lock); 00921 00922 if (!This->frame_initialized || This->info_written) 00923 { 00924 LeaveCriticalSection(&This->lock); 00925 return WINCODEC_ERR_WRONGSTATE; 00926 } 00927 00928 for (i=0; formats[i].guid; i++) 00929 { 00930 if (memcmp(formats[i].guid, pPixelFormat, sizeof(GUID)) == 0) 00931 break; 00932 } 00933 00934 if (!formats[i].guid) i = 0; 00935 00936 This->format = &formats[i]; 00937 memcpy(pPixelFormat, This->format->guid, sizeof(GUID)); 00938 00939 LeaveCriticalSection(&This->lock); 00940 00941 return S_OK; 00942 } 00943 00944 static HRESULT WINAPI PngFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface, 00945 UINT cCount, IWICColorContext **ppIColorContext) 00946 { 00947 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext); 00948 return E_NOTIMPL; 00949 } 00950 00951 static HRESULT WINAPI PngFrameEncode_SetPalette(IWICBitmapFrameEncode *iface, 00952 IWICPalette *pIPalette) 00953 { 00954 FIXME("(%p,%p): stub\n", iface, pIPalette); 00955 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 00956 } 00957 00958 static HRESULT WINAPI PngFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface, 00959 IWICBitmapSource *pIThumbnail) 00960 { 00961 FIXME("(%p,%p): stub\n", iface, pIThumbnail); 00962 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 00963 } 00964 00965 static HRESULT WINAPI PngFrameEncode_WritePixels(IWICBitmapFrameEncode *iface, 00966 UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels) 00967 { 00968 PngEncoder *This = encoder_from_frame(iface); 00969 png_byte **row_pointers=NULL; 00970 UINT i; 00971 jmp_buf jmpbuf; 00972 TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels); 00973 00974 EnterCriticalSection(&This->lock); 00975 00976 if (!This->frame_initialized || !This->width || !This->height || !This->format) 00977 { 00978 LeaveCriticalSection(&This->lock); 00979 return WINCODEC_ERR_WRONGSTATE; 00980 } 00981 00982 if (lineCount == 0 || lineCount + This->lines_written > This->height) 00983 { 00984 LeaveCriticalSection(&This->lock); 00985 return E_INVALIDARG; 00986 } 00987 00988 /* set up setjmp/longjmp error handling */ 00989 if (setjmp(jmpbuf)) 00990 { 00991 LeaveCriticalSection(&This->lock); 00992 HeapFree(GetProcessHeap(), 0, row_pointers); 00993 return E_FAIL; 00994 } 00995 ppng_set_error_fn(This->png_ptr, &jmpbuf, user_error_fn, user_warning_fn); 00996 00997 if (!This->info_written) 00998 { 00999 ppng_set_IHDR(This->png_ptr, This->info_ptr, This->width, This->height, 01000 This->format->bit_depth, This->format->color_type, PNG_INTERLACE_NONE, 01001 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); 01002 01003 if (This->xres != 0.0 && This->yres != 0.0) 01004 { 01005 ppng_set_pHYs(This->png_ptr, This->info_ptr, (This->xres+0.0127) / 0.0254, 01006 (This->yres+0.0127) / 0.0254, PNG_RESOLUTION_METER); 01007 } 01008 01009 ppng_write_info(This->png_ptr, This->info_ptr); 01010 01011 if (This->format->remove_filler) 01012 ppng_set_filler(This->png_ptr, 0, PNG_FILLER_AFTER); 01013 01014 if (This->format->swap_rgb) 01015 ppng_set_bgr(This->png_ptr); 01016 01017 This->info_written = TRUE; 01018 } 01019 01020 row_pointers = HeapAlloc(GetProcessHeap(), 0, lineCount * sizeof(png_byte*)); 01021 if (!row_pointers) 01022 { 01023 LeaveCriticalSection(&This->lock); 01024 return E_OUTOFMEMORY; 01025 } 01026 01027 for (i=0; i<lineCount; i++) 01028 row_pointers[i] = pbPixels + cbStride * i; 01029 01030 ppng_write_rows(This->png_ptr, row_pointers, lineCount); 01031 This->lines_written += lineCount; 01032 01033 LeaveCriticalSection(&This->lock); 01034 01035 HeapFree(GetProcessHeap(), 0, row_pointers); 01036 01037 return S_OK; 01038 } 01039 01040 static HRESULT WINAPI PngFrameEncode_WriteSource(IWICBitmapFrameEncode *iface, 01041 IWICBitmapSource *pIBitmapSource, WICRect *prc) 01042 { 01043 PngEncoder *This = encoder_from_frame(iface); 01044 HRESULT hr; 01045 WICRect rc; 01046 WICPixelFormatGUID guid; 01047 UINT stride; 01048 BYTE *pixeldata; 01049 TRACE("(%p,%p,%p)\n", iface, pIBitmapSource, prc); 01050 01051 if (!This->frame_initialized || !This->width || !This->height) 01052 return WINCODEC_ERR_WRONGSTATE; 01053 01054 if (!This->format) 01055 { 01056 hr = IWICBitmapSource_GetPixelFormat(pIBitmapSource, &guid); 01057 if (FAILED(hr)) return hr; 01058 hr = IWICBitmapFrameEncode_SetPixelFormat(iface, &guid); 01059 if (FAILED(hr)) return hr; 01060 } 01061 01062 hr = IWICBitmapSource_GetPixelFormat(pIBitmapSource, &guid); 01063 if (FAILED(hr)) return hr; 01064 if (memcmp(&guid, This->format->guid, sizeof(GUID)) != 0) 01065 { 01066 /* FIXME: should use WICConvertBitmapSource to convert */ 01067 ERR("format %s unsupported\n", debugstr_guid(&guid)); 01068 return E_FAIL; 01069 } 01070 01071 if (This->xres == 0.0 || This->yres == 0.0) 01072 { 01073 double xres, yres; 01074 hr = IWICBitmapSource_GetResolution(pIBitmapSource, &xres, &yres); 01075 if (FAILED(hr)) return hr; 01076 hr = IWICBitmapFrameEncode_SetResolution(iface, xres, yres); 01077 if (FAILED(hr)) return hr; 01078 } 01079 01080 if (!prc) 01081 { 01082 UINT width, height; 01083 hr = IWICBitmapSource_GetSize(pIBitmapSource, &width, &height); 01084 if (FAILED(hr)) return hr; 01085 rc.X = 0; 01086 rc.Y = 0; 01087 rc.Width = width; 01088 rc.Height = height; 01089 prc = &rc; 01090 } 01091 01092 if (prc->Width != This->width) return E_INVALIDARG; 01093 01094 stride = (This->format->bpp * This->width + 7)/8; 01095 01096 pixeldata = HeapAlloc(GetProcessHeap(), 0, stride * prc->Height); 01097 if (!pixeldata) return E_OUTOFMEMORY; 01098 01099 hr = IWICBitmapSource_CopyPixels(pIBitmapSource, prc, stride, 01100 stride*prc->Height, pixeldata); 01101 01102 if (SUCCEEDED(hr)) 01103 { 01104 hr = IWICBitmapFrameEncode_WritePixels(iface, prc->Height, stride, 01105 stride*prc->Height, pixeldata); 01106 } 01107 01108 HeapFree(GetProcessHeap(), 0, pixeldata); 01109 01110 return hr; 01111 } 01112 01113 static HRESULT WINAPI PngFrameEncode_Commit(IWICBitmapFrameEncode *iface) 01114 { 01115 PngEncoder *This = encoder_from_frame(iface); 01116 jmp_buf jmpbuf; 01117 TRACE("(%p)\n", iface); 01118 01119 EnterCriticalSection(&This->lock); 01120 01121 if (!This->info_written || This->lines_written != This->height || This->frame_committed) 01122 { 01123 LeaveCriticalSection(&This->lock); 01124 return WINCODEC_ERR_WRONGSTATE; 01125 } 01126 01127 /* set up setjmp/longjmp error handling */ 01128 if (setjmp(jmpbuf)) 01129 { 01130 LeaveCriticalSection(&This->lock); 01131 return E_FAIL; 01132 } 01133 ppng_set_error_fn(This->png_ptr, &jmpbuf, user_error_fn, user_warning_fn); 01134 01135 ppng_write_end(This->png_ptr, This->info_ptr); 01136 01137 This->frame_committed = TRUE; 01138 01139 LeaveCriticalSection(&This->lock); 01140 01141 return S_OK; 01142 } 01143 01144 static HRESULT WINAPI PngFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface, 01145 IWICMetadataQueryWriter **ppIMetadataQueryWriter) 01146 { 01147 FIXME("(%p, %p): stub\n", iface, ppIMetadataQueryWriter); 01148 return E_NOTIMPL; 01149 } 01150 01151 static const IWICBitmapFrameEncodeVtbl PngEncoder_FrameVtbl = { 01152 PngFrameEncode_QueryInterface, 01153 PngFrameEncode_AddRef, 01154 PngFrameEncode_Release, 01155 PngFrameEncode_Initialize, 01156 PngFrameEncode_SetSize, 01157 PngFrameEncode_SetResolution, 01158 PngFrameEncode_SetPixelFormat, 01159 PngFrameEncode_SetColorContexts, 01160 PngFrameEncode_SetPalette, 01161 PngFrameEncode_SetThumbnail, 01162 PngFrameEncode_WritePixels, 01163 PngFrameEncode_WriteSource, 01164 PngFrameEncode_Commit, 01165 PngFrameEncode_GetMetadataQueryWriter 01166 }; 01167 01168 static HRESULT WINAPI PngEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid, 01169 void **ppv) 01170 { 01171 PngEncoder *This = (PngEncoder*)iface; 01172 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 01173 01174 if (!ppv) return E_INVALIDARG; 01175 01176 if (IsEqualIID(&IID_IUnknown, iid) || 01177 IsEqualIID(&IID_IWICBitmapEncoder, iid)) 01178 { 01179 *ppv = This; 01180 } 01181 else 01182 { 01183 *ppv = NULL; 01184 return E_NOINTERFACE; 01185 } 01186 01187 IUnknown_AddRef((IUnknown*)*ppv); 01188 return S_OK; 01189 } 01190 01191 static ULONG WINAPI PngEncoder_AddRef(IWICBitmapEncoder *iface) 01192 { 01193 PngEncoder *This = (PngEncoder*)iface; 01194 ULONG ref = InterlockedIncrement(&This->ref); 01195 01196 TRACE("(%p) refcount=%u\n", iface, ref); 01197 01198 return ref; 01199 } 01200 01201 static ULONG WINAPI PngEncoder_Release(IWICBitmapEncoder *iface) 01202 { 01203 PngEncoder *This = (PngEncoder*)iface; 01204 ULONG ref = InterlockedDecrement(&This->ref); 01205 01206 TRACE("(%p) refcount=%u\n", iface, ref); 01207 01208 if (ref == 0) 01209 { 01210 This->lock.DebugInfo->Spare[0] = 0; 01211 DeleteCriticalSection(&This->lock); 01212 if (This->png_ptr) 01213 ppng_destroy_write_struct(&This->png_ptr, &This->info_ptr); 01214 if (This->stream) 01215 IStream_Release(This->stream); 01216 HeapFree(GetProcessHeap(), 0, This); 01217 } 01218 01219 return ref; 01220 } 01221 01222 static void user_write_data(png_structp png_ptr, png_bytep data, png_size_t length) 01223 { 01224 PngEncoder *This = ppng_get_io_ptr(png_ptr); 01225 HRESULT hr; 01226 ULONG byteswritten; 01227 01228 hr = IStream_Write(This->stream, data, length, &byteswritten); 01229 if (FAILED(hr) || byteswritten != length) 01230 { 01231 ppng_error(png_ptr, "failed writing data"); 01232 } 01233 } 01234 01235 static void user_flush(png_structp png_ptr) 01236 { 01237 } 01238 01239 static HRESULT WINAPI PngEncoder_Initialize(IWICBitmapEncoder *iface, 01240 IStream *pIStream, WICBitmapEncoderCacheOption cacheOption) 01241 { 01242 PngEncoder *This = (PngEncoder*)iface; 01243 jmp_buf jmpbuf; 01244 01245 TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOption); 01246 01247 EnterCriticalSection(&This->lock); 01248 01249 if (This->png_ptr) 01250 { 01251 LeaveCriticalSection(&This->lock); 01252 return WINCODEC_ERR_WRONGSTATE; 01253 } 01254 01255 /* initialize libpng */ 01256 This->png_ptr = ppng_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 01257 if (!This->png_ptr) 01258 { 01259 LeaveCriticalSection(&This->lock); 01260 return E_FAIL; 01261 } 01262 01263 This->info_ptr = ppng_create_info_struct(This->png_ptr); 01264 if (!This->info_ptr) 01265 { 01266 ppng_destroy_write_struct(&This->png_ptr, NULL); 01267 This->png_ptr = NULL; 01268 LeaveCriticalSection(&This->lock); 01269 return E_FAIL; 01270 } 01271 01272 IStream_AddRef(pIStream); 01273 This->stream = pIStream; 01274 01275 /* set up setjmp/longjmp error handling */ 01276 if (setjmp(jmpbuf)) 01277 { 01278 ppng_destroy_write_struct(&This->png_ptr, &This->info_ptr); 01279 This->png_ptr = NULL; 01280 IStream_Release(This->stream); 01281 This->stream = NULL; 01282 LeaveCriticalSection(&This->lock); 01283 return E_FAIL; 01284 } 01285 ppng_set_error_fn(This->png_ptr, &jmpbuf, user_error_fn, user_warning_fn); 01286 01287 /* set up custom i/o handling */ 01288 ppng_set_write_fn(This->png_ptr, This, user_write_data, user_flush); 01289 01290 LeaveCriticalSection(&This->lock); 01291 01292 return S_OK; 01293 } 01294 01295 static HRESULT WINAPI PngEncoder_GetContainerFormat(IWICBitmapEncoder *iface, 01296 GUID *pguidContainerFormat) 01297 { 01298 FIXME("(%p,%s): stub\n", iface, debugstr_guid(pguidContainerFormat)); 01299 return E_NOTIMPL; 01300 } 01301 01302 static HRESULT WINAPI PngEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, 01303 IWICBitmapEncoderInfo **ppIEncoderInfo) 01304 { 01305 FIXME("(%p,%p): stub\n", iface, ppIEncoderInfo); 01306 return E_NOTIMPL; 01307 } 01308 01309 static HRESULT WINAPI PngEncoder_SetColorContexts(IWICBitmapEncoder *iface, 01310 UINT cCount, IWICColorContext **ppIColorContext) 01311 { 01312 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext); 01313 return E_NOTIMPL; 01314 } 01315 01316 static HRESULT WINAPI PngEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *pIPalette) 01317 { 01318 TRACE("(%p,%p)\n", iface, pIPalette); 01319 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 01320 } 01321 01322 static HRESULT WINAPI PngEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail) 01323 { 01324 TRACE("(%p,%p)\n", iface, pIThumbnail); 01325 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 01326 } 01327 01328 static HRESULT WINAPI PngEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview) 01329 { 01330 TRACE("(%p,%p)\n", iface, pIPreview); 01331 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 01332 } 01333 01334 static HRESULT WINAPI PngEncoder_CreateNewFrame(IWICBitmapEncoder *iface, 01335 IWICBitmapFrameEncode **ppIFrameEncode, IPropertyBag2 **ppIEncoderOptions) 01336 { 01337 PngEncoder *This = (PngEncoder*)iface; 01338 HRESULT hr; 01339 TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions); 01340 01341 EnterCriticalSection(&This->lock); 01342 01343 if (This->frame_count != 0) 01344 { 01345 LeaveCriticalSection(&This->lock); 01346 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 01347 } 01348 01349 if (!This->stream) 01350 { 01351 LeaveCriticalSection(&This->lock); 01352 return WINCODEC_ERR_NOTINITIALIZED; 01353 } 01354 01355 hr = CreatePropertyBag2(ppIEncoderOptions); 01356 if (FAILED(hr)) 01357 { 01358 LeaveCriticalSection(&This->lock); 01359 return hr; 01360 } 01361 01362 This->frame_count = 1; 01363 01364 LeaveCriticalSection(&This->lock); 01365 01366 IWICBitmapEncoder_AddRef(iface); 01367 *ppIFrameEncode = (IWICBitmapFrameEncode*)&This->lpFrameVtbl; 01368 01369 return S_OK; 01370 } 01371 01372 static HRESULT WINAPI PngEncoder_Commit(IWICBitmapEncoder *iface) 01373 { 01374 PngEncoder *This = (PngEncoder*)iface; 01375 TRACE("(%p)\n", iface); 01376 01377 EnterCriticalSection(&This->lock); 01378 01379 if (!This->frame_committed || This->committed) 01380 { 01381 LeaveCriticalSection(&This->lock); 01382 return WINCODEC_ERR_WRONGSTATE; 01383 } 01384 01385 This->committed = TRUE; 01386 01387 LeaveCriticalSection(&This->lock); 01388 01389 return S_OK; 01390 } 01391 01392 static HRESULT WINAPI PngEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface, 01393 IWICMetadataQueryWriter **ppIMetadataQueryWriter) 01394 { 01395 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter); 01396 return E_NOTIMPL; 01397 } 01398 01399 static const IWICBitmapEncoderVtbl PngEncoder_Vtbl = { 01400 PngEncoder_QueryInterface, 01401 PngEncoder_AddRef, 01402 PngEncoder_Release, 01403 PngEncoder_Initialize, 01404 PngEncoder_GetContainerFormat, 01405 PngEncoder_GetEncoderInfo, 01406 PngEncoder_SetColorContexts, 01407 PngEncoder_SetPalette, 01408 PngEncoder_SetThumbnail, 01409 PngEncoder_SetPreview, 01410 PngEncoder_CreateNewFrame, 01411 PngEncoder_Commit, 01412 PngEncoder_GetMetadataQueryWriter 01413 }; 01414 01415 HRESULT PngEncoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv) 01416 { 01417 PngEncoder *This; 01418 HRESULT ret; 01419 01420 TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv); 01421 01422 *ppv = NULL; 01423 01424 if (pUnkOuter) return CLASS_E_NOAGGREGATION; 01425 01426 if (!libpng_handle && !load_libpng()) 01427 { 01428 ERR("Failed writing PNG because unable to find %s\n",SONAME_LIBPNG); 01429 return E_FAIL; 01430 } 01431 01432 This = HeapAlloc(GetProcessHeap(), 0, sizeof(PngEncoder)); 01433 if (!This) return E_OUTOFMEMORY; 01434 01435 This->lpVtbl = &PngEncoder_Vtbl; 01436 This->lpFrameVtbl = &PngEncoder_FrameVtbl; 01437 This->ref = 1; 01438 This->png_ptr = NULL; 01439 This->info_ptr = NULL; 01440 This->stream = NULL; 01441 This->frame_count = 0; 01442 This->frame_initialized = FALSE; 01443 This->format = NULL; 01444 This->info_written = FALSE; 01445 This->width = 0; 01446 This->height = 0; 01447 This->xres = 0.0; 01448 This->yres = 0.0; 01449 This->lines_written = 0; 01450 This->frame_committed = FALSE; 01451 This->committed = FALSE; 01452 InitializeCriticalSection(&This->lock); 01453 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PngEncoder.lock"); 01454 01455 ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv); 01456 IUnknown_Release((IUnknown*)This); 01457 01458 return ret; 01459 } 01460 01461 #else /* !HAVE_PNG_H */ 01462 01463 HRESULT PngDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv) 01464 { 01465 ERR("Trying to load PNG picture, but PNG support is not compiled in.\n"); 01466 return E_FAIL; 01467 } 01468 01469 HRESULT PngEncoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv) 01470 { 01471 ERR("Trying to save PNG picture, but PNG support is not compiled in.\n"); 01472 return E_FAIL; 01473 } 01474 01475 #endif Generated on Sat May 26 2012 04:25:25 for ReactOS by
1.7.6.1
|