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