1 /* 2 * Copyright 2009 Vincent Povirk for CodeWeavers 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 */ 18 19 #include "config.h" 20 #include "wine/port.h" 21 22 #ifdef HAVE_UNISTD_H 23 # include <unistd.h> 24 #endif 25 #include <stdarg.h> 26 #include <stdio.h> 27 #include <string.h> 28 #include <setjmp.h> 29 30 #ifdef SONAME_LIBJPEG 31 /* This is a hack, so jpeglib.h does not redefine INT32 and the like*/ 32 #define XMD_H 33 #define UINT8 JPEG_UINT8 34 #define UINT16 JPEG_UINT16 35 #define boolean jpeg_boolean 36 #undef HAVE_STDLIB_H 37 # include <jpeglib.h> 38 #undef HAVE_STDLIB_H 39 #define HAVE_STDLIB_H 1 40 #undef UINT8 41 #undef UINT16 42 #undef boolean 43 #endif 44 45 #define COBJMACROS 46 47 #include "windef.h" 48 #include "winbase.h" 49 #include "objbase.h" 50 51 #include "wincodecs_private.h" 52 53 #include "wine/heap.h" 54 #include "wine/debug.h" 55 #include "wine/library.h" 56 57 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); 58 59 #ifdef SONAME_LIBJPEG 60 WINE_DECLARE_DEBUG_CHANNEL(jpeg); 61 62 static void *libjpeg_handle; 63 64 static const WCHAR wszImageQuality[] = {'I','m','a','g','e','Q','u','a','l','i','t','y',0}; 65 static const WCHAR wszBitmapTransform[] = {'B','i','t','m','a','p','T','r','a','n','s','f','o','r','m',0}; 66 static const WCHAR wszLuminance[] = {'L','u','m','i','n','a','n','c','e',0}; 67 static const WCHAR wszChrominance[] = {'C','h','r','o','m','i','n','a','n','c','e',0}; 68 static const WCHAR wszJpegYCrCbSubsampling[] = {'J','p','e','g','Y','C','r','C','b','S','u','b','s','a','m','p','l','i','n','g',0}; 69 static const WCHAR wszSuppressApp0[] = {'S','u','p','p','r','e','s','s','A','p','p','0',0}; 70 71 #define MAKE_FUNCPTR(f) static typeof(f) * p##f 72 MAKE_FUNCPTR(jpeg_CreateCompress); 73 MAKE_FUNCPTR(jpeg_CreateDecompress); 74 MAKE_FUNCPTR(jpeg_destroy_compress); 75 MAKE_FUNCPTR(jpeg_destroy_decompress); 76 MAKE_FUNCPTR(jpeg_finish_compress); 77 MAKE_FUNCPTR(jpeg_read_header); 78 MAKE_FUNCPTR(jpeg_read_scanlines); 79 MAKE_FUNCPTR(jpeg_resync_to_restart); 80 MAKE_FUNCPTR(jpeg_set_defaults); 81 MAKE_FUNCPTR(jpeg_start_compress); 82 MAKE_FUNCPTR(jpeg_start_decompress); 83 MAKE_FUNCPTR(jpeg_std_error); 84 MAKE_FUNCPTR(jpeg_write_scanlines); 85 #undef MAKE_FUNCPTR 86 87 static void *load_libjpeg(void) 88 { 89 if((libjpeg_handle = wine_dlopen(SONAME_LIBJPEG, RTLD_NOW, NULL, 0)) != NULL) { 90 91 #define LOAD_FUNCPTR(f) \ 92 if((p##f = wine_dlsym(libjpeg_handle, #f, NULL, 0)) == NULL) { \ 93 libjpeg_handle = NULL; \ 94 return NULL; \ 95 } 96 97 LOAD_FUNCPTR(jpeg_CreateCompress); 98 LOAD_FUNCPTR(jpeg_CreateDecompress); 99 LOAD_FUNCPTR(jpeg_destroy_compress); 100 LOAD_FUNCPTR(jpeg_destroy_decompress); 101 LOAD_FUNCPTR(jpeg_finish_compress); 102 LOAD_FUNCPTR(jpeg_read_header); 103 LOAD_FUNCPTR(jpeg_read_scanlines); 104 LOAD_FUNCPTR(jpeg_resync_to_restart); 105 LOAD_FUNCPTR(jpeg_set_defaults); 106 LOAD_FUNCPTR(jpeg_start_compress); 107 LOAD_FUNCPTR(jpeg_start_decompress); 108 LOAD_FUNCPTR(jpeg_std_error); 109 LOAD_FUNCPTR(jpeg_write_scanlines); 110 #undef LOAD_FUNCPTR 111 } 112 return libjpeg_handle; 113 } 114 115 static void error_exit_fn(j_common_ptr cinfo) 116 { 117 char message[JMSG_LENGTH_MAX]; 118 if (ERR_ON(jpeg)) 119 { 120 cinfo->err->format_message(cinfo, message); 121 ERR_(jpeg)("%s\n", message); 122 } 123 longjmp(*(jmp_buf*)cinfo->client_data, 1); 124 } 125 126 static void emit_message_fn(j_common_ptr cinfo, int msg_level) 127 { 128 char message[JMSG_LENGTH_MAX]; 129 130 if (msg_level < 0 && ERR_ON(jpeg)) 131 { 132 cinfo->err->format_message(cinfo, message); 133 ERR_(jpeg)("%s\n", message); 134 } 135 else if (msg_level == 0 && WARN_ON(jpeg)) 136 { 137 cinfo->err->format_message(cinfo, message); 138 WARN_(jpeg)("%s\n", message); 139 } 140 else if (msg_level > 0 && TRACE_ON(jpeg)) 141 { 142 cinfo->err->format_message(cinfo, message); 143 TRACE_(jpeg)("%s\n", message); 144 } 145 } 146 147 typedef struct { 148 IWICBitmapDecoder IWICBitmapDecoder_iface; 149 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface; 150 IWICMetadataBlockReader IWICMetadataBlockReader_iface; 151 LONG ref; 152 BOOL initialized; 153 BOOL cinfo_initialized; 154 IStream *stream; 155 struct jpeg_decompress_struct cinfo; 156 struct jpeg_error_mgr jerr; 157 struct jpeg_source_mgr source_mgr; 158 BYTE source_buffer[1024]; 159 UINT bpp, stride; 160 BYTE *image_data; 161 CRITICAL_SECTION lock; 162 } JpegDecoder; 163 164 static inline JpegDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface) 165 { 166 return CONTAINING_RECORD(iface, JpegDecoder, IWICBitmapDecoder_iface); 167 } 168 169 static inline JpegDecoder *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface) 170 { 171 return CONTAINING_RECORD(iface, JpegDecoder, IWICBitmapFrameDecode_iface); 172 } 173 174 static inline JpegDecoder *decoder_from_decompress(j_decompress_ptr decompress) 175 { 176 return CONTAINING_RECORD(decompress, JpegDecoder, cinfo); 177 } 178 179 static inline JpegDecoder *impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface) 180 { 181 return CONTAINING_RECORD(iface, JpegDecoder, IWICMetadataBlockReader_iface); 182 } 183 184 static HRESULT WINAPI JpegDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid, 185 void **ppv) 186 { 187 JpegDecoder *This = impl_from_IWICBitmapDecoder(iface); 188 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 189 190 if (!ppv) return E_INVALIDARG; 191 192 if (IsEqualIID(&IID_IUnknown, iid) || 193 IsEqualIID(&IID_IWICBitmapDecoder, iid)) 194 { 195 *ppv = &This->IWICBitmapDecoder_iface; 196 } 197 else 198 { 199 *ppv = NULL; 200 return E_NOINTERFACE; 201 } 202 203 IUnknown_AddRef((IUnknown*)*ppv); 204 return S_OK; 205 } 206 207 static ULONG WINAPI JpegDecoder_AddRef(IWICBitmapDecoder *iface) 208 { 209 JpegDecoder *This = impl_from_IWICBitmapDecoder(iface); 210 ULONG ref = InterlockedIncrement(&This->ref); 211 212 TRACE("(%p) refcount=%u\n", iface, ref); 213 214 return ref; 215 } 216 217 static ULONG WINAPI JpegDecoder_Release(IWICBitmapDecoder *iface) 218 { 219 JpegDecoder *This = impl_from_IWICBitmapDecoder(iface); 220 ULONG ref = InterlockedDecrement(&This->ref); 221 222 TRACE("(%p) refcount=%u\n", iface, ref); 223 224 if (ref == 0) 225 { 226 This->lock.DebugInfo->Spare[0] = 0; 227 DeleteCriticalSection(&This->lock); 228 if (This->cinfo_initialized) pjpeg_destroy_decompress(&This->cinfo); 229 if (This->stream) IStream_Release(This->stream); 230 HeapFree(GetProcessHeap(), 0, This->image_data); 231 HeapFree(GetProcessHeap(), 0, This); 232 } 233 234 return ref; 235 } 236 237 static HRESULT WINAPI JpegDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream, 238 DWORD *capability) 239 { 240 HRESULT hr; 241 242 TRACE("(%p,%p,%p)\n", iface, stream, capability); 243 244 if (!stream || !capability) return E_INVALIDARG; 245 246 hr = IWICBitmapDecoder_Initialize(iface, stream, WICDecodeMetadataCacheOnDemand); 247 if (hr != S_OK) return hr; 248 249 *capability = WICBitmapDecoderCapabilityCanDecodeAllImages | 250 WICBitmapDecoderCapabilityCanDecodeSomeImages; 251 /* FIXME: WICBitmapDecoderCapabilityCanEnumerateMetadata */ 252 return S_OK; 253 } 254 255 static void source_mgr_init_source(j_decompress_ptr cinfo) 256 { 257 } 258 259 static jpeg_boolean source_mgr_fill_input_buffer(j_decompress_ptr cinfo) 260 { 261 JpegDecoder *This = decoder_from_decompress(cinfo); 262 HRESULT hr; 263 ULONG bytesread; 264 265 hr = IStream_Read(This->stream, This->source_buffer, 1024, &bytesread); 266 267 if (FAILED(hr) || bytesread == 0) 268 { 269 return FALSE; 270 } 271 else 272 { 273 This->source_mgr.next_input_byte = This->source_buffer; 274 This->source_mgr.bytes_in_buffer = bytesread; 275 return TRUE; 276 } 277 } 278 279 static void source_mgr_skip_input_data(j_decompress_ptr cinfo, long num_bytes) 280 { 281 JpegDecoder *This = decoder_from_decompress(cinfo); 282 LARGE_INTEGER seek; 283 284 if (num_bytes > This->source_mgr.bytes_in_buffer) 285 { 286 seek.QuadPart = num_bytes - This->source_mgr.bytes_in_buffer; 287 IStream_Seek(This->stream, seek, STREAM_SEEK_CUR, NULL); 288 This->source_mgr.bytes_in_buffer = 0; 289 } 290 else if (num_bytes > 0) 291 { 292 This->source_mgr.next_input_byte += num_bytes; 293 This->source_mgr.bytes_in_buffer -= num_bytes; 294 } 295 } 296 297 static void source_mgr_term_source(j_decompress_ptr cinfo) 298 { 299 } 300 301 static HRESULT WINAPI JpegDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream, 302 WICDecodeOptions cacheOptions) 303 { 304 JpegDecoder *This = impl_from_IWICBitmapDecoder(iface); 305 int ret; 306 LARGE_INTEGER seek; 307 jmp_buf jmpbuf; 308 UINT data_size, i; 309 310 TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOptions); 311 312 EnterCriticalSection(&This->lock); 313 314 if (This->cinfo_initialized) 315 { 316 LeaveCriticalSection(&This->lock); 317 return WINCODEC_ERR_WRONGSTATE; 318 } 319 320 pjpeg_std_error(&This->jerr); 321 322 This->jerr.error_exit = error_exit_fn; 323 This->jerr.emit_message = emit_message_fn; 324 325 This->cinfo.err = &This->jerr; 326 327 This->cinfo.client_data = jmpbuf; 328 329 if (setjmp(jmpbuf)) 330 { 331 LeaveCriticalSection(&This->lock); 332 return E_FAIL; 333 } 334 335 pjpeg_CreateDecompress(&This->cinfo, JPEG_LIB_VERSION, sizeof(struct jpeg_decompress_struct)); 336 337 This->cinfo_initialized = TRUE; 338 339 This->stream = pIStream; 340 IStream_AddRef(pIStream); 341 342 seek.QuadPart = 0; 343 IStream_Seek(This->stream, seek, STREAM_SEEK_SET, NULL); 344 345 This->source_mgr.bytes_in_buffer = 0; 346 This->source_mgr.init_source = source_mgr_init_source; 347 This->source_mgr.fill_input_buffer = source_mgr_fill_input_buffer; 348 This->source_mgr.skip_input_data = source_mgr_skip_input_data; 349 This->source_mgr.resync_to_restart = pjpeg_resync_to_restart; 350 This->source_mgr.term_source = source_mgr_term_source; 351 352 This->cinfo.src = &This->source_mgr; 353 354 ret = pjpeg_read_header(&This->cinfo, TRUE); 355 356 if (ret != JPEG_HEADER_OK) { 357 WARN("Jpeg image in stream has bad format, read header returned %d.\n",ret); 358 LeaveCriticalSection(&This->lock); 359 return E_FAIL; 360 } 361 362 switch (This->cinfo.jpeg_color_space) 363 { 364 case JCS_GRAYSCALE: 365 This->cinfo.out_color_space = JCS_GRAYSCALE; 366 break; 367 case JCS_RGB: 368 case JCS_YCbCr: 369 This->cinfo.out_color_space = JCS_RGB; 370 break; 371 case JCS_CMYK: 372 case JCS_YCCK: 373 This->cinfo.out_color_space = JCS_CMYK; 374 break; 375 default: 376 ERR("Unknown JPEG color space %i\n", This->cinfo.jpeg_color_space); 377 LeaveCriticalSection(&This->lock); 378 return E_FAIL; 379 } 380 381 if (!pjpeg_start_decompress(&This->cinfo)) 382 { 383 ERR("jpeg_start_decompress failed\n"); 384 LeaveCriticalSection(&This->lock); 385 return E_FAIL; 386 } 387 388 if (This->cinfo.out_color_space == JCS_GRAYSCALE) This->bpp = 8; 389 else if (This->cinfo.out_color_space == JCS_CMYK) This->bpp = 32; 390 else This->bpp = 24; 391 392 This->stride = (This->bpp * This->cinfo.output_width + 7) / 8; 393 data_size = This->stride * This->cinfo.output_height; 394 395 This->image_data = heap_alloc(data_size); 396 if (!This->image_data) 397 { 398 LeaveCriticalSection(&This->lock); 399 return E_OUTOFMEMORY; 400 } 401 402 while (This->cinfo.output_scanline < This->cinfo.output_height) 403 { 404 UINT first_scanline = This->cinfo.output_scanline; 405 UINT max_rows; 406 JSAMPROW out_rows[4]; 407 JDIMENSION ret; 408 409 max_rows = min(This->cinfo.output_height-first_scanline, 4); 410 for (i=0; i<max_rows; i++) 411 out_rows[i] = This->image_data + This->stride * (first_scanline+i); 412 413 ret = pjpeg_read_scanlines(&This->cinfo, out_rows, max_rows); 414 if (ret == 0) 415 { 416 ERR("read_scanlines failed\n"); 417 LeaveCriticalSection(&This->lock); 418 return E_FAIL; 419 } 420 } 421 422 if (This->bpp == 24) 423 { 424 /* libjpeg gives us RGB data and we want BGR, so byteswap the data */ 425 reverse_bgr8(3, This->image_data, 426 This->cinfo.output_width, This->cinfo.output_height, 427 This->stride); 428 } 429 430 if (This->cinfo.out_color_space == JCS_CMYK && This->cinfo.saw_Adobe_marker) 431 { 432 /* Adobe JPEG's have inverted CMYK data. */ 433 for (i=0; i<data_size; i++) 434 This->image_data[i] ^= 0xff; 435 } 436 437 This->initialized = TRUE; 438 439 LeaveCriticalSection(&This->lock); 440 441 return S_OK; 442 } 443 444 static HRESULT WINAPI JpegDecoder_GetContainerFormat(IWICBitmapDecoder *iface, 445 GUID *pguidContainerFormat) 446 { 447 memcpy(pguidContainerFormat, &GUID_ContainerFormatJpeg, sizeof(GUID)); 448 return S_OK; 449 } 450 451 static HRESULT WINAPI JpegDecoder_GetDecoderInfo(IWICBitmapDecoder *iface, 452 IWICBitmapDecoderInfo **ppIDecoderInfo) 453 { 454 TRACE("(%p,%p)\n", iface, ppIDecoderInfo); 455 456 return get_decoder_info(&CLSID_WICJpegDecoder, ppIDecoderInfo); 457 } 458 459 static HRESULT WINAPI JpegDecoder_CopyPalette(IWICBitmapDecoder *iface, 460 IWICPalette *pIPalette) 461 { 462 TRACE("(%p,%p)\n", iface, pIPalette); 463 464 return WINCODEC_ERR_PALETTEUNAVAILABLE; 465 } 466 467 static HRESULT WINAPI JpegDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface, 468 IWICMetadataQueryReader **reader) 469 { 470 TRACE("(%p,%p)\n", iface, reader); 471 472 if (!reader) return E_INVALIDARG; 473 474 *reader = NULL; 475 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 476 } 477 478 static HRESULT WINAPI JpegDecoder_GetPreview(IWICBitmapDecoder *iface, 479 IWICBitmapSource **ppIBitmapSource) 480 { 481 FIXME("(%p,%p): stub\n", iface, ppIBitmapSource); 482 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 483 } 484 485 static HRESULT WINAPI JpegDecoder_GetColorContexts(IWICBitmapDecoder *iface, 486 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) 487 { 488 FIXME("(%p,%u,%p,%p): stub\n", iface, cCount, ppIColorContexts, pcActualCount); 489 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 490 } 491 492 static HRESULT WINAPI JpegDecoder_GetThumbnail(IWICBitmapDecoder *iface, 493 IWICBitmapSource **ppIThumbnail) 494 { 495 FIXME("(%p,%p): stub\n", iface, ppIThumbnail); 496 return WINCODEC_ERR_CODECNOTHUMBNAIL; 497 } 498 499 static HRESULT WINAPI JpegDecoder_GetFrameCount(IWICBitmapDecoder *iface, 500 UINT *pCount) 501 { 502 if (!pCount) return E_INVALIDARG; 503 504 *pCount = 1; 505 return S_OK; 506 } 507 508 static HRESULT WINAPI JpegDecoder_GetFrame(IWICBitmapDecoder *iface, 509 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame) 510 { 511 JpegDecoder *This = impl_from_IWICBitmapDecoder(iface); 512 TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame); 513 514 if (!This->initialized) return WINCODEC_ERR_FRAMEMISSING; 515 516 if (index != 0) return E_INVALIDARG; 517 518 IWICBitmapDecoder_AddRef(iface); 519 *ppIBitmapFrame = &This->IWICBitmapFrameDecode_iface; 520 521 return S_OK; 522 } 523 524 static const IWICBitmapDecoderVtbl JpegDecoder_Vtbl = { 525 JpegDecoder_QueryInterface, 526 JpegDecoder_AddRef, 527 JpegDecoder_Release, 528 JpegDecoder_QueryCapability, 529 JpegDecoder_Initialize, 530 JpegDecoder_GetContainerFormat, 531 JpegDecoder_GetDecoderInfo, 532 JpegDecoder_CopyPalette, 533 JpegDecoder_GetMetadataQueryReader, 534 JpegDecoder_GetPreview, 535 JpegDecoder_GetColorContexts, 536 JpegDecoder_GetThumbnail, 537 JpegDecoder_GetFrameCount, 538 JpegDecoder_GetFrame 539 }; 540 541 static HRESULT WINAPI JpegDecoder_Frame_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid, 542 void **ppv) 543 { 544 JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 545 546 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 547 548 if (!ppv) return E_INVALIDARG; 549 550 if (IsEqualIID(&IID_IUnknown, iid) || 551 IsEqualIID(&IID_IWICBitmapSource, iid) || 552 IsEqualIID(&IID_IWICBitmapFrameDecode, iid)) 553 { 554 *ppv = &This->IWICBitmapFrameDecode_iface; 555 } 556 else 557 { 558 *ppv = NULL; 559 return E_NOINTERFACE; 560 } 561 562 IUnknown_AddRef((IUnknown*)*ppv); 563 return S_OK; 564 } 565 566 static ULONG WINAPI JpegDecoder_Frame_AddRef(IWICBitmapFrameDecode *iface) 567 { 568 JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 569 return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface); 570 } 571 572 static ULONG WINAPI JpegDecoder_Frame_Release(IWICBitmapFrameDecode *iface) 573 { 574 JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 575 return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface); 576 } 577 578 static HRESULT WINAPI JpegDecoder_Frame_GetSize(IWICBitmapFrameDecode *iface, 579 UINT *puiWidth, UINT *puiHeight) 580 { 581 JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 582 *puiWidth = This->cinfo.output_width; 583 *puiHeight = This->cinfo.output_height; 584 TRACE("(%p)->(%u,%u)\n", iface, *puiWidth, *puiHeight); 585 return S_OK; 586 } 587 588 static HRESULT WINAPI JpegDecoder_Frame_GetPixelFormat(IWICBitmapFrameDecode *iface, 589 WICPixelFormatGUID *pPixelFormat) 590 { 591 JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 592 TRACE("(%p,%p)\n", iface, pPixelFormat); 593 if (This->cinfo.out_color_space == JCS_RGB) 594 memcpy(pPixelFormat, &GUID_WICPixelFormat24bppBGR, sizeof(GUID)); 595 else if (This->cinfo.out_color_space == JCS_CMYK) 596 memcpy(pPixelFormat, &GUID_WICPixelFormat32bppCMYK, sizeof(GUID)); 597 else /* This->cinfo.out_color_space == JCS_GRAYSCALE */ 598 memcpy(pPixelFormat, &GUID_WICPixelFormat8bppGray, sizeof(GUID)); 599 return S_OK; 600 } 601 602 static HRESULT WINAPI JpegDecoder_Frame_GetResolution(IWICBitmapFrameDecode *iface, 603 double *pDpiX, double *pDpiY) 604 { 605 JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 606 607 EnterCriticalSection(&This->lock); 608 609 switch (This->cinfo.density_unit) 610 { 611 case 2: /* pixels per centimeter */ 612 *pDpiX = This->cinfo.X_density * 2.54; 613 *pDpiY = This->cinfo.Y_density * 2.54; 614 break; 615 616 case 1: /* pixels per inch */ 617 *pDpiX = This->cinfo.X_density; 618 *pDpiY = This->cinfo.Y_density; 619 break; 620 621 case 0: /* unknown */ 622 default: 623 *pDpiX = 96.0; 624 *pDpiY = 96.0; 625 break; 626 } 627 628 LeaveCriticalSection(&This->lock); 629 630 TRACE("(%p)->(%0.2f,%0.2f)\n", iface, *pDpiX, *pDpiY); 631 632 return S_OK; 633 } 634 635 static HRESULT WINAPI JpegDecoder_Frame_CopyPalette(IWICBitmapFrameDecode *iface, 636 IWICPalette *pIPalette) 637 { 638 FIXME("(%p,%p): stub\n", iface, pIPalette); 639 return E_NOTIMPL; 640 } 641 642 static HRESULT WINAPI JpegDecoder_Frame_CopyPixels(IWICBitmapFrameDecode *iface, 643 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer) 644 { 645 JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 646 647 TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer); 648 649 return copy_pixels(This->bpp, This->image_data, 650 This->cinfo.output_width, This->cinfo.output_height, This->stride, 651 prc, cbStride, cbBufferSize, pbBuffer); 652 } 653 654 static HRESULT WINAPI JpegDecoder_Frame_GetMetadataQueryReader(IWICBitmapFrameDecode *iface, 655 IWICMetadataQueryReader **ppIMetadataQueryReader) 656 { 657 JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 658 659 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader); 660 661 if (!ppIMetadataQueryReader) 662 return E_INVALIDARG; 663 664 return MetadataQueryReader_CreateInstance(&This->IWICMetadataBlockReader_iface, NULL, ppIMetadataQueryReader); 665 } 666 667 static HRESULT WINAPI JpegDecoder_Frame_GetColorContexts(IWICBitmapFrameDecode *iface, 668 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) 669 { 670 FIXME("(%p,%u,%p,%p): stub\n", iface, cCount, ppIColorContexts, pcActualCount); 671 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 672 } 673 674 static HRESULT WINAPI JpegDecoder_Frame_GetThumbnail(IWICBitmapFrameDecode *iface, 675 IWICBitmapSource **ppIThumbnail) 676 { 677 FIXME("(%p,%p): stub\n", iface, ppIThumbnail); 678 return WINCODEC_ERR_CODECNOTHUMBNAIL; 679 } 680 681 static const IWICBitmapFrameDecodeVtbl JpegDecoder_Frame_Vtbl = { 682 JpegDecoder_Frame_QueryInterface, 683 JpegDecoder_Frame_AddRef, 684 JpegDecoder_Frame_Release, 685 JpegDecoder_Frame_GetSize, 686 JpegDecoder_Frame_GetPixelFormat, 687 JpegDecoder_Frame_GetResolution, 688 JpegDecoder_Frame_CopyPalette, 689 JpegDecoder_Frame_CopyPixels, 690 JpegDecoder_Frame_GetMetadataQueryReader, 691 JpegDecoder_Frame_GetColorContexts, 692 JpegDecoder_Frame_GetThumbnail 693 }; 694 695 static HRESULT WINAPI JpegDecoder_Block_QueryInterface(IWICMetadataBlockReader *iface, REFIID iid, 696 void **ppv) 697 { 698 JpegDecoder *This = impl_from_IWICMetadataBlockReader(iface); 699 return IWICBitmapFrameDecode_QueryInterface(&This->IWICBitmapFrameDecode_iface, iid, ppv); 700 } 701 702 static ULONG WINAPI JpegDecoder_Block_AddRef(IWICMetadataBlockReader *iface) 703 { 704 JpegDecoder *This = impl_from_IWICMetadataBlockReader(iface); 705 return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface); 706 } 707 708 static ULONG WINAPI JpegDecoder_Block_Release(IWICMetadataBlockReader *iface) 709 { 710 JpegDecoder *This = impl_from_IWICMetadataBlockReader(iface); 711 return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface); 712 } 713 714 static HRESULT WINAPI JpegDecoder_Block_GetContainerFormat(IWICMetadataBlockReader *iface, 715 GUID *pguidContainerFormat) 716 { 717 TRACE("%p,%p\n", iface, pguidContainerFormat); 718 719 if (!pguidContainerFormat) return E_INVALIDARG; 720 721 memcpy(pguidContainerFormat, &GUID_ContainerFormatJpeg, sizeof(GUID)); 722 723 return S_OK; 724 } 725 726 static HRESULT WINAPI JpegDecoder_Block_GetCount(IWICMetadataBlockReader *iface, 727 UINT *pcCount) 728 { 729 FIXME("%p,%p\n", iface, pcCount); 730 731 if (!pcCount) return E_INVALIDARG; 732 733 *pcCount = 0; 734 735 return S_OK; 736 } 737 738 static HRESULT WINAPI JpegDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader *iface, 739 UINT nIndex, IWICMetadataReader **ppIMetadataReader) 740 { 741 FIXME("%p,%d,%p\n", iface, nIndex, ppIMetadataReader); 742 return E_INVALIDARG; 743 } 744 745 static HRESULT WINAPI JpegDecoder_Block_GetEnumerator(IWICMetadataBlockReader *iface, 746 IEnumUnknown **ppIEnumMetadata) 747 { 748 FIXME("%p,%p\n", iface, ppIEnumMetadata); 749 return E_NOTIMPL; 750 } 751 752 static const IWICMetadataBlockReaderVtbl JpegDecoder_Block_Vtbl = { 753 JpegDecoder_Block_QueryInterface, 754 JpegDecoder_Block_AddRef, 755 JpegDecoder_Block_Release, 756 JpegDecoder_Block_GetContainerFormat, 757 JpegDecoder_Block_GetCount, 758 JpegDecoder_Block_GetReaderByIndex, 759 JpegDecoder_Block_GetEnumerator, 760 }; 761 762 HRESULT JpegDecoder_CreateInstance(REFIID iid, void** ppv) 763 { 764 JpegDecoder *This; 765 HRESULT ret; 766 767 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv); 768 769 if (!libjpeg_handle && !load_libjpeg()) 770 { 771 ERR("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG); 772 return E_FAIL; 773 } 774 775 *ppv = NULL; 776 777 This = HeapAlloc(GetProcessHeap(), 0, sizeof(JpegDecoder)); 778 if (!This) return E_OUTOFMEMORY; 779 780 This->IWICBitmapDecoder_iface.lpVtbl = &JpegDecoder_Vtbl; 781 This->IWICBitmapFrameDecode_iface.lpVtbl = &JpegDecoder_Frame_Vtbl; 782 This->IWICMetadataBlockReader_iface.lpVtbl = &JpegDecoder_Block_Vtbl; 783 This->ref = 1; 784 This->initialized = FALSE; 785 This->cinfo_initialized = FALSE; 786 This->stream = NULL; 787 This->image_data = NULL; 788 InitializeCriticalSection(&This->lock); 789 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JpegDecoder.lock"); 790 791 ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv); 792 IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface); 793 794 return ret; 795 } 796 797 typedef struct jpeg_compress_format { 798 const WICPixelFormatGUID *guid; 799 int bpp; 800 int num_components; 801 J_COLOR_SPACE color_space; 802 int swap_rgb; 803 } jpeg_compress_format; 804 805 static const jpeg_compress_format compress_formats[] = { 806 { &GUID_WICPixelFormat24bppBGR, 24, 3, JCS_RGB, 1 }, 807 { &GUID_WICPixelFormat32bppCMYK, 32, 4, JCS_CMYK }, 808 { &GUID_WICPixelFormat8bppGray, 8, 1, JCS_GRAYSCALE }, 809 { 0 } 810 }; 811 812 typedef struct JpegEncoder { 813 IWICBitmapEncoder IWICBitmapEncoder_iface; 814 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface; 815 LONG ref; 816 struct jpeg_compress_struct cinfo; 817 struct jpeg_error_mgr jerr; 818 struct jpeg_destination_mgr dest_mgr; 819 BOOL initialized; 820 int frame_count; 821 BOOL frame_initialized; 822 BOOL started_compress; 823 int lines_written; 824 BOOL frame_committed; 825 BOOL committed; 826 UINT width, height; 827 double xres, yres; 828 const jpeg_compress_format *format; 829 IStream *stream; 830 WICColor palette[256]; 831 UINT colors; 832 CRITICAL_SECTION lock; 833 BYTE dest_buffer[1024]; 834 } JpegEncoder; 835 836 static inline JpegEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface) 837 { 838 return CONTAINING_RECORD(iface, JpegEncoder, IWICBitmapEncoder_iface); 839 } 840 841 static inline JpegEncoder *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface) 842 { 843 return CONTAINING_RECORD(iface, JpegEncoder, IWICBitmapFrameEncode_iface); 844 } 845 846 static inline JpegEncoder *encoder_from_compress(j_compress_ptr compress) 847 { 848 return CONTAINING_RECORD(compress, JpegEncoder, cinfo); 849 } 850 851 static void dest_mgr_init_destination(j_compress_ptr cinfo) 852 { 853 JpegEncoder *This = encoder_from_compress(cinfo); 854 855 This->dest_mgr.next_output_byte = This->dest_buffer; 856 This->dest_mgr.free_in_buffer = sizeof(This->dest_buffer); 857 } 858 859 static jpeg_boolean dest_mgr_empty_output_buffer(j_compress_ptr cinfo) 860 { 861 JpegEncoder *This = encoder_from_compress(cinfo); 862 HRESULT hr; 863 ULONG byteswritten; 864 865 hr = IStream_Write(This->stream, This->dest_buffer, 866 sizeof(This->dest_buffer), &byteswritten); 867 868 if (hr != S_OK || byteswritten == 0) 869 { 870 ERR("Failed writing data, hr=%x\n", hr); 871 return FALSE; 872 } 873 874 This->dest_mgr.next_output_byte = This->dest_buffer; 875 This->dest_mgr.free_in_buffer = sizeof(This->dest_buffer); 876 return TRUE; 877 } 878 879 static void dest_mgr_term_destination(j_compress_ptr cinfo) 880 { 881 JpegEncoder *This = encoder_from_compress(cinfo); 882 ULONG byteswritten; 883 HRESULT hr; 884 885 if (This->dest_mgr.free_in_buffer != sizeof(This->dest_buffer)) 886 { 887 hr = IStream_Write(This->stream, This->dest_buffer, 888 sizeof(This->dest_buffer) - This->dest_mgr.free_in_buffer, &byteswritten); 889 890 if (hr != S_OK || byteswritten == 0) 891 ERR("Failed writing data, hr=%x\n", hr); 892 } 893 } 894 895 static HRESULT WINAPI JpegEncoder_Frame_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid, 896 void **ppv) 897 { 898 JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface); 899 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 900 901 if (!ppv) return E_INVALIDARG; 902 903 if (IsEqualIID(&IID_IUnknown, iid) || 904 IsEqualIID(&IID_IWICBitmapFrameEncode, iid)) 905 { 906 *ppv = &This->IWICBitmapFrameEncode_iface; 907 } 908 else 909 { 910 *ppv = NULL; 911 return E_NOINTERFACE; 912 } 913 914 IUnknown_AddRef((IUnknown*)*ppv); 915 return S_OK; 916 } 917 918 static ULONG WINAPI JpegEncoder_Frame_AddRef(IWICBitmapFrameEncode *iface) 919 { 920 JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface); 921 return IWICBitmapEncoder_AddRef(&This->IWICBitmapEncoder_iface); 922 } 923 924 static ULONG WINAPI JpegEncoder_Frame_Release(IWICBitmapFrameEncode *iface) 925 { 926 JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface); 927 return IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface); 928 } 929 930 static HRESULT WINAPI JpegEncoder_Frame_Initialize(IWICBitmapFrameEncode *iface, 931 IPropertyBag2 *pIEncoderOptions) 932 { 933 JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface); 934 TRACE("(%p,%p)\n", iface, pIEncoderOptions); 935 936 EnterCriticalSection(&This->lock); 937 938 if (This->frame_initialized) 939 { 940 LeaveCriticalSection(&This->lock); 941 return WINCODEC_ERR_WRONGSTATE; 942 } 943 944 This->frame_initialized = TRUE; 945 946 LeaveCriticalSection(&This->lock); 947 948 return S_OK; 949 } 950 951 static HRESULT WINAPI JpegEncoder_Frame_SetSize(IWICBitmapFrameEncode *iface, 952 UINT uiWidth, UINT uiHeight) 953 { 954 JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface); 955 TRACE("(%p,%u,%u)\n", iface, uiWidth, uiHeight); 956 957 EnterCriticalSection(&This->lock); 958 959 if (!This->frame_initialized || This->started_compress) 960 { 961 LeaveCriticalSection(&This->lock); 962 return WINCODEC_ERR_WRONGSTATE; 963 } 964 965 This->width = uiWidth; 966 This->height = uiHeight; 967 968 LeaveCriticalSection(&This->lock); 969 970 return S_OK; 971 } 972 973 static HRESULT WINAPI JpegEncoder_Frame_SetResolution(IWICBitmapFrameEncode *iface, 974 double dpiX, double dpiY) 975 { 976 JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface); 977 TRACE("(%p,%0.2f,%0.2f)\n", iface, dpiX, dpiY); 978 979 EnterCriticalSection(&This->lock); 980 981 if (!This->frame_initialized || This->started_compress) 982 { 983 LeaveCriticalSection(&This->lock); 984 return WINCODEC_ERR_WRONGSTATE; 985 } 986 987 This->xres = dpiX; 988 This->yres = dpiY; 989 990 LeaveCriticalSection(&This->lock); 991 992 return S_OK; 993 } 994 995 static HRESULT WINAPI JpegEncoder_Frame_SetPixelFormat(IWICBitmapFrameEncode *iface, 996 WICPixelFormatGUID *pPixelFormat) 997 { 998 JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface); 999 int i; 1000 TRACE("(%p,%s)\n", iface, debugstr_guid(pPixelFormat)); 1001 1002 EnterCriticalSection(&This->lock); 1003 1004 if (!This->frame_initialized || This->started_compress) 1005 { 1006 LeaveCriticalSection(&This->lock); 1007 return WINCODEC_ERR_WRONGSTATE; 1008 } 1009 1010 for (i=0; compress_formats[i].guid; i++) 1011 { 1012 if (memcmp(compress_formats[i].guid, pPixelFormat, sizeof(GUID)) == 0) 1013 break; 1014 } 1015 1016 if (!compress_formats[i].guid) i = 0; 1017 1018 This->format = &compress_formats[i]; 1019 memcpy(pPixelFormat, This->format->guid, sizeof(GUID)); 1020 1021 LeaveCriticalSection(&This->lock); 1022 1023 return S_OK; 1024 } 1025 1026 static HRESULT WINAPI JpegEncoder_Frame_SetColorContexts(IWICBitmapFrameEncode *iface, 1027 UINT cCount, IWICColorContext **ppIColorContext) 1028 { 1029 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext); 1030 return E_NOTIMPL; 1031 } 1032 1033 static HRESULT WINAPI JpegEncoder_Frame_SetPalette(IWICBitmapFrameEncode *iface, 1034 IWICPalette *palette) 1035 { 1036 JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface); 1037 HRESULT hr; 1038 1039 TRACE("(%p,%p)\n", iface, palette); 1040 1041 if (!palette) return E_INVALIDARG; 1042 1043 EnterCriticalSection(&This->lock); 1044 1045 if (This->frame_initialized) 1046 hr = IWICPalette_GetColors(palette, 256, This->palette, &This->colors); 1047 else 1048 hr = WINCODEC_ERR_NOTINITIALIZED; 1049 1050 LeaveCriticalSection(&This->lock); 1051 return hr; 1052 } 1053 1054 static HRESULT WINAPI JpegEncoder_Frame_SetThumbnail(IWICBitmapFrameEncode *iface, 1055 IWICBitmapSource *pIThumbnail) 1056 { 1057 FIXME("(%p,%p): stub\n", iface, pIThumbnail); 1058 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 1059 } 1060 1061 static HRESULT WINAPI JpegEncoder_Frame_WritePixels(IWICBitmapFrameEncode *iface, 1062 UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels) 1063 { 1064 JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface); 1065 jmp_buf jmpbuf; 1066 BYTE *swapped_data = NULL, *current_row; 1067 UINT line; 1068 int row_size; 1069 TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels); 1070 1071 EnterCriticalSection(&This->lock); 1072 1073 if (!This->frame_initialized || !This->width || !This->height || !This->format) 1074 { 1075 LeaveCriticalSection(&This->lock); 1076 return WINCODEC_ERR_WRONGSTATE; 1077 } 1078 1079 if (lineCount == 0 || lineCount + This->lines_written > This->height) 1080 { 1081 LeaveCriticalSection(&This->lock); 1082 return E_INVALIDARG; 1083 } 1084 1085 /* set up setjmp/longjmp error handling */ 1086 if (setjmp(jmpbuf)) 1087 { 1088 LeaveCriticalSection(&This->lock); 1089 HeapFree(GetProcessHeap(), 0, swapped_data); 1090 return E_FAIL; 1091 } 1092 This->cinfo.client_data = jmpbuf; 1093 1094 if (!This->started_compress) 1095 { 1096 This->cinfo.image_width = This->width; 1097 This->cinfo.image_height = This->height; 1098 This->cinfo.input_components = This->format->num_components; 1099 This->cinfo.in_color_space = This->format->color_space; 1100 1101 pjpeg_set_defaults(&This->cinfo); 1102 1103 if (This->xres != 0.0 && This->yres != 0.0) 1104 { 1105 This->cinfo.density_unit = 1; /* dots per inch */ 1106 This->cinfo.X_density = This->xres; 1107 This->cinfo.Y_density = This->yres; 1108 } 1109 1110 pjpeg_start_compress(&This->cinfo, TRUE); 1111 1112 This->started_compress = TRUE; 1113 } 1114 1115 row_size = This->format->bpp / 8 * This->width; 1116 1117 if (This->format->swap_rgb) 1118 { 1119 swapped_data = HeapAlloc(GetProcessHeap(), 0, row_size); 1120 if (!swapped_data) 1121 { 1122 LeaveCriticalSection(&This->lock); 1123 return E_OUTOFMEMORY; 1124 } 1125 } 1126 1127 for (line=0; line < lineCount; line++) 1128 { 1129 if (This->format->swap_rgb) 1130 { 1131 UINT x; 1132 1133 memcpy(swapped_data, pbPixels + (cbStride * line), row_size); 1134 1135 for (x=0; x < This->width; x++) 1136 { 1137 BYTE b; 1138 1139 b = swapped_data[x*3]; 1140 swapped_data[x*3] = swapped_data[x*3+2]; 1141 swapped_data[x*3+2] = b; 1142 } 1143 1144 current_row = swapped_data; 1145 } 1146 else 1147 current_row = pbPixels + (cbStride * line); 1148 1149 if (!pjpeg_write_scanlines(&This->cinfo, ¤t_row, 1)) 1150 { 1151 ERR("failed writing scanlines\n"); 1152 LeaveCriticalSection(&This->lock); 1153 HeapFree(GetProcessHeap(), 0, swapped_data); 1154 return E_FAIL; 1155 } 1156 1157 This->lines_written++; 1158 } 1159 1160 LeaveCriticalSection(&This->lock); 1161 HeapFree(GetProcessHeap(), 0, swapped_data); 1162 1163 return S_OK; 1164 } 1165 1166 static HRESULT WINAPI JpegEncoder_Frame_WriteSource(IWICBitmapFrameEncode *iface, 1167 IWICBitmapSource *pIBitmapSource, WICRect *prc) 1168 { 1169 JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface); 1170 HRESULT hr; 1171 TRACE("(%p,%p,%s)\n", iface, pIBitmapSource, debug_wic_rect(prc)); 1172 1173 if (!This->frame_initialized) 1174 return WINCODEC_ERR_WRONGSTATE; 1175 1176 hr = configure_write_source(iface, pIBitmapSource, prc, 1177 This->format ? This->format->guid : NULL, This->width, This->height, 1178 This->xres, This->yres); 1179 1180 if (SUCCEEDED(hr)) 1181 { 1182 hr = write_source(iface, pIBitmapSource, prc, 1183 This->format->guid, This->format->bpp, This->width, This->height); 1184 } 1185 1186 return hr; 1187 } 1188 1189 static HRESULT WINAPI JpegEncoder_Frame_Commit(IWICBitmapFrameEncode *iface) 1190 { 1191 JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface); 1192 jmp_buf jmpbuf; 1193 TRACE("(%p)\n", iface); 1194 1195 EnterCriticalSection(&This->lock); 1196 1197 if (!This->started_compress || This->lines_written != This->height || This->frame_committed) 1198 { 1199 LeaveCriticalSection(&This->lock); 1200 return WINCODEC_ERR_WRONGSTATE; 1201 } 1202 1203 /* set up setjmp/longjmp error handling */ 1204 if (setjmp(jmpbuf)) 1205 { 1206 LeaveCriticalSection(&This->lock); 1207 return E_FAIL; 1208 } 1209 This->cinfo.client_data = jmpbuf; 1210 1211 pjpeg_finish_compress(&This->cinfo); 1212 1213 This->frame_committed = TRUE; 1214 1215 LeaveCriticalSection(&This->lock); 1216 1217 return S_OK; 1218 } 1219 1220 static HRESULT WINAPI JpegEncoder_Frame_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface, 1221 IWICMetadataQueryWriter **ppIMetadataQueryWriter) 1222 { 1223 FIXME("(%p, %p): stub\n", iface, ppIMetadataQueryWriter); 1224 return E_NOTIMPL; 1225 } 1226 1227 static const IWICBitmapFrameEncodeVtbl JpegEncoder_FrameVtbl = { 1228 JpegEncoder_Frame_QueryInterface, 1229 JpegEncoder_Frame_AddRef, 1230 JpegEncoder_Frame_Release, 1231 JpegEncoder_Frame_Initialize, 1232 JpegEncoder_Frame_SetSize, 1233 JpegEncoder_Frame_SetResolution, 1234 JpegEncoder_Frame_SetPixelFormat, 1235 JpegEncoder_Frame_SetColorContexts, 1236 JpegEncoder_Frame_SetPalette, 1237 JpegEncoder_Frame_SetThumbnail, 1238 JpegEncoder_Frame_WritePixels, 1239 JpegEncoder_Frame_WriteSource, 1240 JpegEncoder_Frame_Commit, 1241 JpegEncoder_Frame_GetMetadataQueryWriter 1242 }; 1243 1244 static HRESULT WINAPI JpegEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid, 1245 void **ppv) 1246 { 1247 JpegEncoder *This = impl_from_IWICBitmapEncoder(iface); 1248 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 1249 1250 if (!ppv) return E_INVALIDARG; 1251 1252 if (IsEqualIID(&IID_IUnknown, iid) || 1253 IsEqualIID(&IID_IWICBitmapEncoder, iid)) 1254 { 1255 *ppv = &This->IWICBitmapEncoder_iface; 1256 } 1257 else 1258 { 1259 *ppv = NULL; 1260 return E_NOINTERFACE; 1261 } 1262 1263 IUnknown_AddRef((IUnknown*)*ppv); 1264 return S_OK; 1265 } 1266 1267 static ULONG WINAPI JpegEncoder_AddRef(IWICBitmapEncoder *iface) 1268 { 1269 JpegEncoder *This = impl_from_IWICBitmapEncoder(iface); 1270 ULONG ref = InterlockedIncrement(&This->ref); 1271 1272 TRACE("(%p) refcount=%u\n", iface, ref); 1273 1274 return ref; 1275 } 1276 1277 static ULONG WINAPI JpegEncoder_Release(IWICBitmapEncoder *iface) 1278 { 1279 JpegEncoder *This = impl_from_IWICBitmapEncoder(iface); 1280 ULONG ref = InterlockedDecrement(&This->ref); 1281 1282 TRACE("(%p) refcount=%u\n", iface, ref); 1283 1284 if (ref == 0) 1285 { 1286 This->lock.DebugInfo->Spare[0] = 0; 1287 DeleteCriticalSection(&This->lock); 1288 if (This->initialized) pjpeg_destroy_compress(&This->cinfo); 1289 if (This->stream) IStream_Release(This->stream); 1290 HeapFree(GetProcessHeap(), 0, This); 1291 } 1292 1293 return ref; 1294 } 1295 1296 static HRESULT WINAPI JpegEncoder_Initialize(IWICBitmapEncoder *iface, 1297 IStream *pIStream, WICBitmapEncoderCacheOption cacheOption) 1298 { 1299 JpegEncoder *This = impl_from_IWICBitmapEncoder(iface); 1300 jmp_buf jmpbuf; 1301 1302 TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOption); 1303 1304 EnterCriticalSection(&This->lock); 1305 1306 if (This->initialized) 1307 { 1308 LeaveCriticalSection(&This->lock); 1309 return WINCODEC_ERR_WRONGSTATE; 1310 } 1311 1312 pjpeg_std_error(&This->jerr); 1313 1314 This->jerr.error_exit = error_exit_fn; 1315 This->jerr.emit_message = emit_message_fn; 1316 1317 This->cinfo.err = &This->jerr; 1318 1319 This->cinfo.client_data = jmpbuf; 1320 1321 if (setjmp(jmpbuf)) 1322 { 1323 LeaveCriticalSection(&This->lock); 1324 return E_FAIL; 1325 } 1326 1327 pjpeg_CreateCompress(&This->cinfo, JPEG_LIB_VERSION, sizeof(struct jpeg_compress_struct)); 1328 1329 This->stream = pIStream; 1330 IStream_AddRef(pIStream); 1331 1332 This->dest_mgr.next_output_byte = This->dest_buffer; 1333 This->dest_mgr.free_in_buffer = sizeof(This->dest_buffer); 1334 1335 This->dest_mgr.init_destination = dest_mgr_init_destination; 1336 This->dest_mgr.empty_output_buffer = dest_mgr_empty_output_buffer; 1337 This->dest_mgr.term_destination = dest_mgr_term_destination; 1338 1339 This->cinfo.dest = &This->dest_mgr; 1340 1341 This->initialized = TRUE; 1342 1343 LeaveCriticalSection(&This->lock); 1344 1345 return S_OK; 1346 } 1347 1348 static HRESULT WINAPI JpegEncoder_GetContainerFormat(IWICBitmapEncoder *iface, GUID *format) 1349 { 1350 TRACE("(%p,%p)\n", iface, format); 1351 1352 if (!format) 1353 return E_INVALIDARG; 1354 1355 memcpy(format, &GUID_ContainerFormatJpeg, sizeof(*format)); 1356 return S_OK; 1357 } 1358 1359 static HRESULT WINAPI JpegEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, IWICBitmapEncoderInfo **info) 1360 { 1361 IWICComponentInfo *comp_info; 1362 HRESULT hr; 1363 1364 TRACE("%p,%p\n", iface, info); 1365 1366 if (!info) return E_INVALIDARG; 1367 1368 hr = CreateComponentInfo(&CLSID_WICJpegEncoder, &comp_info); 1369 if (hr == S_OK) 1370 { 1371 hr = IWICComponentInfo_QueryInterface(comp_info, &IID_IWICBitmapEncoderInfo, (void **)info); 1372 IWICComponentInfo_Release(comp_info); 1373 } 1374 return hr; 1375 } 1376 1377 static HRESULT WINAPI JpegEncoder_SetColorContexts(IWICBitmapEncoder *iface, 1378 UINT cCount, IWICColorContext **ppIColorContext) 1379 { 1380 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext); 1381 return E_NOTIMPL; 1382 } 1383 1384 static HRESULT WINAPI JpegEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *pIPalette) 1385 { 1386 JpegEncoder *This = impl_from_IWICBitmapEncoder(iface); 1387 HRESULT hr; 1388 1389 TRACE("(%p,%p)\n", iface, pIPalette); 1390 1391 EnterCriticalSection(&This->lock); 1392 1393 hr = This->initialized ? WINCODEC_ERR_UNSUPPORTEDOPERATION : WINCODEC_ERR_NOTINITIALIZED; 1394 1395 LeaveCriticalSection(&This->lock); 1396 1397 return hr; 1398 } 1399 1400 static HRESULT WINAPI JpegEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail) 1401 { 1402 TRACE("(%p,%p)\n", iface, pIThumbnail); 1403 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 1404 } 1405 1406 static HRESULT WINAPI JpegEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview) 1407 { 1408 TRACE("(%p,%p)\n", iface, pIPreview); 1409 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 1410 } 1411 1412 static HRESULT WINAPI JpegEncoder_CreateNewFrame(IWICBitmapEncoder *iface, 1413 IWICBitmapFrameEncode **ppIFrameEncode, IPropertyBag2 **ppIEncoderOptions) 1414 { 1415 JpegEncoder *This = impl_from_IWICBitmapEncoder(iface); 1416 HRESULT hr; 1417 static const PROPBAG2 opts[6] = 1418 { 1419 { PROPBAG2_TYPE_DATA, VT_R4, 0, 0, (LPOLESTR)wszImageQuality }, 1420 { PROPBAG2_TYPE_DATA, VT_UI1, 0, 0, (LPOLESTR)wszBitmapTransform }, 1421 { PROPBAG2_TYPE_DATA, VT_I4 | VT_ARRAY, 0, 0, (LPOLESTR)wszLuminance }, 1422 { PROPBAG2_TYPE_DATA, VT_I4 | VT_ARRAY, 0, 0, (LPOLESTR)wszChrominance }, 1423 { PROPBAG2_TYPE_DATA, VT_UI1, 0, 0, (LPOLESTR)wszJpegYCrCbSubsampling }, 1424 { PROPBAG2_TYPE_DATA, VT_BOOL, 0, 0, (LPOLESTR)wszSuppressApp0 }, 1425 }; 1426 1427 TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions); 1428 1429 EnterCriticalSection(&This->lock); 1430 1431 if (This->frame_count != 0) 1432 { 1433 LeaveCriticalSection(&This->lock); 1434 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 1435 } 1436 1437 if (!This->initialized) 1438 { 1439 LeaveCriticalSection(&This->lock); 1440 return WINCODEC_ERR_NOTINITIALIZED; 1441 } 1442 1443 if (ppIEncoderOptions) 1444 { 1445 hr = CreatePropertyBag2(opts, ARRAY_SIZE(opts), ppIEncoderOptions); 1446 if (FAILED(hr)) 1447 { 1448 LeaveCriticalSection(&This->lock); 1449 return hr; 1450 } 1451 } 1452 1453 This->frame_count = 1; 1454 1455 LeaveCriticalSection(&This->lock); 1456 1457 IWICBitmapEncoder_AddRef(iface); 1458 *ppIFrameEncode = &This->IWICBitmapFrameEncode_iface; 1459 1460 return S_OK; 1461 } 1462 1463 static HRESULT WINAPI JpegEncoder_Commit(IWICBitmapEncoder *iface) 1464 { 1465 JpegEncoder *This = impl_from_IWICBitmapEncoder(iface); 1466 TRACE("(%p)\n", iface); 1467 1468 EnterCriticalSection(&This->lock); 1469 1470 if (!This->frame_committed || This->committed) 1471 { 1472 LeaveCriticalSection(&This->lock); 1473 return WINCODEC_ERR_WRONGSTATE; 1474 } 1475 1476 This->committed = TRUE; 1477 1478 LeaveCriticalSection(&This->lock); 1479 1480 return S_OK; 1481 } 1482 1483 static HRESULT WINAPI JpegEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface, 1484 IWICMetadataQueryWriter **ppIMetadataQueryWriter) 1485 { 1486 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter); 1487 return E_NOTIMPL; 1488 } 1489 1490 static const IWICBitmapEncoderVtbl JpegEncoder_Vtbl = { 1491 JpegEncoder_QueryInterface, 1492 JpegEncoder_AddRef, 1493 JpegEncoder_Release, 1494 JpegEncoder_Initialize, 1495 JpegEncoder_GetContainerFormat, 1496 JpegEncoder_GetEncoderInfo, 1497 JpegEncoder_SetColorContexts, 1498 JpegEncoder_SetPalette, 1499 JpegEncoder_SetThumbnail, 1500 JpegEncoder_SetPreview, 1501 JpegEncoder_CreateNewFrame, 1502 JpegEncoder_Commit, 1503 JpegEncoder_GetMetadataQueryWriter 1504 }; 1505 1506 HRESULT JpegEncoder_CreateInstance(REFIID iid, void** ppv) 1507 { 1508 JpegEncoder *This; 1509 HRESULT ret; 1510 1511 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv); 1512 1513 *ppv = NULL; 1514 1515 if (!libjpeg_handle && !load_libjpeg()) 1516 { 1517 ERR("Failed writing JPEG because unable to find %s\n",SONAME_LIBJPEG); 1518 return E_FAIL; 1519 } 1520 1521 This = HeapAlloc(GetProcessHeap(), 0, sizeof(JpegEncoder)); 1522 if (!This) return E_OUTOFMEMORY; 1523 1524 This->IWICBitmapEncoder_iface.lpVtbl = &JpegEncoder_Vtbl; 1525 This->IWICBitmapFrameEncode_iface.lpVtbl = &JpegEncoder_FrameVtbl; 1526 This->ref = 1; 1527 This->initialized = FALSE; 1528 This->frame_count = 0; 1529 This->frame_initialized = FALSE; 1530 This->started_compress = FALSE; 1531 This->lines_written = 0; 1532 This->frame_committed = FALSE; 1533 This->committed = FALSE; 1534 This->width = This->height = 0; 1535 This->xres = This->yres = 0.0; 1536 This->format = NULL; 1537 This->stream = NULL; 1538 This->colors = 0; 1539 InitializeCriticalSection(&This->lock); 1540 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JpegEncoder.lock"); 1541 1542 ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv); 1543 IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface); 1544 1545 return ret; 1546 } 1547 1548 #else /* !defined(SONAME_LIBJPEG) */ 1549 1550 HRESULT JpegDecoder_CreateInstance(REFIID iid, void** ppv) 1551 { 1552 ERR("Trying to load JPEG picture, but JPEG support is not compiled in.\n"); 1553 return E_FAIL; 1554 } 1555 1556 HRESULT JpegEncoder_CreateInstance(REFIID iid, void** ppv) 1557 { 1558 ERR("Trying to save JPEG picture, but JPEG support is not compiled in.\n"); 1559 return E_FAIL; 1560 } 1561 1562 #endif 1563