win32u: Move NtUserTranslateMessage implementation from user32.
[wine.git] / dlls / windowscodecs / tgaformat.c
blobf545cc6cffbcdc1b48ad2c3efd9421b596f0e79e
1 /*
2 * Copyright 2010 Vincent Povirk for CodeWeavers
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.
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.
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
19 #include <stdarg.h>
21 #define COBJMACROS
23 #include "windef.h"
24 #include "winbase.h"
25 #include "objbase.h"
27 #include "wincodecs_private.h"
29 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
33 #include "pshpack1.h"
35 typedef struct {
36 BYTE id_length;
37 BYTE colormap_type;
38 BYTE image_type;
39 /* Colormap Specification */
40 WORD colormap_firstentry;
41 WORD colormap_length;
42 BYTE colormap_entrysize;
43 /* Image Specification */
44 WORD xorigin;
45 WORD yorigin;
46 WORD width;
47 WORD height;
48 BYTE depth;
49 BYTE image_descriptor;
50 } tga_header;
52 #define IMAGETYPE_COLORMAPPED 1
53 #define IMAGETYPE_TRUECOLOR 2
54 #define IMAGETYPE_GRAYSCALE 3
55 #define IMAGETYPE_RLE 8
57 #define IMAGE_ATTRIBUTE_BITCOUNT_MASK 0xf
58 #define IMAGE_RIGHTTOLEFT 0x10
59 #define IMAGE_TOPTOBOTTOM 0x20
61 typedef struct {
62 DWORD extension_area_offset;
63 DWORD developer_directory_offset;
64 char magic[18];
65 } tga_footer;
67 static const BYTE tga_footer_magic[18] = "TRUEVISION-XFILE.";
69 typedef struct {
70 WORD size;
71 char author_name[41];
72 char author_comments[324];
73 WORD timestamp[6];
74 char job_name[41];
75 WORD job_timestamp[6];
76 char software_id[41];
77 WORD software_version;
78 char software_version_letter;
79 DWORD key_color;
80 WORD pixel_width;
81 WORD pixel_height;
82 WORD gamma_numerator;
83 WORD gamma_denominator;
84 DWORD color_correction_offset;
85 DWORD thumbnail_offset;
86 DWORD scanline_offset;
87 BYTE attributes_type;
88 } tga_extension_area;
90 #define ATTRIBUTE_NO_ALPHA 0
91 #define ATTRIBUTE_UNDEFINED 1
92 #define ATTRIBUTE_UNDEFINED_PRESERVE 2
93 #define ATTRIBUTE_ALPHA 3
94 #define ATTRIBUTE_PALPHA 4
96 #include "poppack.h"
98 typedef struct {
99 IWICBitmapDecoder IWICBitmapDecoder_iface;
100 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
101 LONG ref;
102 BOOL initialized;
103 IStream *stream;
104 tga_header header;
105 tga_extension_area extension_area;
106 BYTE *imagebits;
107 BYTE *origin;
108 int stride;
109 ULONG id_offset;
110 ULONG colormap_length;
111 ULONG colormap_offset;
112 ULONG image_offset;
113 ULONG extension_area_offset;
114 ULONG developer_directory_offset;
115 CRITICAL_SECTION lock;
116 } TgaDecoder;
118 static inline TgaDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
120 return CONTAINING_RECORD(iface, TgaDecoder, IWICBitmapDecoder_iface);
123 static inline TgaDecoder *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
125 return CONTAINING_RECORD(iface, TgaDecoder, IWICBitmapFrameDecode_iface);
128 static HRESULT WINAPI TgaDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
129 void **ppv)
131 TgaDecoder *This = impl_from_IWICBitmapDecoder(iface);
132 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
134 if (!ppv) return E_INVALIDARG;
136 if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICBitmapDecoder, iid))
138 *ppv = &This->IWICBitmapDecoder_iface;
140 else
142 *ppv = NULL;
143 return E_NOINTERFACE;
146 IUnknown_AddRef((IUnknown*)*ppv);
147 return S_OK;
150 static ULONG WINAPI TgaDecoder_AddRef(IWICBitmapDecoder *iface)
152 TgaDecoder *This = impl_from_IWICBitmapDecoder(iface);
153 ULONG ref = InterlockedIncrement(&This->ref);
155 TRACE("(%p) refcount=%lu\n", iface, ref);
157 return ref;
160 static ULONG WINAPI TgaDecoder_Release(IWICBitmapDecoder *iface)
162 TgaDecoder *This = impl_from_IWICBitmapDecoder(iface);
163 ULONG ref = InterlockedDecrement(&This->ref);
165 TRACE("(%p) refcount=%lu\n", iface, ref);
167 if (ref == 0)
169 This->lock.DebugInfo->Spare[0] = 0;
170 DeleteCriticalSection(&This->lock);
171 if (This->stream)
172 IStream_Release(This->stream);
173 HeapFree(GetProcessHeap(), 0, This->imagebits);
174 HeapFree(GetProcessHeap(), 0, This);
177 return ref;
180 static HRESULT WINAPI TgaDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream,
181 DWORD *capability)
183 HRESULT hr;
185 TRACE("(%p,%p,%p)\n", iface, stream, capability);
187 if (!stream || !capability) return E_INVALIDARG;
189 hr = IWICBitmapDecoder_Initialize(iface, stream, WICDecodeMetadataCacheOnDemand);
190 if (hr != S_OK) return hr;
192 *capability = WICBitmapDecoderCapabilityCanDecodeAllImages |
193 WICBitmapDecoderCapabilityCanDecodeSomeImages;
194 return S_OK;
197 static HRESULT WINAPI TgaDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
198 WICDecodeOptions cacheOptions)
200 TgaDecoder *This = impl_from_IWICBitmapDecoder(iface);
201 HRESULT hr=S_OK;
202 DWORD bytesread;
203 LARGE_INTEGER seek;
204 tga_footer footer;
205 int attribute_bitcount;
206 int mapped_depth=0;
208 TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOptions);
210 EnterCriticalSection(&This->lock);
212 if (This->initialized)
214 hr = WINCODEC_ERR_WRONGSTATE;
215 goto end;
218 seek.QuadPart = 0;
219 hr = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
220 if (FAILED(hr)) goto end;
222 hr = IStream_Read(pIStream, &This->header, sizeof(tga_header), &bytesread);
223 if (SUCCEEDED(hr) && bytesread != sizeof(tga_header))
225 TRACE("got only %lu bytes\n", bytesread);
226 hr = E_FAIL;
228 if (FAILED(hr)) goto end;
230 TRACE("imagetype=%u, colormap type=%u, depth=%u, image descriptor=0x%x\n",
231 This->header.image_type, This->header.colormap_type,
232 This->header.depth, This->header.image_descriptor);
234 /* Sanity checking. Since TGA has no clear identifying markers, we need
235 * to be careful to not load a non-TGA image. */
236 switch (This->header.image_type)
238 case IMAGETYPE_COLORMAPPED:
239 case IMAGETYPE_COLORMAPPED|IMAGETYPE_RLE:
240 if (This->header.colormap_type != 1)
241 hr = E_FAIL;
242 mapped_depth = This->header.colormap_entrysize;
243 break;
244 case IMAGETYPE_TRUECOLOR:
245 case IMAGETYPE_TRUECOLOR|IMAGETYPE_RLE:
246 if (This->header.colormap_type != 0 && This->header.colormap_type != 1)
247 hr = E_FAIL;
248 mapped_depth = This->header.depth;
249 break;
250 case IMAGETYPE_GRAYSCALE:
251 case IMAGETYPE_GRAYSCALE|IMAGETYPE_RLE:
252 if (This->header.colormap_type != 0)
253 hr = E_FAIL;
254 mapped_depth = 0;
255 break;
256 default:
257 hr = E_FAIL;
260 if (This->header.depth != 8 && This->header.depth != 16 &&
261 This->header.depth != 24 && This->header.depth != 32)
262 hr = E_FAIL;
264 if ((This->header.image_descriptor & 0xc0) != 0)
265 hr = E_FAIL;
267 attribute_bitcount = This->header.image_descriptor & IMAGE_ATTRIBUTE_BITCOUNT_MASK;
269 if (attribute_bitcount &&
270 !((mapped_depth == 32 && attribute_bitcount == 8) ||
271 (mapped_depth == 16 && attribute_bitcount == 1)))
272 hr = E_FAIL;
274 if (FAILED(hr))
276 WARN("bad tga header\n");
277 goto end;
280 /* Locate data in the file based on the header. */
281 This->id_offset = sizeof(tga_header);
282 This->colormap_offset = This->id_offset + This->header.id_length;
283 if (This->header.colormap_type == 1)
284 This->colormap_length = ((This->header.colormap_entrysize+7)/8) * This->header.colormap_length;
285 else
286 This->colormap_length = 0;
287 This->image_offset = This->colormap_offset + This->colormap_length;
289 /* Read footer if there is one */
290 seek.QuadPart = -(LONGLONG)sizeof(tga_footer);
291 hr = IStream_Seek(pIStream, seek, STREAM_SEEK_END, NULL);
293 if (SUCCEEDED(hr)) {
294 hr = IStream_Read(pIStream, &footer, sizeof(tga_footer), &bytesread);
295 if (SUCCEEDED(hr) && bytesread != sizeof(tga_footer))
297 TRACE("got only %lu footer bytes\n", bytesread);
298 hr = E_FAIL;
301 if (memcmp(footer.magic, tga_footer_magic, sizeof(tga_footer_magic)) == 0)
303 This->extension_area_offset = footer.extension_area_offset;
304 This->developer_directory_offset = footer.developer_directory_offset;
306 else
308 This->extension_area_offset = 0;
309 This->developer_directory_offset = 0;
312 else
314 /* File is too small to have a footer. */
315 This->extension_area_offset = 0;
316 This->developer_directory_offset = 0;
317 hr = S_OK;
320 if (This->extension_area_offset)
322 seek.QuadPart = This->extension_area_offset;
323 hr = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
324 if (FAILED(hr)) goto end;
326 hr = IStream_Read(pIStream, &This->extension_area, sizeof(tga_extension_area), &bytesread);
327 if (SUCCEEDED(hr) && bytesread != sizeof(tga_extension_area))
329 TRACE("got only %lu extension area bytes\n", bytesread);
330 hr = E_FAIL;
332 if (SUCCEEDED(hr) && This->extension_area.size < 495)
334 TRACE("extension area is only %u bytes long\n", This->extension_area.size);
335 hr = E_FAIL;
337 if (FAILED(hr)) goto end;
340 IStream_AddRef(pIStream);
341 This->stream = pIStream;
342 This->initialized = TRUE;
344 end:
345 LeaveCriticalSection(&This->lock);
346 return hr;
349 static HRESULT WINAPI TgaDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
350 GUID *pguidContainerFormat)
352 memcpy(pguidContainerFormat, &GUID_WineContainerFormatTga, sizeof(GUID));
353 return S_OK;
356 static HRESULT WINAPI TgaDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
357 IWICBitmapDecoderInfo **ppIDecoderInfo)
359 TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
361 return get_decoder_info(&CLSID_WineTgaDecoder, ppIDecoderInfo);
364 static HRESULT WINAPI TgaDecoder_CopyPalette(IWICBitmapDecoder *iface,
365 IWICPalette *pIPalette)
367 FIXME("(%p,%p): stub\n", iface, pIPalette);
368 return E_NOTIMPL;
371 static HRESULT WINAPI TgaDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
372 IWICMetadataQueryReader **ppIMetadataQueryReader)
374 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryReader);
375 return E_NOTIMPL;
378 static HRESULT WINAPI TgaDecoder_GetPreview(IWICBitmapDecoder *iface,
379 IWICBitmapSource **ppIBitmapSource)
381 FIXME("(%p,%p): stub\n", iface, ppIBitmapSource);
382 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
385 static HRESULT WINAPI TgaDecoder_GetColorContexts(IWICBitmapDecoder *iface,
386 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
388 FIXME("(%p,%u,%p,%p): stub\n", iface, cCount, ppIColorContexts, pcActualCount);
389 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
392 static HRESULT WINAPI TgaDecoder_GetThumbnail(IWICBitmapDecoder *iface,
393 IWICBitmapSource **ppIThumbnail)
395 FIXME("(%p,%p): stub\n", iface, ppIThumbnail);
396 return WINCODEC_ERR_CODECNOTHUMBNAIL;
399 static HRESULT WINAPI TgaDecoder_GetFrameCount(IWICBitmapDecoder *iface,
400 UINT *pCount)
402 if (!pCount) return E_INVALIDARG;
404 *pCount = 1;
405 return S_OK;
408 static HRESULT WINAPI TgaDecoder_GetFrame(IWICBitmapDecoder *iface,
409 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
411 TgaDecoder *This = impl_from_IWICBitmapDecoder(iface);
412 TRACE("(%p,%p)\n", iface, ppIBitmapFrame);
414 if (!This->initialized) return WINCODEC_ERR_FRAMEMISSING;
416 if (index != 0) return E_INVALIDARG;
418 IWICBitmapDecoder_AddRef(iface);
419 *ppIBitmapFrame = &This->IWICBitmapFrameDecode_iface;
421 return S_OK;
424 static const IWICBitmapDecoderVtbl TgaDecoder_Vtbl = {
425 TgaDecoder_QueryInterface,
426 TgaDecoder_AddRef,
427 TgaDecoder_Release,
428 TgaDecoder_QueryCapability,
429 TgaDecoder_Initialize,
430 TgaDecoder_GetContainerFormat,
431 TgaDecoder_GetDecoderInfo,
432 TgaDecoder_CopyPalette,
433 TgaDecoder_GetMetadataQueryReader,
434 TgaDecoder_GetPreview,
435 TgaDecoder_GetColorContexts,
436 TgaDecoder_GetThumbnail,
437 TgaDecoder_GetFrameCount,
438 TgaDecoder_GetFrame
441 static HRESULT WINAPI TgaDecoder_Frame_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
442 void **ppv)
444 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
446 if (!ppv) return E_INVALIDARG;
448 if (IsEqualIID(&IID_IUnknown, iid) ||
449 IsEqualIID(&IID_IWICBitmapSource, iid) ||
450 IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
452 *ppv = iface;
454 else
456 *ppv = NULL;
457 return E_NOINTERFACE;
460 IUnknown_AddRef((IUnknown*)*ppv);
461 return S_OK;
464 static ULONG WINAPI TgaDecoder_Frame_AddRef(IWICBitmapFrameDecode *iface)
466 TgaDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
467 return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface);
470 static ULONG WINAPI TgaDecoder_Frame_Release(IWICBitmapFrameDecode *iface)
472 TgaDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
473 return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
476 static HRESULT WINAPI TgaDecoder_Frame_GetSize(IWICBitmapFrameDecode *iface,
477 UINT *puiWidth, UINT *puiHeight)
479 TgaDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
481 *puiWidth = This->header.width;
482 *puiHeight = This->header.height;
484 TRACE("(%p)->(%u,%u)\n", iface, *puiWidth, *puiHeight);
486 return S_OK;
489 static HRESULT WINAPI TgaDecoder_Frame_GetPixelFormat(IWICBitmapFrameDecode *iface,
490 WICPixelFormatGUID *pPixelFormat)
492 TgaDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
493 int attribute_bitcount;
494 byte attribute_type;
496 TRACE("(%p,%p)\n", iface, pPixelFormat);
498 attribute_bitcount = This->header.image_descriptor & IMAGE_ATTRIBUTE_BITCOUNT_MASK;
500 if (attribute_bitcount && This->extension_area_offset)
501 attribute_type = This->extension_area.attributes_type;
502 else if (attribute_bitcount)
503 attribute_type = ATTRIBUTE_ALPHA;
504 else
505 attribute_type = ATTRIBUTE_NO_ALPHA;
507 switch (This->header.image_type & ~IMAGETYPE_RLE)
509 case IMAGETYPE_COLORMAPPED:
510 switch (This->header.depth)
512 case 8:
513 memcpy(pPixelFormat, &GUID_WICPixelFormat8bppIndexed, sizeof(GUID));
514 break;
515 default:
516 FIXME("Unhandled indexed color depth %u\n", This->header.depth);
517 return E_NOTIMPL;
519 break;
520 case IMAGETYPE_TRUECOLOR:
521 switch (This->header.depth)
523 case 16:
524 switch (attribute_type)
526 case ATTRIBUTE_NO_ALPHA:
527 case ATTRIBUTE_UNDEFINED:
528 case ATTRIBUTE_UNDEFINED_PRESERVE:
529 memcpy(pPixelFormat, &GUID_WICPixelFormat16bppBGR555, sizeof(GUID));
530 break;
531 case ATTRIBUTE_ALPHA:
532 case ATTRIBUTE_PALPHA:
533 memcpy(pPixelFormat, &GUID_WICPixelFormat16bppBGRA5551, sizeof(GUID));
534 break;
535 default:
536 FIXME("Unhandled 16-bit attribute type %u\n", attribute_type);
537 return E_NOTIMPL;
539 break;
540 case 24:
541 memcpy(pPixelFormat, &GUID_WICPixelFormat24bppBGR, sizeof(GUID));
542 break;
543 case 32:
544 switch (attribute_type)
546 case ATTRIBUTE_NO_ALPHA:
547 case ATTRIBUTE_UNDEFINED:
548 case ATTRIBUTE_UNDEFINED_PRESERVE:
549 memcpy(pPixelFormat, &GUID_WICPixelFormat32bppBGR, sizeof(GUID));
550 break;
551 case ATTRIBUTE_ALPHA:
552 memcpy(pPixelFormat, &GUID_WICPixelFormat32bppBGRA, sizeof(GUID));
553 break;
554 case ATTRIBUTE_PALPHA:
555 memcpy(pPixelFormat, &GUID_WICPixelFormat32bppPBGRA, sizeof(GUID));
556 break;
557 default:
558 FIXME("Unhandled 32-bit attribute type %u\n", attribute_type);
559 return E_NOTIMPL;
561 break;
562 default:
563 FIXME("Unhandled truecolor depth %u\n", This->header.depth);
564 return E_NOTIMPL;
566 break;
567 case IMAGETYPE_GRAYSCALE:
568 switch (This->header.depth)
570 case 8:
571 memcpy(pPixelFormat, &GUID_WICPixelFormat8bppGray, sizeof(GUID));
572 break;
573 case 16:
574 memcpy(pPixelFormat, &GUID_WICPixelFormat16bppGray, sizeof(GUID));
575 break;
576 default:
577 FIXME("Unhandled grayscale depth %u\n", This->header.depth);
578 return E_NOTIMPL;
580 break;
581 default:
582 ERR("Unknown image type %u\n", This->header.image_type);
583 return E_FAIL;
586 return S_OK;
589 static HRESULT WINAPI TgaDecoder_Frame_GetResolution(IWICBitmapFrameDecode *iface,
590 double *pDpiX, double *pDpiY)
592 FIXME("(%p,%p,%p): stub\n", iface, pDpiX, pDpiY);
593 return E_NOTIMPL;
596 static HRESULT WINAPI TgaDecoder_Frame_CopyPalette(IWICBitmapFrameDecode *iface,
597 IWICPalette *pIPalette)
599 TgaDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
600 HRESULT hr=S_OK;
601 WICColor colors[256], *color;
602 BYTE *colormap_data;
603 WORD *wcolormap_data;
604 DWORD *dwcolormap_data;
605 LARGE_INTEGER seek;
606 ULONG bytesread;
607 int depth, attribute_bitcount, attribute_type;
608 int i;
610 TRACE("(%p,%p)\n", iface, pIPalette);
612 if (!This->colormap_length)
614 WARN("no colormap present in this file\n");
615 return WINCODEC_ERR_PALETTEUNAVAILABLE;
618 if (This->header.colormap_firstentry + This->header.colormap_length > 256)
620 FIXME("cannot read colormap with %i entries starting at %i\n",
621 This->header.colormap_firstentry + This->header.colormap_length,
622 This->header.colormap_firstentry);
623 return E_FAIL;
626 colormap_data = HeapAlloc(GetProcessHeap(), 0, This->colormap_length);
627 if (!colormap_data) return E_OUTOFMEMORY;
629 wcolormap_data = (WORD*)colormap_data;
630 dwcolormap_data = (DWORD*)colormap_data;
632 EnterCriticalSection(&This->lock);
634 seek.QuadPart = This->colormap_offset;
635 hr = IStream_Seek(This->stream, seek, STREAM_SEEK_SET, NULL);
637 if (SUCCEEDED(hr))
639 hr = IStream_Read(This->stream, colormap_data, This->colormap_length, &bytesread);
640 if (SUCCEEDED(hr) && bytesread != This->colormap_length)
642 WARN("expected %li bytes in colormap, got %li\n", This->colormap_length, bytesread);
643 hr = E_FAIL;
647 LeaveCriticalSection(&This->lock);
649 if (SUCCEEDED(hr))
651 attribute_bitcount = This->header.image_descriptor & IMAGE_ATTRIBUTE_BITCOUNT_MASK;
653 if (attribute_bitcount && This->extension_area_offset)
654 attribute_type = This->extension_area.attributes_type;
655 else if (attribute_bitcount)
656 attribute_type = ATTRIBUTE_ALPHA;
657 else
658 attribute_type = ATTRIBUTE_NO_ALPHA;
660 depth = This->header.colormap_entrysize;
661 if (depth == 15)
663 depth = 16;
664 attribute_type = ATTRIBUTE_NO_ALPHA;
667 memset(colors, 0, sizeof(colors));
669 color = &colors[This->header.colormap_firstentry];
671 /* Colormap entries can be in any truecolor format, and we have to convert them. */
672 switch (depth)
674 case 16:
675 switch (attribute_type)
677 case ATTRIBUTE_NO_ALPHA:
678 case ATTRIBUTE_UNDEFINED:
679 case ATTRIBUTE_UNDEFINED_PRESERVE:
680 for (i=0; i<This->header.colormap_length; i++)
682 WORD srcval = wcolormap_data[i];
683 *color++=0xff000000 | /* constant 255 alpha */
684 ((srcval << 9) & 0xf80000) | /* r */
685 ((srcval << 4) & 0x070000) | /* r - 3 bits */
686 ((srcval << 6) & 0x00f800) | /* g */
687 ((srcval << 1) & 0x000700) | /* g - 3 bits */
688 ((srcval << 3) & 0x0000f8) | /* b */
689 ((srcval >> 2) & 0x000007); /* b - 3 bits */
691 break;
692 case ATTRIBUTE_ALPHA:
693 case ATTRIBUTE_PALPHA:
694 for (i=0; i<This->header.colormap_length; i++)
696 WORD srcval = wcolormap_data[i];
697 *color++=((srcval & 0x8000) ? 0xff000000 : 0) | /* alpha */
698 ((srcval << 9) & 0xf80000) | /* r */
699 ((srcval << 4) & 0x070000) | /* r - 3 bits */
700 ((srcval << 6) & 0x00f800) | /* g */
701 ((srcval << 1) & 0x000700) | /* g - 3 bits */
702 ((srcval << 3) & 0x0000f8) | /* b */
703 ((srcval >> 2) & 0x000007); /* b - 3 bits */
705 break;
706 default:
707 FIXME("Unhandled 16-bit attribute type %u\n", attribute_type);
708 hr = E_NOTIMPL;
710 break;
711 case 24:
712 for (i=0; i<This->header.colormap_length; i++)
714 *color++=0xff000000 | /* alpha */
715 colormap_data[i*3+2] | /* red */
716 colormap_data[i*3+1] | /* green */
717 colormap_data[i*3]; /* blue */
719 break;
720 case 32:
721 switch (attribute_type)
723 case ATTRIBUTE_NO_ALPHA:
724 case ATTRIBUTE_UNDEFINED:
725 case ATTRIBUTE_UNDEFINED_PRESERVE:
726 for (i=0; i<This->header.colormap_length; i++)
727 *color++=dwcolormap_data[i]|0xff000000;
728 break;
729 case ATTRIBUTE_ALPHA:
730 for (i=0; i<This->header.colormap_length; i++)
731 *color++=dwcolormap_data[i];
732 break;
733 case ATTRIBUTE_PALPHA:
734 /* FIXME: Unpremultiply alpha */
735 default:
736 FIXME("Unhandled 16-bit attribute type %u\n", attribute_type);
737 hr = E_NOTIMPL;
739 break;
740 default:
741 FIXME("Unhandled truecolor depth %u\n", This->header.depth);
742 hr = E_NOTIMPL;
746 HeapFree(GetProcessHeap(), 0, colormap_data);
748 if (SUCCEEDED(hr))
749 hr = IWICPalette_InitializeCustom(pIPalette, colors, 256);
751 return hr;
754 static HRESULT TgaDecoder_ReadRLE(TgaDecoder *This, BYTE *imagebits, int datasize)
756 int i=0, j, bytesperpixel;
757 ULONG bytesread;
758 HRESULT hr=S_OK;
760 bytesperpixel = This->header.depth / 8;
762 while (i<datasize)
764 BYTE rc;
765 int count, size;
766 BYTE pixeldata[4];
768 hr = IStream_Read(This->stream, &rc, 1, &bytesread);
769 if (bytesread != 1) hr = E_FAIL;
770 if (FAILED(hr)) break;
772 count = (rc&0x7f)+1;
773 size = count * bytesperpixel;
775 if (size + i > datasize)
777 WARN("RLE packet too large\n");
778 hr = E_FAIL;
779 break;
782 if (rc&0x80)
784 /* Run-length packet */
785 hr = IStream_Read(This->stream, pixeldata, bytesperpixel, &bytesread);
786 if (bytesread != bytesperpixel) hr = E_FAIL;
787 if (FAILED(hr)) break;
789 if (bytesperpixel == 1)
790 memset(&imagebits[i], pixeldata[0], count);
791 else
793 for (j=0; j<count; j++)
794 memcpy(&imagebits[i+j*bytesperpixel], pixeldata, bytesperpixel);
797 else
799 /* Raw packet */
800 hr = IStream_Read(This->stream, &imagebits[i], size, &bytesread);
801 if (bytesread != size) hr = E_FAIL;
802 if (FAILED(hr)) break;
805 i += size;
808 return hr;
811 static HRESULT TgaDecoder_ReadImage(TgaDecoder *This)
813 HRESULT hr=S_OK;
814 int datasize;
815 LARGE_INTEGER seek;
816 ULONG bytesread;
818 if (This->imagebits)
819 return S_OK;
821 EnterCriticalSection(&This->lock);
823 if (!This->imagebits)
825 if (This->header.image_descriptor & IMAGE_RIGHTTOLEFT)
827 FIXME("Right to left image reading not implemented\n");
828 hr = E_NOTIMPL;
831 if (SUCCEEDED(hr))
833 datasize = This->header.width * This->header.height * (This->header.depth / 8);
834 This->imagebits = HeapAlloc(GetProcessHeap(), 0, datasize);
835 if (!This->imagebits) hr = E_OUTOFMEMORY;
838 if (SUCCEEDED(hr))
840 seek.QuadPart = This->image_offset;
841 hr = IStream_Seek(This->stream, seek, STREAM_SEEK_SET, NULL);
844 if (SUCCEEDED(hr))
846 if (This->header.image_type & IMAGETYPE_RLE)
848 hr = TgaDecoder_ReadRLE(This, This->imagebits, datasize);
850 else
852 hr = IStream_Read(This->stream, This->imagebits, datasize, &bytesread);
853 if (SUCCEEDED(hr) && bytesread != datasize)
854 hr = E_FAIL;
858 if (SUCCEEDED(hr))
860 if (This->header.image_descriptor & IMAGE_TOPTOBOTTOM)
862 This->origin = This->imagebits;
863 This->stride = This->header.width * (This->header.depth / 8);
865 else
867 This->stride = -This->header.width * (This->header.depth / 8);
868 This->origin = This->imagebits + This->header.width * (This->header.height - 1) * (This->header.depth / 8);
871 else
873 HeapFree(GetProcessHeap(), 0, This->imagebits);
874 This->imagebits = NULL;
878 LeaveCriticalSection(&This->lock);
880 return hr;
883 static HRESULT WINAPI TgaDecoder_Frame_CopyPixels(IWICBitmapFrameDecode *iface,
884 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
886 TgaDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
887 HRESULT hr;
889 TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer);
891 hr = TgaDecoder_ReadImage(This);
893 if (SUCCEEDED(hr))
895 hr = copy_pixels(This->header.depth, This->origin,
896 This->header.width, This->header.height, This->stride,
897 prc, cbStride, cbBufferSize, pbBuffer);
900 return hr;
903 static HRESULT WINAPI TgaDecoder_Frame_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
904 IWICMetadataQueryReader **ppIMetadataQueryReader)
906 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryReader);
907 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
910 static HRESULT WINAPI TgaDecoder_Frame_GetColorContexts(IWICBitmapFrameDecode *iface,
911 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
913 FIXME("(%p,%u,%p,%p): stub\n", iface, cCount, ppIColorContexts, pcActualCount);
914 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
917 static HRESULT WINAPI TgaDecoder_Frame_GetThumbnail(IWICBitmapFrameDecode *iface,
918 IWICBitmapSource **ppIThumbnail)
920 FIXME("(%p,%p): stub\n", iface, ppIThumbnail);
921 return WINCODEC_ERR_CODECNOTHUMBNAIL;
924 static const IWICBitmapFrameDecodeVtbl TgaDecoder_Frame_Vtbl = {
925 TgaDecoder_Frame_QueryInterface,
926 TgaDecoder_Frame_AddRef,
927 TgaDecoder_Frame_Release,
928 TgaDecoder_Frame_GetSize,
929 TgaDecoder_Frame_GetPixelFormat,
930 TgaDecoder_Frame_GetResolution,
931 TgaDecoder_Frame_CopyPalette,
932 TgaDecoder_Frame_CopyPixels,
933 TgaDecoder_Frame_GetMetadataQueryReader,
934 TgaDecoder_Frame_GetColorContexts,
935 TgaDecoder_Frame_GetThumbnail
938 HRESULT TgaDecoder_CreateInstance(REFIID iid, void** ppv)
940 TgaDecoder *This;
941 HRESULT ret;
943 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
945 *ppv = NULL;
947 This = HeapAlloc(GetProcessHeap(), 0, sizeof(TgaDecoder));
948 if (!This) return E_OUTOFMEMORY;
950 This->IWICBitmapDecoder_iface.lpVtbl = &TgaDecoder_Vtbl;
951 This->IWICBitmapFrameDecode_iface.lpVtbl = &TgaDecoder_Frame_Vtbl;
952 This->ref = 1;
953 This->initialized = FALSE;
954 This->stream = NULL;
955 This->imagebits = NULL;
956 InitializeCriticalSection(&This->lock);
957 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": TgaDecoder.lock");
959 ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
960 IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
962 return ret;