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