From 72930dc0724b3bf88e4f888b339e9d567c09d44a Mon Sep 17 00:00:00 2001
From: Dmitry Timoshkov <dmitry@baikal.ru>
Date: Fri, 9 Dec 2016 12:33:30 +0800
Subject: windowscodecs: Add support for 3bps RGB format to TIFF decoder.

---
 dlls/windowscodecs/tiffformat.c | 78 +++++++++++++++++++++++++++++++++++++++--
 1 file changed, 75 insertions(+), 3 deletions(-)

diff --git a/dlls/windowscodecs/tiffformat.c b/dlls/windowscodecs/tiffformat.c
index 166bacd..9906d75 100644
--- a/dlls/windowscodecs/tiffformat.c
+++ b/dlls/windowscodecs/tiffformat.c
@@ -407,8 +407,6 @@ static HRESULT tiff_get_decode_info(TIFF *tiff, tiff_decode_info *decode_info)
         }
         break;
     case 2: /* RGB */
-        decode_info->bpp = bps * samples;
-
         if (samples == 4)
         {
             ret = pTIFFGetField(tiff, TIFFTAG_EXTRASAMPLES, &extra_sample_count, &extra_samples);
@@ -425,8 +423,11 @@ static HRESULT tiff_get_decode_info(TIFF *tiff, tiff_decode_info *decode_info)
             return E_FAIL;
         }
 
+        decode_info->bpp = max(bps, 8) * samples;
+        decode_info->source_bpp = bps * samples;
         switch(bps)
         {
+        case 1:
         case 8:
             decode_info->reverse_bgr = 1;
             if (samples == 3)
@@ -1009,8 +1010,79 @@ static HRESULT TiffFrameDecode_ReadTile(TiffFrameDecode *This, UINT tile_x, UINT
     if (ret == -1)
         return E_FAIL;
 
+    /* 3bpp RGB */
+    if (This->decode_info.source_bpp == 3 && This->decode_info.samples == 3 && This->decode_info.bpp == 24)
+    {
+        BYTE *srcdata, *src, *dst;
+        DWORD x, y, count, width_bytes = (This->decode_info.tile_width * 3 + 7) / 8;
+
+        count = width_bytes * This->decode_info.tile_height;
+
+        srcdata = HeapAlloc(GetProcessHeap(), 0, count);
+        if (!srcdata) return E_OUTOFMEMORY;
+        memcpy(srcdata, This->cached_tile, count);
+
+        for (y = 0; y < This->decode_info.tile_height; y++)
+        {
+            src = srcdata + y * width_bytes;
+            dst = This->cached_tile + y * This->decode_info.tile_width * 3;
+
+            for (x = 0; x < This->decode_info.tile_width; x += 8)
+            {
+                dst[2] = (src[0] & 0x80) ? 0xff : 0; /* R */
+                dst[1] = (src[0] & 0x40) ? 0xff : 0; /* G */
+                dst[0] = (src[0] & 0x20) ? 0xff : 0; /* B */
+                if (x + 1 < This->decode_info.tile_width)
+                {
+                    dst[5] = (src[0] & 0x10) ? 0xff : 0; /* R */
+                    dst[4] = (src[0] & 0x08) ? 0xff : 0; /* G */
+                    dst[3] = (src[0] & 0x04) ? 0xff : 0; /* B */
+                }
+                if (x + 2 < This->decode_info.tile_width)
+                {
+                    dst[8] = (src[0] & 0x02) ? 0xff : 0; /* R */
+                    dst[7] = (src[0] & 0x01) ? 0xff : 0; /* G */
+                    dst[6]  = (src[1] & 0x80) ? 0xff : 0; /* B */
+                }
+                if (x + 3 < This->decode_info.tile_width)
+                {
+                    dst[11] = (src[1] & 0x40) ? 0xff : 0; /* R */
+                    dst[10] = (src[1] & 0x20) ? 0xff : 0; /* G */
+                    dst[9]  = (src[1] & 0x10) ? 0xff : 0; /* B */
+                }
+                if (x + 4 < This->decode_info.tile_width)
+                {
+                    dst[14] = (src[1] & 0x08) ? 0xff : 0; /* R */
+                    dst[13] = (src[1] & 0x04) ? 0xff : 0; /* G */
+                    dst[12] = (src[1] & 0x02) ? 0xff : 0; /* B */
+                }
+                if (x + 5 < This->decode_info.tile_width)
+                {
+                    dst[17] = (src[1] & 0x01) ? 0xff : 0; /* R */
+                    dst[16] = (src[2] & 0x80) ? 0xff : 0; /* G */
+                    dst[15] = (src[2] & 0x40) ? 0xff : 0; /* B */
+                }
+                if (x + 6 < This->decode_info.tile_width)
+                {
+                    dst[20] = (src[2] & 0x20) ? 0xff : 0; /* R */
+                    dst[19] = (src[2] & 0x10) ? 0xff : 0; /* G */
+                    dst[18] = (src[2] & 0x08) ? 0xff : 0; /* B */
+                }
+                if (x + 7 < This->decode_info.tile_width)
+                {
+                    dst[23] = (src[2] & 0x04) ? 0xff : 0; /* R */
+                    dst[22] = (src[2] & 0x02) ? 0xff : 0; /* G */
+                    dst[21] = (src[2] & 0x01) ? 0xff : 0; /* B */
+                }
+                src += 3;
+                dst += 24;
+            }
+        }
+
+        HeapFree(GetProcessHeap(), 0, srcdata);
+    }
     /* 8bpp grayscale with extra alpha */
-    if (This->decode_info.source_bpp == 16 && This->decode_info.samples == 2 && This->decode_info.bpp == 32)
+    else if (This->decode_info.source_bpp == 16 && This->decode_info.samples == 2 && This->decode_info.bpp == 32)
     {
         BYTE *src;
         DWORD *dst, count = This->decode_info.tile_width * This->decode_info.tile_height;
-- 
2.9.0

