vcl/qa/cppunit/png/PngFilterTest.cxx     |   66 +++++++++++++++++++++++++++++++
 vcl/source/filter/png/PngImageWriter.cxx |   24 +++++++++++
 2 files changed, 90 insertions(+)

New commits:
commit 80395bf5f2bc7d48c690893abf8604540c24806f
Author:     offtkp <parisop...@gmail.com>
AuthorDate: Mon Jul 4 22:07:28 2022 +0300
Commit:     Tomaž Vajngerl <qui...@gmail.com>
CommitDate: Tue Jul 19 09:59:03 2022 +0200

    Add PngImageWriter 1 bit palette export support
    
    Added support for exporting 1 bit palette png for non grayscale images
    and unit test
    
    Change-Id: I0b4c63c922fad4e42c7db61e81c553c69dd6bff6
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136813
    Tested-by: Jenkins
    Reviewed-by: Tomaž Vajngerl <qui...@gmail.com>

diff --git a/vcl/qa/cppunit/png/PngFilterTest.cxx 
b/vcl/qa/cppunit/png/PngFilterTest.cxx
index 81531f21b0e6..2eae9544ecbb 100644
--- a/vcl/qa/cppunit/png/PngFilterTest.cxx
+++ b/vcl/qa/cppunit/png/PngFilterTest.cxx
@@ -175,6 +175,7 @@ public:
     void testPngRoundtrip24();
     void testPngRoundtrip24_8();
     void testPngRoundtrip32();
+    void testPngWrite1BitRGBPalette();
 
     CPPUNIT_TEST_SUITE(PngFilterTest);
     CPPUNIT_TEST(testPng);
@@ -184,6 +185,7 @@ public:
     CPPUNIT_TEST(testPngRoundtrip24);
     CPPUNIT_TEST(testPngRoundtrip24_8);
     CPPUNIT_TEST(testPngRoundtrip32);
+    CPPUNIT_TEST(testPngWrite1BitRGBPalette);
     CPPUNIT_TEST_SUITE_END();
 };
 
@@ -1863,6 +1865,70 @@ void PngFilterTest::testPngRoundtrip24_8()
 
 void PngFilterTest::testPngRoundtrip32() {}
 
+void PngFilterTest::testPngWrite1BitRGBPalette()
+{
+    SvMemoryStream aExportStream;
+    {
+        BitmapPalette aPal;
+        aPal.SetEntryCount(2);
+        aPal[0] = COL_RED;
+        aPal[1] = COL_GREEN;
+        Bitmap aBitmap(Size(16, 16), vcl::PixelFormat::N1_BPP, &aPal);
+        {
+            BitmapScopedWriteAccess pWriteAccessBitmap(aBitmap);
+            // Top left
+            for (int i = 0; i < 8; i++)
+            {
+                for (int j = 0; j < 8; j++)
+                {
+                    pWriteAccessBitmap->SetPixelIndex(i, j, 0);
+                }
+            }
+            // Top right
+            for (int i = 0; i < 8; i++)
+            {
+                for (int j = 8; j < 16; j++)
+                {
+                    pWriteAccessBitmap->SetPixelIndex(i, j, 1);
+                }
+            }
+            // Bottom left
+            for (int i = 8; i < 16; i++)
+            {
+                for (int j = 0; j < 8; j++)
+                {
+                    pWriteAccessBitmap->SetPixelIndex(i, j, 1);
+                }
+            }
+            // Bottom right
+            for (int i = 8; i < 16; i++)
+            {
+                for (int j = 8; j < 16; j++)
+                {
+                    pWriteAccessBitmap->SetPixelIndex(i, j, 0);
+                }
+            }
+        }
+        BitmapEx aBitmapEx(aBitmap);
+        vcl::PngImageWriter aPngWriter(aExportStream);
+        CPPUNIT_ASSERT_EQUAL(true, aPngWriter.write(aBitmapEx));
+    }
+    aExportStream.Seek(0);
+    {
+        vcl::PngImageReader aPngReader(aExportStream);
+        BitmapEx aBitmapEx;
+        CPPUNIT_ASSERT_EQUAL(true, aPngReader.read(aBitmapEx));
+
+        CPPUNIT_ASSERT_EQUAL(16L, aBitmapEx.GetSizePixel().Width());
+        CPPUNIT_ASSERT_EQUAL(16L, aBitmapEx.GetSizePixel().Height());
+
+        CPPUNIT_ASSERT_EQUAL(COL_RED, aBitmapEx.GetPixelColor(0, 0));
+        CPPUNIT_ASSERT_EQUAL(COL_RED, aBitmapEx.GetPixelColor(15, 15));
+        CPPUNIT_ASSERT_EQUAL(COL_GREEN, aBitmapEx.GetPixelColor(15, 0));
+        CPPUNIT_ASSERT_EQUAL(COL_GREEN, aBitmapEx.GetPixelColor(0, 15));
+    }
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(PngFilterTest);
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/vcl/source/filter/png/PngImageWriter.cxx 
b/vcl/source/filter/png/PngImageWriter.cxx
index b83683b181da..48399ba05018 100644
--- a/vcl/source/filter/png/PngImageWriter.cxx
+++ b/vcl/source/filter/png/PngImageWriter.cxx
@@ -100,6 +100,13 @@ static bool pngWrite(SvStream& rStream, BitmapEx& 
rBitmapEx, int nCompressionLev
         auto eScanlineFormat = pAccess->GetScanlineFormat();
         switch (eScanlineFormat)
         {
+            case ScanlineFormat::N1BitMsbPal:
+            case ScanlineFormat::N1BitLsbPal:
+            {
+                colorType = PNG_COLOR_TYPE_PALETTE;
+                bitDepth = 1;
+                break;
+            }
             case ScanlineFormat::N8BitPal:
             {
                 if (!aBitmap.HasGreyPalette8Bit())
@@ -133,6 +140,23 @@ static bool pngWrite(SvStream& rStream, BitmapEx& 
rBitmapEx, int nCompressionLev
         int compressionType = PNG_COMPRESSION_TYPE_DEFAULT;
         int filterMethod = PNG_FILTER_TYPE_DEFAULT;
 
+        // Convert BitmapPalette to png_color*
+        if (colorType == PNG_COLOR_TYPE_PALETTE)
+        {
+            // Reserve enough space for 3 channels for each palette entry
+            auto aBitmapPalette = pAccess->GetPalette();
+            auto nEntryCount = aBitmapPalette.GetEntryCount();
+            std::unique_ptr<png_color[]> aPngPaletteArray(new 
png_color[nEntryCount * 3]);
+            for (sal_uInt16 i = 0; i < nEntryCount; i++)
+            {
+                aPngPaletteArray[i].red = aBitmapPalette[i].GetRed();
+                aPngPaletteArray[i].green = aBitmapPalette[i].GetGreen();
+                aPngPaletteArray[i].blue = aBitmapPalette[i].GetBlue();
+            }
+            // Palette is copied over so it can be safely discarded
+            png_set_PLTE(pPng, pInfo, aPngPaletteArray.get(), nEntryCount);
+        }
+
         png_set_IHDR(pPng, pInfo, aSize.Width(), aSize.Height(), bitDepth, 
colorType, interlaceType,
                      compressionType, filterMethod);
 

Reply via email to