ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

pngformat.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.