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