From 6b4f4bdf9beb0c73fa8b8bc218cd206f2cd347fa Mon Sep 17 00:00:00 2001
From: offtkp <parisoplop@gmail.com>
Date: Sun, 7 Mar 2021 13:48:39 +0900
Subject: vcl: add PNG writer based on libpng
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Add PngImageWriter, a new png writer that uses libpng to replace
our own at pngwrite.cxx

PS: most of the work on this commit is done by Tomaž

Change-Id: I52ffd1b286162ee0dd9f694c4f3210385f71daf8
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136008
Tested-by: Jenkins
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
---
 vcl/qa/cppunit/png/PngFilterTest.cxx | 173 +++++++++++++++++++++++++++++++++++
 1 file changed, 173 insertions(+)

(limited to 'vcl/qa')

diff --git a/vcl/qa/cppunit/png/PngFilterTest.cxx b/vcl/qa/cppunit/png/PngFilterTest.cxx
index c167c4c9c636..727f86c9476b 100644
--- a/vcl/qa/cppunit/png/PngFilterTest.cxx
+++ b/vcl/qa/cppunit/png/PngFilterTest.cxx
@@ -24,14 +24,20 @@
 #include <test/bootstrapfixture.hxx>
 #include <tools/stream.hxx>
 #include <vcl/filter/PngImageReader.hxx>
+#include <vcl/filter/PngImageWriter.hxx>
 #include <vcl/BitmapReadAccess.hxx>
+#include <bitmap/BitmapWriteAccess.hxx>
 #include <vcl/alpha.hxx>
 #include <vcl/graphicfilter.hxx>
+#include <unotools/tempfile.hxx>
 
 using namespace css;
 
 class PngFilterTest : public test::BootstrapFixture
 {
+    // Should keep the temp files (should be false)
+    static constexpr bool bKeepTemp = true;
+
     OUString maDataUrl;
 
     OUString getFullUrl(std::u16string_view sFileName)
@@ -48,10 +54,18 @@ public:
 
     void testPng();
     void testMsGifInPng();
+    void testPngRoundtrip8BitGrey();
+    void testPngRoundtrip24();
+    void testPngRoundtrip24_8();
+    void testPngRoundtrip32();
 
     CPPUNIT_TEST_SUITE(PngFilterTest);
     CPPUNIT_TEST(testPng);
     CPPUNIT_TEST(testMsGifInPng);
+    CPPUNIT_TEST(testPngRoundtrip8BitGrey);
+    CPPUNIT_TEST(testPngRoundtrip24);
+    CPPUNIT_TEST(testPngRoundtrip24_8);
+    CPPUNIT_TEST(testPngRoundtrip32);
     CPPUNIT_TEST_SUITE_END();
 };
 
@@ -245,6 +259,165 @@ void PngFilterTest::testMsGifInPng()
     CPPUNIT_ASSERT(aGraphic.IsAnimated());
 }
 
+void PngFilterTest::testPngRoundtrip8BitGrey()
+{
+    utl::TempFile aTempFile(u"testPngRoundtrip8BitGrey");
+    if (!bKeepTemp)
+        aTempFile.EnableKillingFile();
+    {
+        SvStream& rStream = *aTempFile.GetStream(StreamMode::WRITE);
+        Bitmap aBitmap(Size(16, 16), vcl::PixelFormat::N8_BPP, &Bitmap::GetGreyPalette(256));
+        {
+            BitmapScopedWriteAccess pWriteAccess(aBitmap);
+            pWriteAccess->Erase(COL_BLACK);
+            for (int i = 0; i < 8; ++i)
+            {
+                for (int j = 0; j < 8; ++j)
+                {
+                    pWriteAccess->SetPixel(i, j, COL_GRAY);
+                }
+            }
+            for (int i = 8; i < 16; ++i)
+            {
+                for (int j = 8; j < 16; ++j)
+                {
+                    pWriteAccess->SetPixel(i, j, COL_LIGHTGRAY);
+                }
+            }
+        }
+        BitmapEx aBitmapEx(aBitmap);
+
+        vcl::PngImageWriter aPngWriter(rStream);
+        CPPUNIT_ASSERT_EQUAL(true, aPngWriter.write(aBitmapEx));
+        aTempFile.CloseStream();
+    }
+    {
+        SvStream& rStream = *aTempFile.GetStream(StreamMode::READ);
+
+        vcl::PngImageReader aPngReader(rStream);
+        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_GRAY, aBitmapEx.GetPixelColor(0, 0));
+        CPPUNIT_ASSERT_EQUAL(COL_LIGHTGRAY, aBitmapEx.GetPixelColor(15, 15));
+        CPPUNIT_ASSERT_EQUAL(COL_BLACK, aBitmapEx.GetPixelColor(15, 0));
+        CPPUNIT_ASSERT_EQUAL(COL_BLACK, aBitmapEx.GetPixelColor(0, 15));
+    }
+}
+
+void PngFilterTest::testPngRoundtrip24()
+{
+    utl::TempFile aTempFile(u"testPngRoundtrip24");
+    if (!bKeepTemp)
+        aTempFile.EnableKillingFile();
+    {
+        SvStream& rStream = *aTempFile.GetStream(StreamMode::WRITE);
+        Bitmap aBitmap(Size(16, 16), vcl::PixelFormat::N24_BPP);
+        {
+            BitmapScopedWriteAccess pWriteAccess(aBitmap);
+            pWriteAccess->Erase(COL_BLACK);
+            for (int i = 0; i < 8; ++i)
+            {
+                for (int j = 0; j < 8; ++j)
+                {
+                    pWriteAccess->SetPixel(i, j, COL_LIGHTRED);
+                }
+            }
+            for (int i = 8; i < 16; ++i)
+            {
+                for (int j = 8; j < 16; ++j)
+                {
+                    pWriteAccess->SetPixel(i, j, COL_LIGHTBLUE);
+                }
+            }
+        }
+        BitmapEx aBitmapEx(aBitmap);
+
+        vcl::PngImageWriter aPngWriter(rStream);
+        CPPUNIT_ASSERT_EQUAL(true, aPngWriter.write(aBitmapEx));
+    }
+    {
+        SvStream& rStream = *aTempFile.GetStream(StreamMode::READ);
+        rStream.Seek(0);
+
+        vcl::PngImageReader aPngReader(rStream);
+        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_LIGHTRED, aBitmapEx.GetPixelColor(0, 0));
+        CPPUNIT_ASSERT_EQUAL(COL_LIGHTBLUE, aBitmapEx.GetPixelColor(15, 15));
+        CPPUNIT_ASSERT_EQUAL(COL_BLACK, aBitmapEx.GetPixelColor(15, 0));
+        CPPUNIT_ASSERT_EQUAL(COL_BLACK, aBitmapEx.GetPixelColor(0, 15));
+    }
+}
+
+void PngFilterTest::testPngRoundtrip24_8()
+{
+    utl::TempFile aTempFile(u"testPngRoundtrip24_8");
+    if (!bKeepTemp)
+        aTempFile.EnableKillingFile();
+    {
+        SvStream& rStream = *aTempFile.GetStream(StreamMode::WRITE);
+        Bitmap aBitmap(Size(16, 16), vcl::PixelFormat::N24_BPP);
+        AlphaMask aAlpha(Size(16, 16));
+        {
+            BitmapScopedWriteAccess pWriteAccessBitmap(aBitmap);
+            AlphaScopedWriteAccess pWriteAccessAlpha(aAlpha);
+            pWriteAccessAlpha->Erase(Color(ColorTransparency, 0x00, 0xAA, 0xAA, 0xAA));
+            pWriteAccessBitmap->Erase(COL_BLACK);
+            for (int i = 0; i < 8; ++i)
+            {
+                for (int j = 0; j < 8; ++j)
+                {
+                    pWriteAccessBitmap->SetPixel(i, j, COL_LIGHTRED);
+                    pWriteAccessAlpha->SetPixel(i, j,
+                                                Color(ColorTransparency, 0x00, 0xBB, 0xBB, 0xBB));
+                }
+            }
+            for (int i = 8; i < 16; ++i)
+            {
+                for (int j = 8; j < 16; ++j)
+                {
+                    pWriteAccessBitmap->SetPixel(i, j, COL_LIGHTBLUE);
+                    pWriteAccessAlpha->SetPixel(i, j,
+                                                Color(ColorTransparency, 0x00, 0xCC, 0xCC, 0xCC));
+                }
+            }
+        }
+        BitmapEx aBitmapEx(aBitmap, aAlpha);
+        vcl::PngImageWriter aPngWriter(rStream);
+        CPPUNIT_ASSERT_EQUAL(true, aPngWriter.write(aBitmapEx));
+    }
+    {
+        SvStream& rStream = *aTempFile.GetStream(StreamMode::READ);
+        rStream.Seek(0);
+
+        vcl::PngImageReader aPngReader(rStream);
+        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(Color(ColorTransparency, 0xBB, 0xFF, 0x00, 0x00),
+                             aBitmapEx.GetPixelColor(0, 0));
+        CPPUNIT_ASSERT_EQUAL(Color(ColorTransparency, 0xCC, 0x00, 0x00, 0xFF),
+                             aBitmapEx.GetPixelColor(15, 15));
+        CPPUNIT_ASSERT_EQUAL(Color(ColorTransparency, 0xAA, 0x00, 0x00, 0x00),
+                             aBitmapEx.GetPixelColor(15, 0));
+        CPPUNIT_ASSERT_EQUAL(Color(ColorTransparency, 0xAA, 0x00, 0x00, 0x00),
+                             aBitmapEx.GetPixelColor(0, 15));
+    }
+}
+
+void PngFilterTest::testPngRoundtrip32() {}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(PngFilterTest);
 
 CPPUNIT_PLUGIN_IMPLEMENT();
-- 
cgit