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);