vcl/qa/cppunit/graphicfilter/data/tiff/tdf74331.tif |binary
 vcl/qa/cppunit/graphicfilter/filters-tiff-test.cxx  |   51 ++++
 vcl/source/filter/itiff/itiff.cxx                   |  239 ++++++++++----------
 3 files changed, 177 insertions(+), 113 deletions(-)

New commits:
commit 520d8c9ec7718cf6678614ecf18656dafcad9445
Author:     Caolán McNamara <caol...@redhat.com>
AuthorDate: Fri Apr 29 13:18:47 2022 +0100
Commit:     Caolán McNamara <caol...@redhat.com>
CommitDate: Sun May 1 11:03:13 2022 +0200

    tdf#74331: 16bit "min-is-black" tiff not loaded correctly
    
    try an alternative fix
    
    git show -w is your friend here
    
    Change-Id: Ie9644f73431243ea0e9c6ef7f5c7ca4dadc7ed9e
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133638
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <caol...@redhat.com>

diff --git a/vcl/qa/cppunit/graphicfilter/data/tiff/tdf74331.tif 
b/vcl/qa/cppunit/graphicfilter/data/tiff/tdf74331.tif
new file mode 100644
index 000000000000..702b8218ca5f
Binary files /dev/null and 
b/vcl/qa/cppunit/graphicfilter/data/tiff/tdf74331.tif differ
diff --git a/vcl/qa/cppunit/graphicfilter/filters-tiff-test.cxx 
b/vcl/qa/cppunit/graphicfilter/filters-tiff-test.cxx
index 5842acf9ae8d..72f12ca565f5 100644
--- a/vcl/qa/cppunit/graphicfilter/filters-tiff-test.cxx
+++ b/vcl/qa/cppunit/graphicfilter/filters-tiff-test.cxx
@@ -45,6 +45,7 @@ public:
     void testTdf126460();
     void testTdf115863();
     void testTdf138818();
+    void testTdf74331();
     void testRoundtrip();
     void testRGB8bits();
     void testRGB16bits();
@@ -54,6 +55,7 @@ public:
     CPPUNIT_TEST(testTdf126460);
     CPPUNIT_TEST(testTdf115863);
     CPPUNIT_TEST(testTdf138818);
+    CPPUNIT_TEST(testTdf74331);
     CPPUNIT_TEST(testRoundtrip);
     CPPUNIT_TEST(testRGB8bits);
     CPPUNIT_TEST(testRGB16bits);
@@ -128,6 +130,55 @@ void TiffFilterTest::testTdf138818()
     CPPUNIT_ASSERT_EQUAL(sal_uInt32(46428), 
aGraphic.GetGfxLink().GetDataSize());
 }
 
+void TiffFilterTest::testTdf74331()
+{
+    OUString aURL = getUrl() + "tdf74331.tif";
+    SvFileStream aFileStream(aURL, StreamMode::READ);
+    Graphic aGraphic;
+    GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
+
+    ErrCode bResult = rFilter.ImportGraphic(aGraphic, aURL, aFileStream);
+
+    CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, bResult);
+
+    Bitmap aBitmap = aGraphic.GetBitmapEx().GetBitmap();
+    Size aSize = aBitmap.GetSizePixel();
+    CPPUNIT_ASSERT_EQUAL(tools::Long(200), aSize.Width());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(200), aSize.Height());
+
+    Bitmap::ScopedReadAccess pReadAccess(aBitmap);
+
+    // Check the image contains different kinds of grays
+    int nGrayCount = 0;
+    int nGray3Count = 0;
+    int nGray7Count = 0;
+    int nLightGrayCount = 0;
+
+    for (tools::Long nX = 1; nX < aSize.Width() - 1; ++nX)
+    {
+        for (tools::Long nY = 1; nY < aSize.Height() - 1; ++nY)
+        {
+            const Color aColor = pReadAccess->GetColor(nY, nX);
+            if (aColor == COL_GRAY)
+                ++nGrayCount;
+            else if (aColor == COL_GRAY3)
+                ++nGray3Count;
+            else if (aColor == COL_GRAY7)
+                ++nGray7Count;
+            else if (aColor == COL_LIGHTGRAY)
+                ++nLightGrayCount;
+        }
+    }
+
+    // Without the fix in place, this test would have failed with
+    // - Expected: 313
+    // - Actual  : 0
+    CPPUNIT_ASSERT_EQUAL(313, nGrayCount);
+    CPPUNIT_ASSERT_EQUAL(71, nGray3Count);
+    CPPUNIT_ASSERT_EQUAL(227, nGray7Count);
+    CPPUNIT_ASSERT_EQUAL(165, nLightGrayCount);
+}
+
 void TiffFilterTest::testRoundtrip()
 {
     Bitmap aBitmap(Size(2, 2), vcl::PixelFormat::N24_BPP);
diff --git a/vcl/source/filter/itiff/itiff.cxx 
b/vcl/source/filter/itiff/itiff.cxx
index 7fa66b746c5d..f94864f429e0 100644
--- a/vcl/source/filter/itiff/itiff.cxx
+++ b/vcl/source/filter/itiff/itiff.cxx
@@ -978,156 +978,169 @@ bool TIFFReader::ConvertScanline(sal_Int32 nY)
     {
         if ( nMaxSampleValue > nMinSampleValue )
         {
-            sal_uInt32 nMinMax = ( ( 1 << nDstBitsPerPixel ) - 1 ) / ( 
nMaxSampleValue - nMinSampleValue );
             sal_uInt8* pt = getMapData(0);
             sal_uInt8* ptend = pt + nBytesPerRow;
-            sal_uInt8 nShift;
 
-            switch ( nDstBitsPerPixel )
+            if (nBitsPerSample > 8)
             {
-                case 8 :
+                sal_uInt32 nMinMax = nMinSampleValue * 255 / ( nMaxSampleValue 
- nMinSampleValue );
+                for (sal_Int32 nx = 0; nx < nImageWidth; ++nx)
                 {
-                    if (pt + nImageWidth > ptend)
-                        return false;
+                    nVal = GetBits(pt, nx * nSamplesPerPixel * nBitsPerSample, 
nBitsPerSample);
+                    SetPixel(nY, nx, static_cast<sal_uInt8>(nVal - nMinMax));
+                }
+            }
+            else
+            {
+                sal_uInt32 nMinMax = ( ( 1 << nDstBitsPerPixel ) - 1 ) / ( 
nMaxSampleValue - nMinSampleValue );
+                sal_uInt8 nShift;
 
-                    if ( bByteSwap )
+                switch ( nDstBitsPerPixel )
+                {
+                    case 8 :
                     {
-                        if ( nPredictor == 2 )
+                        if (pt + nImageWidth > ptend)
+                            return false;
+
+                        if ( bByteSwap )
                         {
-                            sal_uInt8 nLast = 0;
-                            for (sal_Int32 nx = 0; nx < nImageWidth; ++nx)
+                            if ( nPredictor == 2 )
                             {
-                                nLast += nx == 0 ? BYTESWAP( *pt++ ) : *pt++;
-                                SetPixel(nY, nx, nLast);
+                                sal_uInt8 nLast = 0;
+                                for (sal_Int32 nx = 0; nx < nImageWidth; ++nx)
+                                {
+                                    nLast += nx == 0 ? BYTESWAP( *pt++ ) : 
*pt++;
+                                    SetPixel(nY, nx, nLast);
+                                }
                             }
-                        }
-                        else
-                        {
-                            for (sal_Int32 nx = 0; nx < nImageWidth; ++nx)
+                            else
                             {
-                                sal_uInt8 nLast = *pt++;
-                                SetPixel(nY, nx, static_cast<sal_uInt8>( 
(BYTESWAP(static_cast<sal_uInt32>(nLast)) - nMinSampleValue) * nMinMax ));
+                                for (sal_Int32 nx = 0; nx < nImageWidth; ++nx)
+                                {
+                                    sal_uInt8 nLast = *pt++;
+                                    SetPixel(nY, nx, static_cast<sal_uInt8>( 
(BYTESWAP(static_cast<sal_uInt32>(nLast)) - nMinSampleValue) * nMinMax ));
+                                }
                             }
                         }
-                    }
-                    else
-                    {
-                        if ( nPredictor == 2 )
+                        else
                         {
-                            sal_uInt8 nLast = 0;
-                            for (sal_Int32 nx = 0; nx < nImageWidth; ++nx)
+                            if ( nPredictor == 2 )
                             {
-                                nLast += *pt++;
-                                SetPixel(nY, nx, nLast);
+                                sal_uInt8 nLast = 0;
+                                for (sal_Int32 nx = 0; nx < nImageWidth; ++nx)
+                                {
+                                    nLast += *pt++;
+                                    SetPixel(nY, nx, nLast);
+                                }
                             }
-                        }
-                        else
-                        {
-                            for (sal_Int32 nx = 0; nx < nImageWidth; ++nx)
+                            else
                             {
-                                SetPixel(nY, nx, static_cast<sal_uInt8>( 
(static_cast<sal_uInt32>(*pt++) - nMinSampleValue) * nMinMax ));
+                                for (sal_Int32 nx = 0; nx < nImageWidth; ++nx)
+                                {
+                                    SetPixel(nY, nx, static_cast<sal_uInt8>( 
(static_cast<sal_uInt32>(*pt++) - nMinSampleValue) * nMinMax ));
+                                }
                             }
                         }
                     }
-                }
-                break;
-
-                case 7 :
-                case 6 :
-                case 5 :
-                case 4 :
-                case 3 :
-                case 2 :
-                {
-                    for (sal_Int32 nx = 0; nx < nImageWidth; ++nx)
+                    break;
+
+                    case 7 :
+                    case 6 :
+                    case 5 :
+                    case 4 :
+                    case 3 :
+                    case 2 :
                     {
-                        nVal = ( GetBits( pt, nx * nBitsPerSample, 
nBitsPerSample ) - nMinSampleValue ) * nMinMax;
-                        SetPixel(nY, nx, static_cast<sal_uInt8>(nVal));
+                        for (sal_Int32 nx = 0; nx < nImageWidth; ++nx)
+                        {
+                            nVal = ( GetBits( pt, nx * nBitsPerSample, 
nBitsPerSample ) - nMinSampleValue ) * nMinMax;
+                            SetPixel(nY, nx, static_cast<sal_uInt8>(nVal));
+                        }
                     }
-                }
-                break;
+                    break;
 
-                case 1 :
-                {
-                    sal_uInt32 nByteCount = nImageWidth >> 3;
+                    case 1 :
+                    {
+                        sal_uInt32 nByteCount = nImageWidth >> 3;
 
-                    sal_uInt32 nBytesNeeded = nByteCount;
-                    if (nImageWidth & 7)
-                        ++nBytesNeeded;
-                    if (pt + nBytesNeeded > ptend)
-                        return false;
+                        sal_uInt32 nBytesNeeded = nByteCount;
+                        if (nImageWidth & 7)
+                            ++nBytesNeeded;
+                        if (pt + nBytesNeeded > ptend)
+                            return false;
 
-                    if ( bByteSwap )
-                    {
-                        sal_Int32 nx = 0;
-                        while (nByteCount--)
+                        if ( bByteSwap )
                         {
-                            nByteVal = *pt++;
-                            SetPixel(nY, nx++, nByteVal & 1);
-                            nByteVal >>= 1;
-                            SetPixel(nY, nx++, nByteVal & 1);
-                            nByteVal >>= 1;
-                            SetPixel(nY, nx++, nByteVal & 1);
-                            nByteVal >>= 1;
-                            SetPixel(nY, nx++, nByteVal & 1);
-                            nByteVal >>= 1;
-                            SetPixel(nY, nx++, nByteVal & 1);
-                            nByteVal >>= 1;
-                            SetPixel(nY, nx++, nByteVal & 1);
-                            nByteVal >>= 1;
-                            SetPixel(nY, nx++, nByteVal & 1);
-                            nByteVal >>= 1;
-                            SetPixel(nY, nx++, nByteVal);
-                        }
-                        if ( nImageWidth & 7 )
-                        {
-                            nByteVal = *pt++;
-                            while ( nx < nImageWidth )
+                            sal_Int32 nx = 0;
+                            while (nByteCount--)
                             {
+                                nByteVal = *pt++;
+                                SetPixel(nY, nx++, nByteVal & 1);
+                                nByteVal >>= 1;
+                                SetPixel(nY, nx++, nByteVal & 1);
+                                nByteVal >>= 1;
+                                SetPixel(nY, nx++, nByteVal & 1);
+                                nByteVal >>= 1;
+                                SetPixel(nY, nx++, nByteVal & 1);
+                                nByteVal >>= 1;
                                 SetPixel(nY, nx++, nByteVal & 1);
                                 nByteVal >>= 1;
+                                SetPixel(nY, nx++, nByteVal & 1);
+                                nByteVal >>= 1;
+                                SetPixel(nY, nx++, nByteVal & 1);
+                                nByteVal >>= 1;
+                                SetPixel(nY, nx++, nByteVal);
+                            }
+                            if ( nImageWidth & 7 )
+                            {
+                                nByteVal = *pt++;
+                                while ( nx < nImageWidth )
+                                {
+                                    SetPixel(nY, nx++, nByteVal & 1);
+                                    nByteVal >>= 1;
+                                }
                             }
                         }
-                    }
-                    else
-                    {
-                        sal_Int32 nx = 7;
-                        while (nByteCount--)
-                        {
-                            nByteVal = *pt++;
-                            SetPixel(nY, nx, nByteVal & 1);
-                            nByteVal >>= 1;
-                            SetPixel(nY, --nx, nByteVal & 1);
-                            nByteVal >>= 1;
-                            SetPixel(nY, --nx, nByteVal & 1);
-                            nByteVal >>= 1;
-                            SetPixel(nY, --nx, nByteVal & 1);
-                            nByteVal >>= 1;
-                            SetPixel(nY, --nx, nByteVal & 1);
-                            nByteVal >>= 1;
-                            SetPixel(nY, --nx, nByteVal & 1);
-                            nByteVal >>= 1;
-                            SetPixel(nY, --nx, nByteVal & 1);
-                            nByteVal >>= 1;
-                            SetPixel(nY, --nx, nByteVal);
-                            nx += 15;
-                        }
-                        if ( nImageWidth & 7 )
+                        else
                         {
-                            nx -= 7;
-                            nByteVal = *pt++;
-                            nShift = 7;
-                            while ( nx < nImageWidth )
+                            sal_Int32 nx = 7;
+                            while (nByteCount--)
                             {
-                                SetPixel(nY, nx++, ( nByteVal >> nShift ) & 1);
+                                nByteVal = *pt++;
+                                SetPixel(nY, nx, nByteVal & 1);
+                                nByteVal >>= 1;
+                                SetPixel(nY, --nx, nByteVal & 1);
+                                nByteVal >>= 1;
+                                SetPixel(nY, --nx, nByteVal & 1);
+                                nByteVal >>= 1;
+                                SetPixel(nY, --nx, nByteVal & 1);
+                                nByteVal >>= 1;
+                                SetPixel(nY, --nx, nByteVal & 1);
+                                nByteVal >>= 1;
+                                SetPixel(nY, --nx, nByteVal & 1);
+                                nByteVal >>= 1;
+                                SetPixel(nY, --nx, nByteVal & 1);
+                                nByteVal >>= 1;
+                                SetPixel(nY, --nx, nByteVal);
+                                nx += 15;
+                            }
+                            if ( nImageWidth & 7 )
+                            {
+                                nx -= 7;
+                                nByteVal = *pt++;
+                                nShift = 7;
+                                while ( nx < nImageWidth )
+                                {
+                                    SetPixel(nY, nx++, ( nByteVal >> nShift ) 
& 1);
+                                }
                             }
                         }
                     }
-                }
-                break;
+                    break;
 
-                default :
-                    return false;
+                    default :
+                        return false;
+                }
             }
         }
     }

Reply via email to