msvcrt: Move btowc implementation to mbcs.c file.
[wine.git] / dlls / windowscodecs / tgaformat.c
blobb572d8f686742af7b14edd7df0c65d5b7c5bf372
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 "config.h"
20 #include "wine/port.h"
22 #include <stdarg.h>
24 #define COBJMACROS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "objbase.h"
30 #include "wincodecs_private.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
36 #include "pshpack1.h"
38 typedef struct {
39 BYTE id_length;
40 BYTE colormap_type;
41 BYTE image_type;
42 /* Colormap Specification */
43 WORD colormap_firstentry;
44 WORD colormap_length;
45 BYTE colormap_entrysize;
46 /* Image Specification */
47 WORD xorigin;
48 WORD yorigin;
49 WORD width;
50 WORD height;
51 BYTE depth;
52 BYTE image_descriptor;
53 } tga_header;
55 #define IMAGETYPE_COLORMAPPED 1
56 #define IMAGETYPE_TRUECOLOR 2
57 #define IMAGETYPE_GRAYSCALE 3
58 #define IMAGETYPE_RLE 8
60 #define IMAGE_ATTRIBUTE_BITCOUNT_MASK 0xf
61 #define IMAGE_RIGHTTOLEFT 0x10
62 #define IMAGE_TOPTOBOTTOM 0x20
64 typedef struct {
65 DWORD extension_area_offset;
66 DWORD developer_directory_offset;
67 char magic[18];
68 } tga_footer;
70 static const BYTE tga_footer_magic[18] = "TRUEVISION-XFILE.";
72 typedef struct {
73 WORD size;
74 char author_name[41];
75 char author_comments[324];
76 WORD timestamp[6];
77 char job_name[41];
78 WORD job_timestamp[6];
79 char software_id[41];
80 WORD software_version;
81 char software_version_letter;
82 DWORD key_color;
83 WORD pixel_width;
84 WORD pixel_height;
85 WORD gamma_numerator;
86 WORD gamma_denominator;
87 DWORD color_correction_offset;
88 DWORD thumbnail_offset;
89 DWORD scanline_offset;
90 BYTE attributes_type;
91 } tga_extension_area;
93 #define ATTRIBUTE_NO_ALPHA 0
94 #define ATTRIBUTE_UNDEFINED 1
95 #define ATTRIBUTE_UNDEFINED_PRESERVE 2
96 #define ATTRIBUTE_ALPHA 3
97 #define ATTRIBUTE_PALPHA 4
99 #include "poppack.h"
101 typedef struct {
102 IWICBitmapDecoder IWICBitmapDecoder_iface;
103 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
104 LONG ref;
105 BOOL initialized;
106 IStream *stream;
107 tga_header header;
108 tga_extension_area extension_area;
109 BYTE *imagebits;
110 BYTE *origin;
111 int stride;
112 ULONG id_offset;
113 ULONG colormap_length;
114 ULONG colormap_offset;
115 ULONG image_offset;
116 ULONG extension_area_offset;
117 ULONG developer_directory_offset;
118 CRITICAL_SECTION lock;
119 } TgaDecoder;
121 static inline TgaDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
123 return CONTAINING_RECORD(iface, TgaDecoder, IWICBitmapDecoder_iface);
126 static inline TgaDecoder *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
128 return CONTAINING_RECORD(iface, TgaDecoder, IWICBitmapFrameDecode_iface);
131 static HRESULT WINAPI TgaDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
132 void **ppv)
134 TgaDecoder *This = impl_from_IWICBitmapDecoder(iface);
135 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
137 if (!ppv) return E_INVALIDARG;
139 if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICBitmapDecoder, iid))
141 *ppv = &This->IWICBitmapDecoder_iface;
143 else
145 *ppv = NULL;
146 return E_NOINTERFACE;
149 IUnknown_AddRef((IUnknown*)*ppv);
150 return S_OK;
153 static ULONG WINAPI TgaDecoder_AddRef(IWICBitmapDecoder *iface)
155 TgaDecoder *This = impl_from_IWICBitmapDecoder(iface);
156 ULONG ref = InterlockedIncrement(&This->ref);
158 TRACE("(%p) refcount=%u\n", iface, ref);
160 return ref;
163 static ULONG WINAPI TgaDecoder_Release(IWICBitmapDecoder *iface)
165 TgaDecoder *This = impl_from_IWICBitmapDecoder(iface);
166 ULONG ref = InterlockedDecrement(&This->ref);
168 TRACE("(%p) refcount=%u\n", iface, ref);
170 if (ref == 0)
172 This->lock.DebugInfo->Spare[0] = 0;
173 DeleteCriticalSection(&This->lock);
174 if (This->stream)
175 IStream_Release(This->stream);
176 HeapFree(GetProcessHeap(), 0, This->imagebits);
177 HeapFree(GetProcessHeap(), 0, This);
180 return ref;
183 static HRESULT WINAPI TgaDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream,
184 DWORD *capability)
186 HRESULT hr;
188 TRACE("(%p,%p,%p)\n", iface, stream, capability);
190 if (!stream || !capability) return E_INVALIDARG;
192 hr = IWICBitmapDecoder_Initialize(iface, stream, WICDecodeMetadataCacheOnDemand);
193 if (hr != S_OK) return hr;
195 *capability = WICBitmapDecoderCapabilityCanDecodeAllImages |
196 WICBitmapDecoderCapabilityCanDecodeSomeImages;
197 return S_OK;
200 static HRESULT WINAPI TgaDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
201 WICDecodeOptions cacheOptions)
203 TgaDecoder *This = impl_from_IWICBitmapDecoder(iface);
204 HRESULT hr=S_OK;
205 DWORD bytesread;
206 LARGE_INTEGER seek;
207 tga_footer footer;
208 int attribute_bitcount;
209 int mapped_depth=0;
211 TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOptions);
213 EnterCriticalSection(&This->lock);
215 if (This->initialized)
217 hr = WINCODEC_ERR_WRONGSTATE;
218 goto end;
221 seek.QuadPart = 0;
222 hr = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
223 if (FAILED(hr)) goto end;
225 hr = IStream_Read(pIStream, &This->header, sizeof(tga_header), &bytesread);
226 if (SUCCEEDED(hr) && bytesread != sizeof(tga_header))
228 TRACE("got only %u bytes\n", bytesread);
229 hr = E_FAIL;
231 if (FAILED(hr)) goto end;
233 TRACE("imagetype=%u, colormap type=%u, depth=%u, image descriptor=0x%x\n",
234 This->header.image_type, This->header.colormap_type,
235 This->header.depth, This->header.image_descriptor);
237 /* Sanity checking. Since TGA has no clear identifying markers, we need
238 * to be careful to not load a non-TGA image. */
239 switch (This->header.image_type)
241 case IMAGETYPE_COLORMAPPED:
242 case IMAGETYPE_COLORMAPPED|IMAGETYPE_RLE:
243 if (This->header.colormap_type != 1)
244 hr = E_FAIL;
245 mapped_depth = This->header.colormap_entrysize;
246 break;
247 case IMAGETYPE_TRUECOLOR:
248 case IMAGETYPE_TRUECOLOR|IMAGETYPE_RLE:
249 if (This->header.colormap_type != 0 && This->header.colormap_type != 1)
250 hr = E_FAIL;
251 mapped_depth = This->header.depth;
252 break;
253 case IMAGETYPE_GRAYSCALE:
254 case IMAGETYPE_GRAYSCALE|IMAGETYPE_RLE:
255 if (This->header.colormap_type != 0)
256 hr = E_FAIL;
257 mapped_depth = 0;
258 break;
259 default:
260 hr = E_FAIL;
263 if (This->header.depth != 8 && This->header.depth != 16 &&
264 This->header.depth != 24 && This->header.depth != 32)
265 hr = E_FAIL;
267 if ((This->header.image_descriptor & 0xc0) != 0)
268 hr = E_FAIL;
270 attribute_bitcount = This->header.image_descriptor & IMAGE_ATTRIBUTE_BITCOUNT_MASK;
272 if (attribute_bitcount &&
273 !((mapped_depth == 32 && attribute_bitcount == 8) ||
274 (mapped_depth == 16 && attribute_bitcount == 1)))
275 hr = E_FAIL;
277 if (FAILED(hr))
279 WARN("bad tga header\n");
280 goto end;
283 /* Locate data in the file based on the header. */
284 This->id_offset = sizeof(tga_header);
285 This->colormap_offset = This->id_offset + This->header.id_length;
286 if (This->header.colormap_type == 1)
287 This->colormap_length = ((This->header.colormap_entrysize+7)/8) * This->header.colormap_length;
288 else
289 This->colormap_length = 0;
290 This->image_offset = This->colormap_offset + This->colormap_length;
292 /* Read footer if there is one */
293 seek.QuadPart = -(LONGLONG)sizeof(tga_footer);
294 hr = IStream_Seek(pIStream, seek, STREAM_SEEK_END, NULL);
296 if (SUCCEEDED(hr)) {
297 hr = IStream_Read(pIStream, &footer, sizeof(tga_footer), &bytesread);
298 if (SUCCEEDED(hr) && bytesread != sizeof(tga_footer))
300 TRACE("got only %u footer bytes\n", bytesread);
301 hr = E_FAIL;
304 if (memcmp(footer.magic, tga_footer_magic, sizeof(tga_footer_magic)) == 0)
306 This->extension_area_offset = footer.extension_area_offset;
307 This->developer_directory_offset = footer.developer_directory_offset;
309 else
311 This->extension_area_offset = 0;
312 This->developer_directory_offset = 0;
315 else
317 /* File is too small to have a footer. */
318 This->extension_area_offset = 0;
319 This->developer_directory_offset = 0;
320 hr = S_OK;
323 if (This->extension_area_offset)
325 seek.QuadPart = This->extension_area_offset;
326 hr = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
327 if (FAILED(hr)) goto end;
329 hr = IStream_Read(pIStream, &This->extension_area, sizeof(tga_extension_area), &bytesread);
330 if (SUCCEEDED(hr) && bytesread != sizeof(tga_extension_area))
332 TRACE("got only %u extension area bytes\n", bytesread);
333 hr = E_FAIL;
335 if (SUCCEEDED(hr) && This->extension_area.size < 495)
337 TRACE("extension area is only %u bytes long\n", This->extension_area.size);
338 hr = E_FAIL;
340 if (FAILED(hr)) goto end;
343 IStream_AddRef(pIStream);
344 This->stream = pIStream;
345 This->initialized = TRUE;
347 end:
348 LeaveCriticalSection(&This->lock);
349 return hr;
352 static HRESULT WINAPI TgaDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
353 GUID *pguidContainerFormat)
355 memcpy(pguidContainerFormat, &GUID_WineContainerFormatTga, sizeof(GUID));
356 return S_OK;
359 static HRESULT WINAPI TgaDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
360 IWICBitmapDecoderInfo **ppIDecoderInfo)
362 TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
364 return get_decoder_info(&CLSID_WineTgaDecoder, ppIDecoderInfo);
367 static HRESULT WINAPI TgaDecoder_CopyPalette(IWICBitmapDecoder *iface,
368 IWICPalette *pIPalette)
370 FIXME("(%p,%p): stub\n", iface, pIPalette);
371 return E_NOTIMPL;
374 static HRESULT WINAPI TgaDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
375 IWICMetadataQueryReader **ppIMetadataQueryReader)
377 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryReader);
378 return E_NOTIMPL;
381 static HRESULT WINAPI TgaDecoder_GetPreview(IWICBitmapDecoder *iface,
382 IWICBitmapSource **ppIBitmapSource)
384 FIXME("(%p,%p): stub\n", iface, ppIBitmapSource);
385 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
388 static HRESULT WINAPI TgaDecoder_GetColorContexts(IWICBitmapDecoder *iface,
389 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
391 FIXME("(%p,%u,%p,%p): stub\n", iface, cCount, ppIColorContexts, pcActualCount);
392 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
395 static HRESULT WINAPI TgaDecoder_GetThumbnail(IWICBitmapDecoder *iface,
396 IWICBitmapSource **ppIThumbnail)
398 FIXME("(%p,%p): stub\n", iface, ppIThumbnail);
399 return WINCODEC_ERR_CODECNOTHUMBNAIL;
402 static HRESULT WINAPI TgaDecoder_GetFrameCount(IWICBitmapDecoder *iface,
403 UINT *pCount)
405 if (!pCount) return E_INVALIDARG;
407 *pCount = 1;
408 return S_OK;
411 static HRESULT WINAPI TgaDecoder_GetFrame(IWICBitmapDecoder *iface,
412 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
414 TgaDecoder *This = impl_from_IWICBitmapDecoder(iface);
415 TRACE("(%p,%p)\n", iface, ppIBitmapFrame);
417 if (!This->initialized) return WINCODEC_ERR_FRAMEMISSING;
419 if (index != 0) return E_INVALIDARG;
421 IWICBitmapDecoder_AddRef(iface);
422 *ppIBitmapFrame = &This->IWICBitmapFrameDecode_iface;
424 return S_OK;
427 static const IWICBitmapDecoderVtbl TgaDecoder_Vtbl = {
428 TgaDecoder_QueryInterface,
429 TgaDecoder_AddRef,
430 TgaDecoder_Release,
431 TgaDecoder_QueryCapability,
432 TgaDecoder_Initialize,
433 TgaDecoder_GetContainerFormat,
434 TgaDecoder_GetDecoderInfo,
435 TgaDecoder_CopyPalette,
436 TgaDecoder_GetMetadataQueryReader,
437 TgaDecoder_GetPreview,
438 TgaDecoder_GetColorContexts,
439 TgaDecoder_GetThumbnail,
440 TgaDecoder_GetFrameCount,
441 TgaDecoder_GetFrame
444 static HRESULT WINAPI TgaDecoder_Frame_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
445 void **ppv)
447 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
449 if (!ppv) return E_INVALIDARG;
451 if (IsEqualIID(&IID_IUnknown, iid) ||
452 IsEqualIID(&IID_IWICBitmapSource, iid) ||
453 IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
455 *ppv = iface;
457 else
459 *ppv = NULL;
460 return E_NOINTERFACE;
463 IUnknown_AddRef((IUnknown*)*ppv);
464 return S_OK;
467 static ULONG WINAPI TgaDecoder_Frame_AddRef(IWICBitmapFrameDecode *iface)
469 TgaDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
470 return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface);
473 static ULONG WINAPI TgaDecoder_Frame_Release(IWICBitmapFrameDecode *iface)
475 TgaDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
476 return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
479 static HRESULT WINAPI TgaDecoder_Frame_GetSize(IWICBitmapFrameDecode *iface,
480 UINT *puiWidth, UINT *puiHeight)
482 TgaDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
484 *puiWidth = This->header.width;
485 *puiHeight = This->header.height;
487 TRACE("(%p)->(%u,%u)\n", iface, *puiWidth, *puiHeight);
489 return S_OK;
492 static HRESULT WINAPI TgaDecoder_Frame_GetPixelFormat(IWICBitmapFrameDecode *iface,
493 WICPixelFormatGUID *pPixelFormat)
495 TgaDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
496 int attribute_bitcount;
497 byte attribute_type;
499 TRACE("(%p,%p)\n", iface, pPixelFormat);
501 attribute_bitcount = This->header.image_descriptor & IMAGE_ATTRIBUTE_BITCOUNT_MASK;
503 if (attribute_bitcount && This->extension_area_offset)
504 attribute_type = This->extension_area.attributes_type;
505 else if (attribute_bitcount)
506 attribute_type = ATTRIBUTE_ALPHA;
507 else
508 attribute_type = ATTRIBUTE_NO_ALPHA;
510 switch (This->header.image_type & ~IMAGETYPE_RLE)
512 case IMAGETYPE_COLORMAPPED:
513 switch (This->header.depth)
515 case 8:
516 memcpy(pPixelFormat, &GUID_WICPixelFormat8bppIndexed, sizeof(GUID));
517 break;
518 default:
519 FIXME("Unhandled indexed color depth %u\n", This->header.depth);
520 return E_NOTIMPL;
522 break;
523 case IMAGETYPE_TRUECOLOR:
524 switch (This->header.depth)
526 case 16:
527 switch (attribute_type)
529 case ATTRIBUTE_NO_ALPHA:
530 case ATTRIBUTE_UNDEFINED:
531 case ATTRIBUTE_UNDEFINED_PRESERVE:
532 memcpy(pPixelFormat, &GUID_WICPixelFormat16bppBGR555, sizeof(GUID));
533 break;
534 case ATTRIBUTE_ALPHA:
535 case ATTRIBUTE_PALPHA:
536 memcpy(pPixelFormat, &GUID_WICPixelFormat16bppBGRA5551, sizeof(GUID));
537 break;
538 default:
539 FIXME("Unhandled 16-bit attribute type %u\n", attribute_type);
540 return E_NOTIMPL;
542 break;
543 case 24:
544 memcpy(pPixelFormat, &GUID_WICPixelFormat24bppBGR, sizeof(GUID));
545 break;
546 case 32:
547 switch (attribute_type)
549 case ATTRIBUTE_NO_ALPHA:
550 case ATTRIBUTE_UNDEFINED:
551 case ATTRIBUTE_UNDEFINED_PRESERVE:
552 memcpy(pPixelFormat, &GUID_WICPixelFormat32bppBGR, sizeof(GUID));
553 break;
554 case ATTRIBUTE_ALPHA:
555 memcpy(pPixelFormat, &GUID_WICPixelFormat32bppBGRA, sizeof(GUID));
556 break;
557 case ATTRIBUTE_PALPHA:
558 memcpy(pPixelFormat, &GUID_WICPixelFormat32bppPBGRA, sizeof(GUID));
559 break;
560 default:
561 FIXME("Unhandled 32-bit attribute type %u\n", attribute_type);
562 return E_NOTIMPL;
564 break;
565 default:
566 FIXME("Unhandled truecolor depth %u\n", This->header.depth);
567 return E_NOTIMPL;
569 break;
570 case IMAGETYPE_GRAYSCALE:
571 switch (This->header.depth)
573 case 8:
574 memcpy(pPixelFormat, &GUID_WICPixelFormat8bppGray, sizeof(GUID));
575 break;
576 case 16:
577 memcpy(pPixelFormat, &GUID_WICPixelFormat16bppGray, sizeof(GUID));
578 break;
579 default:
580 FIXME("Unhandled grayscale depth %u\n", This->header.depth);
581 return E_NOTIMPL;
583 break;
584 default:
585 ERR("Unknown image type %u\n", This->header.image_type);
586 return E_FAIL;
589 return S_OK;
592 static HRESULT WINAPI TgaDecoder_Frame_GetResolution(IWICBitmapFrameDecode *iface,
593 double *pDpiX, double *pDpiY)
595 FIXME("(%p,%p,%p): stub\n", iface, pDpiX, pDpiY);
596 return E_NOTIMPL;
599 static HRESULT WINAPI TgaDecoder_Frame_CopyPalette(IWICBitmapFrameDecode *iface,
600 IWICPalette *pIPalette)
602 TgaDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
603 HRESULT hr=S_OK;
604 WICColor colors[256], *color;
605 BYTE *colormap_data;
606 WORD *wcolormap_data;
607 DWORD *dwcolormap_data;
608 LARGE_INTEGER seek;
609 ULONG bytesread;
610 int depth, attribute_bitcount, attribute_type;
611 int i;
613 TRACE("(%p,%p)\n", iface, pIPalette);
615 if (!This->colormap_length)
617 WARN("no colormap present in this file\n");
618 return WINCODEC_ERR_PALETTEUNAVAILABLE;
621 if (This->header.colormap_firstentry + This->header.colormap_length > 256)
623 FIXME("cannot read colormap with %i entries starting at %i\n",
624 This->header.colormap_firstentry + This->header.colormap_length,
625 This->header.colormap_firstentry);
626 return E_FAIL;
629 colormap_data = HeapAlloc(GetProcessHeap(), 0, This->colormap_length);
630 if (!colormap_data) return E_OUTOFMEMORY;
632 wcolormap_data = (WORD*)colormap_data;
633 dwcolormap_data = (DWORD*)colormap_data;
635 EnterCriticalSection(&This->lock);
637 seek.QuadPart = This->colormap_offset;
638 hr = IStream_Seek(This->stream, seek, STREAM_SEEK_SET, NULL);
640 if (SUCCEEDED(hr))
642 hr = IStream_Read(This->stream, colormap_data, This->colormap_length, &bytesread);
643 if (SUCCEEDED(hr) && bytesread != This->colormap_length)
645 WARN("expected %i bytes in colormap, got %i\n", This->colormap_length, bytesread);
646 hr = E_FAIL;
650 LeaveCriticalSection(&This->lock);
652 if (SUCCEEDED(hr))
654 attribute_bitcount = This->header.image_descriptor & IMAGE_ATTRIBUTE_BITCOUNT_MASK;
656 if (attribute_bitcount && This->extension_area_offset)
657 attribute_type = This->extension_area.attributes_type;
658 else if (attribute_bitcount)
659 attribute_type = ATTRIBUTE_ALPHA;
660 else
661 attribute_type = ATTRIBUTE_NO_ALPHA;
663 depth = This->header.colormap_entrysize;
664 if (depth == 15)
666 depth = 16;
667 attribute_type = ATTRIBUTE_NO_ALPHA;
670 memset(colors, 0, sizeof(colors));
672 color = &colors[This->header.colormap_firstentry];
674 /* Colormap entries can be in any truecolor format, and we have to convert them. */
675 switch (depth)
677 case 16:
678 switch (attribute_type)
680 case ATTRIBUTE_NO_ALPHA:
681 case ATTRIBUTE_UNDEFINED:
682 case ATTRIBUTE_UNDEFINED_PRESERVE:
683 for (i=0; i<This->header.colormap_length; i++)
685 WORD srcval = wcolormap_data[i];
686 *color++=0xff000000 | /* constant 255 alpha */
687 ((srcval << 9) & 0xf80000) | /* r */
688 ((srcval << 4) & 0x070000) | /* r - 3 bits */
689 ((srcval << 6) & 0x00f800) | /* g */
690 ((srcval << 1) & 0x000700) | /* g - 3 bits */
691 ((srcval << 3) & 0x0000f8) | /* b */
692 ((srcval >> 2) & 0x000007); /* b - 3 bits */
694 break;
695 case ATTRIBUTE_ALPHA:
696 case ATTRIBUTE_PALPHA:
697 for (i=0; i<This->header.colormap_length; i++)
699 WORD srcval = wcolormap_data[i];
700 *color++=((srcval & 0x8000) ? 0xff000000 : 0) | /* alpha */
701 ((srcval << 9) & 0xf80000) | /* r */
702 ((srcval << 4) & 0x070000) | /* r - 3 bits */
703 ((srcval << 6) & 0x00f800) | /* g */
704 ((srcval << 1) & 0x000700) | /* g - 3 bits */
705 ((srcval << 3) & 0x0000f8) | /* b */
706 ((srcval >> 2) & 0x000007); /* b - 3 bits */
708 break;
709 default:
710 FIXME("Unhandled 16-bit attribute type %u\n", attribute_type);
711 hr = E_NOTIMPL;
713 break;
714 case 24:
715 for (i=0; i<This->header.colormap_length; i++)
717 *color++=0xff000000 | /* alpha */
718 colormap_data[i*3+2] | /* red */
719 colormap_data[i*3+1] | /* green */
720 colormap_data[i*3]; /* blue */
722 break;
723 case 32:
724 switch (attribute_type)
726 case ATTRIBUTE_NO_ALPHA:
727 case ATTRIBUTE_UNDEFINED:
728 case ATTRIBUTE_UNDEFINED_PRESERVE:
729 for (i=0; i<This->header.colormap_length; i++)
730 *color++=dwcolormap_data[i]|0xff000000;
731 break;
732 case ATTRIBUTE_ALPHA:
733 for (i=0; i<This->header.colormap_length; i++)
734 *color++=dwcolormap_data[i];
735 break;
736 case ATTRIBUTE_PALPHA:
737 /* FIXME: Unpremultiply alpha */
738 default:
739 FIXME("Unhandled 16-bit attribute type %u\n", attribute_type);
740 hr = E_NOTIMPL;
742 break;
743 default:
744 FIXME("Unhandled truecolor depth %u\n", This->header.depth);
745 hr = E_NOTIMPL;
749 HeapFree(GetProcessHeap(), 0, colormap_data);
751 if (SUCCEEDED(hr))
752 hr = IWICPalette_InitializeCustom(pIPalette, colors, 256);
754 return hr;
757 static HRESULT TgaDecoder_ReadRLE(TgaDecoder *This, BYTE *imagebits, int datasize)
759 int i=0, j, bytesperpixel;
760 ULONG bytesread;
761 HRESULT hr=S_OK;
763 bytesperpixel = This->header.depth / 8;
765 while (i<datasize)
767 BYTE rc;
768 int count, size;
769 BYTE pixeldata[4];
771 hr = IStream_Read(This->stream, &rc, 1, &bytesread);
772 if (bytesread != 1) hr = E_FAIL;
773 if (FAILED(hr)) break;
775 count = (rc&0x7f)+1;
776 size = count * bytesperpixel;
778 if (size + i > datasize)
780 WARN("RLE packet too large\n");
781 hr = E_FAIL;
782 break;
785 if (rc&0x80)
787 /* Run-length packet */
788 hr = IStream_Read(This->stream, pixeldata, bytesperpixel, &bytesread);
789 if (bytesread != bytesperpixel) hr = E_FAIL;
790 if (FAILED(hr)) break;
792 if (bytesperpixel == 1)
793 memset(&imagebits[i], pixeldata[0], count);
794 else
796 for (j=0; j<count; j++)
797 memcpy(&imagebits[i+j*bytesperpixel], pixeldata, bytesperpixel);
800 else
802 /* Raw packet */
803 hr = IStream_Read(This->stream, &imagebits[i], size, &bytesread);
804 if (bytesread != size) hr = E_FAIL;
805 if (FAILED(hr)) break;
808 i += size;
811 return hr;
814 static HRESULT TgaDecoder_ReadImage(TgaDecoder *This)
816 HRESULT hr=S_OK;
817 int datasize;
818 LARGE_INTEGER seek;
819 ULONG bytesread;
821 if (This->imagebits)
822 return S_OK;
824 EnterCriticalSection(&This->lock);
826 if (!This->imagebits)
828 if (This->header.image_descriptor & IMAGE_RIGHTTOLEFT)
830 FIXME("Right to left image reading not implemented\n");
831 hr = E_NOTIMPL;
834 if (SUCCEEDED(hr))
836 datasize = This->header.width * This->header.height * (This->header.depth / 8);
837 This->imagebits = HeapAlloc(GetProcessHeap(), 0, datasize);
838 if (!This->imagebits) hr = E_OUTOFMEMORY;
841 if (SUCCEEDED(hr))
843 seek.QuadPart = This->image_offset;
844 hr = IStream_Seek(This->stream, seek, STREAM_SEEK_SET, NULL);
847 if (SUCCEEDED(hr))
849 if (This->header.image_type & IMAGETYPE_RLE)
851 hr = TgaDecoder_ReadRLE(This, This->imagebits, datasize);
853 else
855 hr = IStream_Read(This->stream, This->imagebits, datasize, &bytesread);
856 if (SUCCEEDED(hr) && bytesread != datasize)
857 hr = E_FAIL;
861 if (SUCCEEDED(hr))
863 if (This->header.image_descriptor & IMAGE_TOPTOBOTTOM)
865 This->origin = This->imagebits;
866 This->stride = This->header.width * (This->header.depth / 8);
868 else
870 This->stride = -This->header.width * (This->header.depth / 8);
871 This->origin = This->imagebits + This->header.width * (This->header.height - 1) * (This->header.depth / 8);
874 else
876 HeapFree(GetProcessHeap(), 0, This->imagebits);
877 This->imagebits = NULL;
881 LeaveCriticalSection(&This->lock);
883 return hr;
886 static HRESULT WINAPI TgaDecoder_Frame_CopyPixels(IWICBitmapFrameDecode *iface,
887 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
889 TgaDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
890 HRESULT hr;
892 TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer);
894 hr = TgaDecoder_ReadImage(This);
896 if (SUCCEEDED(hr))
898 hr = copy_pixels(This->header.depth, This->origin,
899 This->header.width, This->header.height, This->stride,
900 prc, cbStride, cbBufferSize, pbBuffer);
903 return hr;
906 static HRESULT WINAPI TgaDecoder_Frame_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
907 IWICMetadataQueryReader **ppIMetadataQueryReader)
909 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryReader);
910 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
913 static HRESULT WINAPI TgaDecoder_Frame_GetColorContexts(IWICBitmapFrameDecode *iface,
914 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
916 FIXME("(%p,%u,%p,%p): stub\n", iface, cCount, ppIColorContexts, pcActualCount);
917 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
920 static HRESULT WINAPI TgaDecoder_Frame_GetThumbnail(IWICBitmapFrameDecode *iface,
921 IWICBitmapSource **ppIThumbnail)
923 FIXME("(%p,%p): stub\n", iface, ppIThumbnail);
924 return WINCODEC_ERR_CODECNOTHUMBNAIL;
927 static const IWICBitmapFrameDecodeVtbl TgaDecoder_Frame_Vtbl = {
928 TgaDecoder_Frame_QueryInterface,
929 TgaDecoder_Frame_AddRef,
930 TgaDecoder_Frame_Release,
931 TgaDecoder_Frame_GetSize,
932 TgaDecoder_Frame_GetPixelFormat,
933 TgaDecoder_Frame_GetResolution,
934 TgaDecoder_Frame_CopyPalette,
935 TgaDecoder_Frame_CopyPixels,
936 TgaDecoder_Frame_GetMetadataQueryReader,
937 TgaDecoder_Frame_GetColorContexts,
938 TgaDecoder_Frame_GetThumbnail
941 HRESULT TgaDecoder_CreateInstance(REFIID iid, void** ppv)
943 TgaDecoder *This;
944 HRESULT ret;
946 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
948 *ppv = NULL;
950 This = HeapAlloc(GetProcessHeap(), 0, sizeof(TgaDecoder));
951 if (!This) return E_OUTOFMEMORY;
953 This->IWICBitmapDecoder_iface.lpVtbl = &TgaDecoder_Vtbl;
954 This->IWICBitmapFrameDecode_iface.lpVtbl = &TgaDecoder_Frame_Vtbl;
955 This->ref = 1;
956 This->initialized = FALSE;
957 This->stream = NULL;
958 This->imagebits = NULL;
959 InitializeCriticalSection(&This->lock);
960 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": TgaDecoder.lock");
962 ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
963 IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
965 return ret;