summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuboš Luňák <l.lunak@collabora.com>2021-03-05 19:55:43 +0100
committerLuboš Luňák <l.lunak@collabora.com>2021-03-12 15:37:21 +0100
commite1d0846e060d2b3faedfe1a5877303037d8cf4d6 (patch)
treec232b6fcc14b77ff1022a3bc42277c9827324d17
parente286bd791bfaa00746ea143303761f76e0af1f0d (diff)
drop PNGReader and use only PngImageReader
PNGReader is a home-made PNG reader that does not use libpng, so it's more code, presumably less optimized and it apparently also doesn't always map colors properly. The only two features it has that PngImageReader doesn't are explicit chunk reading (used only for reading Microsoft's GIF in PNG, I implemented that for PngImageReader in a previous commit), and it loads paletted images as BitmapEx with a palette instead of converting to direct-color 24/32bpp or 8bpp-gray. The latter is even questional if nowadays that's feature or a misfeature, as it saves memory at the expense of speed. I can implement that if somebody misses it. I had to adjust some tests: - CVE-2016-0952-1.png - invalid CRC of the PNG header, neither Gimp nor Gwenview can display that, it should fail - afl-sample-Z_NEED_DICT.png - failure while decompressing data, but the loader considers that only a partially broken image since the header is correct, so it "passes" (like in Gimp or Gwenview) - SdImportTest::testTdf134210() and testPictureWithSchemeColor::Load_Verify_Reload_Verify() need the colors tested changed, because apparently gamma correction or something is now applied correctly, and it wasn't before (again checked the loaded images with Gimp) Change-Id: Id46f8d8a01256daf48ca64264b47c4e609183837 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/112042 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk> Reviewed-by: Luboš Luňák <l.lunak@collabora.com>
-rw-r--r--framework/source/uiconfiguration/imagemanagerimpl.cxx6
-rw-r--r--include/vcl/filter/PngImageReader.hxx4
-rw-r--r--include/vcl/pngread.hxx59
-rw-r--r--sd/qa/unit/export-tests-ooxml1.cxx6
-rw-r--r--sd/qa/unit/import-tests.cxx16
-rw-r--r--sd/source/ui/slidesorter/cache/SlsBitmapCompressor.cxx6
-rw-r--r--sfx2/source/control/recentdocsview.cxx6
-rw-r--r--sfx2/source/control/thumbnailview.cxx6
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport10.cxx6
-rw-r--r--vcl/Library_vcl.mk1
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2016-0952-1.png (renamed from vcl/qa/cppunit/graphicfilter/data/png/pass/CVE-2016-0952-1.png)0
-rw-r--r--vcl/qa/cppunit/graphicfilter/data/png/pass/afl-sample-Z_NEED_DICT.png (renamed from vcl/qa/cppunit/graphicfilter/data/png/fail/afl-sample-Z_NEED_DICT.png)bin260 -> 260 bytes
-rw-r--r--vcl/source/app/brand.cxx7
-rw-r--r--vcl/source/filter/graphicfilter.cxx70
-rw-r--r--vcl/source/filter/png/PngImageReader.cxx7
-rw-r--r--vcl/source/filter/png/pngread.cxx1708
-rw-r--r--vcl/source/treelist/transfer.cxx7
-rw-r--r--vcl/workben/fftester.cxx6
-rw-r--r--vcl/workben/pngfuzzer.cxx6
-rw-r--r--vcl/workben/vcldemo.cxx1
20 files changed, 63 insertions, 1865 deletions
diff --git a/framework/source/uiconfiguration/imagemanagerimpl.cxx b/framework/source/uiconfiguration/imagemanagerimpl.cxx
index 64cf3a53342c..8b7733aac91e 100644
--- a/framework/source/uiconfiguration/imagemanagerimpl.cxx
+++ b/framework/source/uiconfiguration/imagemanagerimpl.cxx
@@ -42,7 +42,7 @@
#include <osl/mutex.hxx>
#include <comphelper/sequence.hxx>
#include <unotools/ucbstreamhelper.hxx>
-#include <vcl/pngread.hxx>
+#include <vcl/filter/PngImageReader.hxx>
#include <vcl/pngwrite.hxx>
#include <rtl/instance.hxx>
#include <memory>
@@ -333,8 +333,8 @@ void ImageManagerImpl::implts_loadUserImages(
BitmapEx aUserBitmap;
{
std::unique_ptr<SvStream> pSvStream(utl::UcbStreamHelper::CreateStream( xBitmapStream ));
- vcl::PNGReader aPngReader( *pSvStream );
- aUserBitmap = aPngReader.Read();
+ vcl::PngImageReader aPngReader( *pSvStream );
+ aUserBitmap = aPngReader.read();
}
// Delete old image list and create a new one from the read bitmap
diff --git a/include/vcl/filter/PngImageReader.hxx b/include/vcl/filter/PngImageReader.hxx
index 2cd57549cf49..2615fd961bd4 100644
--- a/include/vcl/filter/PngImageReader.hxx
+++ b/include/vcl/filter/PngImageReader.hxx
@@ -33,7 +33,11 @@ class VCL_DLLPUBLIC PngImageReader
public:
PngImageReader(SvStream& rStream);
+ // Returns true if image was successfully read without errors.
+ // A usable bitmap may be returned even if there were errors (e.g. incomplete image).
bool read(BitmapEx& rBitmap);
+ // Returns a bitmap without indicating if there were errors.
+ BitmapEx read();
// Returns the contents of the msOG chunk (containing a Gif image), if it exists.
// Does not change position in the stream.
diff --git a/include/vcl/pngread.hxx b/include/vcl/pngread.hxx
deleted file mode 100644
index d3fa1942ee57..000000000000
--- a/include/vcl/pngread.hxx
+++ /dev/null
@@ -1,59 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/*
- * This file is part of the LibreOffice project.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- *
- * This file incorporates work covered by the following license notice:
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed
- * with this work for additional information regarding copyright
- * ownership. The ASF licenses this file to you under the Apache
- * License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.apache.org/licenses/LICENSE-2.0 .
- */
-
-#ifndef INCLUDED_VCL_PNGREAD_HXX
-#define INCLUDED_VCL_PNGREAD_HXX
-
-#include <vcl/dllapi.h>
-#include <vcl/bitmapex.hxx>
-#include <memory>
-#include <vector>
-
-namespace vcl
-{
-class PNGReaderImpl;
-
-class VCL_DLLPUBLIC PNGReader
-{
- std::unique_ptr<PNGReaderImpl> mpImpl;
-
-public:
- /* the PNG chunks are read within the c'tor, so the stream will
- be positioned at the end of the PNG */
- explicit PNGReader(SvStream& rStream);
- ~PNGReader();
-
- /* an empty preview size hint (=default) will read the whole image
- */
- BitmapEx Read();
-
- // retrieve every chunk that resides inside the PNG
- struct ChunkData
- {
- sal_uInt32 nType = 0;
- std::vector<sal_uInt8> aData;
- };
- const std::vector<ChunkData>& GetChunks() const;
-};
-
-} // end namespace vcl
-
-#endif // INCLUDED_VCL_PNGREAD_HXX
-
-/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/qa/unit/export-tests-ooxml1.cxx b/sd/qa/unit/export-tests-ooxml1.cxx
index 1e5f673428c2..4972669e4b82 100644
--- a/sd/qa/unit/export-tests-ooxml1.cxx
+++ b/sd/qa/unit/export-tests-ooxml1.cxx
@@ -54,7 +54,7 @@
#include <svx/svdotable.hxx>
#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
#include <rtl/uri.hxx>
-#include <vcl/pngread.hxx>
+#include <vcl/filter/PngImageReader.hxx>
using namespace css;
@@ -1344,8 +1344,8 @@ void SdOOXMLExportTest1::testNarrationMimeType()
OUString aImageRelName;
CPPUNIT_ASSERT(aImageAbsName.startsWith("file:///", &aImageRelName));
std::unique_ptr<SvStream> pImageStream = parseExportStream(aTempFile, aImageRelName);
- vcl::PNGReader aReader(*pImageStream);
- BitmapEx aBitmapEx = aReader.Read();
+ vcl::PngImageReader aReader(*pImageStream);
+ BitmapEx aBitmapEx = aReader.read();
// Without the accompanying fix in place, this test would have failed with:
// - Expected: 256
// - Actual : 120
diff --git a/sd/qa/unit/import-tests.cxx b/sd/qa/unit/import-tests.cxx
index 12560e90d586..cce54cb16e4f 100644
--- a/sd/qa/unit/import-tests.cxx
+++ b/sd/qa/unit/import-tests.cxx
@@ -92,7 +92,7 @@
#include <comphelper/sequenceashashmap.hxx>
#include <comphelper/graphicmimetype.hxx>
#include <comphelper/lok.hxx>
-#include <vcl/pngread.hxx>
+#include <vcl/filter/PngImageReader.hxx>
#include <vcl/BitmapReadAccess.hxx>
#include <vcl/dibtools.hxx>
#include <svx/svdograf.hxx>
@@ -1614,8 +1614,8 @@ void SdImportTest::testTdf113163()
xGraphicExporter->filter(aDescriptor);
SvFileStream aFileStream(aTempFile.GetURL(), StreamMode::READ);
- vcl::PNGReader aPNGReader(aFileStream);
- BitmapEx aBMPEx = aPNGReader.Read();
+ vcl::PngImageReader aPNGReader(aFileStream);
+ BitmapEx aBMPEx = aPNGReader.read();
// make sure the bitmap is not empty and correct size (PNG export->import was successful)
CPPUNIT_ASSERT_EQUAL(Size(100, 100), aBMPEx.GetSizePixel());
@@ -1665,8 +1665,8 @@ void SdImportTest::testTdf93124()
xGraphicExporter->filter(aDescriptor);
SvFileStream aFileStream(aTempFile.GetURL(), StreamMode::READ);
- vcl::PNGReader aPNGReader(aFileStream);
- BitmapEx aBMPEx = aPNGReader.Read();
+ vcl::PngImageReader aPNGReader(aFileStream);
+ BitmapEx aBMPEx = aPNGReader.read();
// make sure the bitmap is not empty and correct size (PNG export->import was successful)
CPPUNIT_ASSERT_EQUAL(Size(320, 180), aBMPEx.GetSizePixel());
@@ -1730,8 +1730,8 @@ void SdImportTest::testTdf99729()
xGraphicExporter->filter(aDescriptor);
SvFileStream aFileStream(aTempFile.GetURL(), StreamMode::READ);
- vcl::PNGReader aPNGReader(aFileStream);
- BitmapEx aBMPEx = aPNGReader.Read();
+ vcl::PngImageReader aPNGReader(aFileStream);
+ BitmapEx aBMPEx = aPNGReader.read();
Bitmap aBMP = aBMPEx.GetBitmap();
Bitmap::ScopedReadAccess pRead(aBMP);
for (tools::Long nX = 154; nX < (154 + 12); ++nX)
@@ -2768,7 +2768,7 @@ void SdImportTest::testTdf134210()
Graphic aGraphic(xGraphic);
BitmapEx aBitmap(aGraphic.GetBitmapEx());
- CPPUNIT_ASSERT_EQUAL( Color(6708292), aBitmap.GetPixelColor( 0, 0 ));
+ CPPUNIT_ASSERT_EQUAL( Color(6313534), aBitmap.GetPixelColor( 0, 0 ));
xDocShRef->DoClose();
}
diff --git a/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.cxx b/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.cxx
index 04b99dbf6c15..d4da935ddd0c 100644
--- a/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.cxx
+++ b/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.cxx
@@ -21,7 +21,7 @@
#include <tools/stream.hxx>
#include <vcl/bitmapex.hxx>
-#include <vcl/pngread.hxx>
+#include <vcl/filter/PngImageReader.hxx>
#include <vcl/pngwrite.hxx>
namespace sd::slidesorter::cache {
@@ -180,8 +180,8 @@ BitmapEx PngCompression::Decompress (
if (pData != nullptr)
{
SvMemoryStream aStream (pData->mpData, pData->mnDataSize, StreamMode::READ);
- vcl::PNGReader aReader (aStream);
- aResult = aReader.Read().GetBitmap();
+ vcl::PngImageReader aReader (aStream);
+ aResult = aReader.read().GetBitmap();
}
return aResult;
diff --git a/sfx2/source/control/recentdocsview.cxx b/sfx2/source/control/recentdocsview.cxx
index d137d366837c..ca822d0c3487 100644
--- a/sfx2/source/control/recentdocsview.cxx
+++ b/sfx2/source/control/recentdocsview.cxx
@@ -24,7 +24,7 @@
#include <tools/diagnose_ex.h>
#include <unotools/historyoptions.hxx>
#include <vcl/event.hxx>
-#include <vcl/pngread.hxx>
+#include <vcl/filter/PngImageReader.hxx>
#include <vcl/ptrstyle.hxx>
#include <vcl/svapp.hxx>
#include <tools/stream.hxx>
@@ -264,8 +264,8 @@ void RecentDocsView::Reload()
comphelper::Base64::decode(aDecoded, aBase64);
SvMemoryStream aStream(aDecoded.getArray(), aDecoded.getLength(), StreamMode::READ);
- vcl::PNGReader aReader(aStream);
- aThumbnail = aReader.Read();
+ vcl::PngImageReader aReader(aStream);
+ aThumbnail = aReader.read();
} else
{
INetURLObject aUrl(aURL);
diff --git a/sfx2/source/control/thumbnailview.cxx b/sfx2/source/control/thumbnailview.cxx
index 071e73f54c9c..f9624027755e 100644
--- a/sfx2/source/control/thumbnailview.cxx
+++ b/sfx2/source/control/thumbnailview.cxx
@@ -30,7 +30,7 @@
#include <vcl/svapp.hxx>
#include <vcl/settings.hxx>
#include <vcl/event.hxx>
-#include <vcl/pngread.hxx>
+#include <vcl/filter/PngImageReader.hxx>
#include <com/sun/star/accessibility/AccessibleEventId.hpp>
#include <com/sun/star/embed/ElementModes.hpp>
@@ -138,8 +138,8 @@ BitmapEx ThumbnailView::readThumbnail(const OUString &msURL)
{
std::unique_ptr<SvStream> pStream (
::utl::UcbStreamHelper::CreateStream (xIStream));
- vcl::PNGReader aReader (*pStream);
- aThumbnail = aReader.Read ();
+ vcl::PngImageReader aReader (*pStream);
+ aThumbnail = aReader.read ();
}
// Note that the preview is returned without scaling it to the desired
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx
index 45f9a46000e1..c33f99cb4322 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx
@@ -453,10 +453,8 @@ DECLARE_OOXMLEXPORT_TEST(testPictureWithSchemeColor, "picture-with-schemecolor.d
BitmapEx aBitmap(aVclGraphic.GetBitmapEx());
CPPUNIT_ASSERT_EQUAL(tools::Long(341), aBitmap.GetSizePixel().Width());
CPPUNIT_ASSERT_EQUAL(tools::Long(181), aBitmap.GetSizePixel().Height());
- Color aColor(aBitmap.GetPixelColor(120, 30));
- CPPUNIT_ASSERT_EQUAL(aColor, Color( 0xb1, 0xc8, 0xdd ));
- aColor = aBitmap.GetPixelColor(260, 130);
- CPPUNIT_ASSERT_EQUAL(aColor, Color( 0xb1, 0xc8, 0xdd ));
+ CPPUNIT_ASSERT_EQUAL(Color( 0xad, 0xc5, 0xdb ), aBitmap.GetPixelColor(120, 30));
+ CPPUNIT_ASSERT_EQUAL(Color( 0xad, 0xc5, 0xdb ), aBitmap.GetPixelColor(260, 130));
}
DECLARE_OOXMLEXPORT_TEST(testFdo69656, "Table_cell_auto_width_fdo69656.docx")
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index 00c2971df58a..17ddf83fe961 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -476,7 +476,6 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
vcl/source/filter/wmf/wmfexternal \
vcl/source/filter/wmf/wmfwr \
vcl/source/filter/png/PngImageReader \
- vcl/source/filter/png/pngread \
vcl/source/filter/png/pngwrite \
vcl/source/font/Feature \
vcl/source/font/FeatureCollector \
diff --git a/vcl/qa/cppunit/graphicfilter/data/png/pass/CVE-2016-0952-1.png b/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2016-0952-1.png
index 7848d5ad565c..7848d5ad565c 100644
--- a/vcl/qa/cppunit/graphicfilter/data/png/pass/CVE-2016-0952-1.png
+++ b/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2016-0952-1.png
diff --git a/vcl/qa/cppunit/graphicfilter/data/png/fail/afl-sample-Z_NEED_DICT.png b/vcl/qa/cppunit/graphicfilter/data/png/pass/afl-sample-Z_NEED_DICT.png
index db8e7a834af8..db8e7a834af8 100644
--- a/vcl/qa/cppunit/graphicfilter/data/png/fail/afl-sample-Z_NEED_DICT.png
+++ b/vcl/qa/cppunit/graphicfilter/data/png/pass/afl-sample-Z_NEED_DICT.png
Binary files differ
diff --git a/vcl/source/app/brand.cxx b/vcl/source/app/brand.cxx
index 269d141de3fe..ed4cccff4031 100644
--- a/vcl/source/app/brand.cxx
+++ b/vcl/source/app/brand.cxx
@@ -29,7 +29,8 @@
#include <tools/urlobj.hxx>
#include <tools/stream.hxx>
#include <i18nlangtag/languagetag.hxx>
-#include <vcl/pngread.hxx>
+#include <vcl/filter/PngImageReader.hxx>
+#include <vcl/bitmapex.hxx>
#include <vcl/svapp.hxx>
namespace {
@@ -38,8 +39,8 @@ namespace {
INetURLObject aObj( rPath );
SvFileStream aStrm( aObj.PathToFileName(), StreamMode::STD_READ );
if ( !aStrm.GetError() ) {
- vcl::PNGReader aReader( aStrm );
- rBitmap = aReader.Read();
+ vcl::PngImageReader aReader( aStrm );
+ rBitmap = aReader.read();
return !rBitmap.IsEmpty();
}
else
diff --git a/vcl/source/filter/graphicfilter.cxx b/vcl/source/filter/graphicfilter.cxx
index f6349d9923a9..e482f0f5d213 100644
--- a/vcl/source/filter/graphicfilter.cxx
+++ b/vcl/source/filter/graphicfilter.cxx
@@ -32,7 +32,7 @@
#include <vcl/dibtools.hxx>
#include <fltcall.hxx>
#include <vcl/salctype.hxx>
-#include <vcl/pngread.hxx>
+#include <vcl/filter/PngImageReader.hxx>
#include <vcl/pngwrite.hxx>
#include <vcl/vectorgraphicdata.hxx>
#include <vcl/virdev.hxx>
@@ -87,8 +87,6 @@
#include <graphic/GraphicFormatDetector.hxx>
#include <graphic/GraphicReader.hxx>
-#define PMGCHUNG_msOG 0x6d734f47 // Microsoft Office Animated GIF
-
typedef ::std::vector< GraphicFilter* > FilterList_impl;
static FilterList_impl* pFilterHdlList = nullptr;
@@ -755,35 +753,12 @@ Graphic GraphicFilter::ImportUnloadedGraphic(SvStream& rIStream, sal_uInt64 size
}
else if (aFilterName.equalsIgnoreAsciiCase(IMP_PNG))
{
- vcl::PNGReader aPNGReader(rIStream);
-
// check if this PNG contains a GIF chunk!
- const std::vector<vcl::PNGReader::ChunkData>& rChunkData = aPNGReader.GetChunks();
- for (auto const& chunk : rChunkData)
- {
- // Microsoft Office is storing Animated GIFs in following chunk
- if (chunk.nType == PMGCHUNG_msOG)
- {
- sal_uInt32 nChunkSize = chunk.aData.size();
-
- if (nChunkSize > 11)
- {
- const std::vector<sal_uInt8>& rData = chunk.aData;
- nGraphicContentSize = nChunkSize - 11;
- SvMemoryStream aIStrm(const_cast<sal_uInt8*>(&rData[11]), nGraphicContentSize, StreamMode::READ);
- pGraphicContent.reset(new sal_uInt8[nGraphicContentSize]);
- sal_uInt64 aCurrentPosition = aIStrm.Tell();
- aIStrm.ReadBytes(pGraphicContent.get(), nGraphicContentSize);
- aIStrm.Seek(aCurrentPosition);
- eLinkType = GfxLinkType::NativeGif;
- break;
- }
- }
- }
- if (eLinkType == GfxLinkType::NONE)
- {
+ pGraphicContent = vcl::PngImageReader::getMicrosoftGifChunk(rIStream, &nGraphicContentSize);
+ if( pGraphicContent )
+ eLinkType = GfxLinkType::NativeGif;
+ else
eLinkType = GfxLinkType::NativePng;
- }
}
else if (aFilterName.equalsIgnoreAsciiCase(IMP_JPEG))
{
@@ -955,36 +930,19 @@ ErrCode GraphicFilter::readPNG(SvStream & rStream, Graphic & rGraphic, GfxLinkTy
{
ErrCode aReturnCode = ERRCODE_NONE;
- vcl::PNGReader aPNGReader(rStream);
+ // check if this PNG contains a GIF chunk!
+ rpGraphicContent = vcl::PngImageReader::getMicrosoftGifChunk(rStream, &rGraphicContentSize);
+ if( rpGraphicContent )
{
- // check if this PNG contains a GIF chunk!
- const std::vector<vcl::PNGReader::ChunkData>& rChunkData = aPNGReader.GetChunks();
- for (auto const& chunk : rChunkData)
- {
- // Microsoft Office is storing Animated GIFs in following chunk
- if (chunk.nType == PMGCHUNG_msOG)
- {
- sal_uInt32 nChunkSize = chunk.aData.size();
-
- if (nChunkSize > 11)
- {
- const std::vector<sal_uInt8>& rData = chunk.aData;
- rGraphicContentSize = nChunkSize - 11;
- SvMemoryStream aIStrm(const_cast<sal_uInt8*>(&rData[11]), rGraphicContentSize, StreamMode::READ);
- rpGraphicContent.reset(new sal_uInt8[rGraphicContentSize]);
- sal_uInt64 aCurrentPosition = aIStrm.Tell();
- aIStrm.ReadBytes(rpGraphicContent.get(), rGraphicContentSize);
- aIStrm.Seek(aCurrentPosition);
- ImportGIF(aIStrm, rGraphic);
- rLinkType = GfxLinkType::NativeGif;
- return aReturnCode;
- }
- }
- }
+ SvMemoryStream aIStrm(rpGraphicContent.get(), rGraphicContentSize, StreamMode::READ);
+ ImportGIF(aIStrm, rGraphic);
+ rLinkType = GfxLinkType::NativeGif;
+ return aReturnCode;
}
// PNG has no GIF chunk
- BitmapEx aBitmapEx(aPNGReader.Read());
+ vcl::PngImageReader aPNGReader(rStream);
+ BitmapEx aBitmapEx(aPNGReader.read());
if (!aBitmapEx.IsEmpty())
{
rGraphic = aBitmapEx;
diff --git a/vcl/source/filter/png/PngImageReader.cxx b/vcl/source/filter/png/PngImageReader.cxx
index 829f3dd45bca..1f1b632bbd0d 100644
--- a/vcl/source/filter/png/PngImageReader.cxx
+++ b/vcl/source/filter/png/PngImageReader.cxx
@@ -425,6 +425,13 @@ bool PngImageReader::read(BitmapEx& rBitmapEx)
return reader(mrStream, rBitmapEx, bSupportsBitmap32);
}
+BitmapEx PngImageReader::read()
+{
+ BitmapEx bitmap;
+ read(bitmap);
+ return bitmap;
+}
+
std::unique_ptr<sal_uInt8[]> PngImageReader::getMicrosoftGifChunk(SvStream& rStream,
sal_Int32* chunkSize)
{
diff --git a/vcl/source/filter/png/pngread.cxx b/vcl/source/filter/png/pngread.cxx
deleted file mode 100644
index 8b3f777c6ac5..000000000000
--- a/vcl/source/filter/png/pngread.cxx
+++ /dev/null
@@ -1,1708 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/*
- * This file is part of the LibreOffice project.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- *
- * This file incorporates work covered by the following license notice:
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed
- * with this work for additional information regarding copyright
- * ownership. The ASF licenses this file to you under the Apache
- * License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.apache.org/licenses/LICENSE-2.0 .
- */
-
-#include <sal/config.h>
-#include <sal/log.hxx>
-#include <o3tl/safeint.hxx>
-#include <osl/diagnose.h>
-
-#include <cassert>
-#include <memory>
-#include <unotools/configmgr.hxx>
-#include <vcl/pngread.hxx>
-
-#include <cmath>
-#include <rtl/crc.h>
-#include <tools/zcodec.hxx>
-#include <tools/stream.hxx>
-#include <vcl/alpha.hxx>
-#include <osl/endian.h>
-
-#include <bitmap/BitmapWriteAccess.hxx>
-
-namespace vcl
-{
-
-#define PNGCHUNK_IHDR 0x49484452
-#define PNGCHUNK_PLTE 0x504c5445
-#define PNGCHUNK_IDAT 0x49444154
-#define PNGCHUNK_IEND 0x49454e44
-#define PNGCHUNK_bKGD 0x624b4744
-#define PNGCHUNK_gAMA 0x67414d41
-#define PNGCHUNK_pHYs 0x70485973
-#define PNGCHUNK_tRNS 0x74524e53
-
-#define VIEWING_GAMMA 2.35
-#define DISPLAY_GAMMA 1.0
-
-
-const sal_uInt8 mpDefaultColorTable[ 256 ] =
-{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
- 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
- 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
- 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
- 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
- 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
- 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
- 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
- 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
- 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
- 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
- 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
- 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
- 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
-};
-
-class PNGReaderImpl
-{
-private:
- SvStream& mrPNGStream;
- SvStreamEndian mnOrigStreamMode;
-
- std::vector<vcl::PNGReader::ChunkData> maChunkSeq;
- std::vector<vcl::PNGReader::ChunkData>::iterator maChunkIter;
- std::vector<sal_uInt8>::iterator maDataIter;
-
- std::unique_ptr<Bitmap> mpBmp;
- BitmapScopedWriteAccess mxAcc;
- std::unique_ptr<Bitmap> mpMaskBmp;
- BitmapScopedWriteAccess mxMaskAcc;
- std::unique_ptr<AlphaMask> mpAlphaMask;
- AlphaScopedWriteAccess mxAlphaAcc;
- BitmapWriteAccess* mpMaskAcc;
-
- ZCodec mpZCodec;
- std::unique_ptr<sal_uInt8[]>
- mpInflateInBuf; // as big as the size of a scanline + alphachannel + 1
- std::unique_ptr<sal_uInt8[]>
- mpScanPrior; // pointer to the latest scanline
- std::unique_ptr<sal_uInt8[]>
- mpTransTab; // for transparency in images with palette colortype
- sal_uInt8* mpScanCurrent; // pointer into the current scanline
- sal_uInt8* mpColorTable;
- std::size_t mnStreamSize; // estimate of PNG file size
- sal_uInt32 mnChunkType; // Type of current PNG chunk
- sal_Int32 mnChunkLen; // Length of current PNG chunk
- Size maOrigSize; // pixel size of the full image
- Size maTargetSize; // pixel size of the result image
- Size maPhysSize; // preferred size in MapUnit::Map100thMM units
- sal_uInt32 mnBPP; // number of bytes per pixel
- sal_uInt32 mnScansize; // max size of scanline
- sal_uInt32 mnYpos; // latest y position in full image
- int mnPass; // if interlaced the latest pass ( 1..7 ) else 7
- sal_uInt32 mnXStart; // the starting X for the current pass
- sal_uInt32 mnXAdd; // the increment for input images X coords for the current pass
- sal_uInt32 mnYAdd; // the increment for input images Y coords for the current pass
- int mnPreviewShift; // shift to convert orig image coords into preview image coords
- int mnPreviewMask; // == ((1 << mnPreviewShift) - 1)
- sal_uInt16 mnTargetDepth; // pixel depth of target bitmap
- sal_uInt8 mnTransRed;
- sal_uInt8 mnTransGreen;
- sal_uInt8 mnTransBlue;
- sal_uInt8 mnPngDepth; // pixel depth of PNG data
- sal_uInt8 mnColorType;
- sal_uInt8 mnCompressionType;
- sal_uInt8 mnFilterType;
- sal_uInt8 mnInterlaceType;
- const BitmapColor mcTranspColor; // transparency mask's transparency "color"
- const BitmapColor mcOpaqueColor; // transparency mask's opaque "color"
- bool mbTransparent : 1; // graphic includes a tRNS Chunk or an alpha Channel
- bool mbAlphaChannel : 1; // is true for ColorType 4 and 6
- bool mbRGBTriple : 1;
- bool mbPalette : 1; // false if we need a Palette
- bool mbGrayScale : 1;
- bool mbzCodecInUse : 1;
- bool mbStatus : 1;
- bool mbIDATStarted : 1; // true if IDAT seen
- bool mbIDATComplete : 1; // true if finished with enough IDAT chunks
- bool mbpHYs : 1; // true if physical size of pixel available
- bool mbIgnoreCRC : 1; // skip checking CRCs while fuzzing
-
-#if OSL_DEBUG_LEVEL > 0
- // do some checks in debug mode
- sal_Int32 mnAllocSizeScanline;
- sal_Int32 mnAllocSizeScanlineAlpha;
-#endif
- // the temporary Scanline (and alpha) for direct scanline copy to Bitmap
- std::unique_ptr<sal_uInt8[]>
- mpScanline;
- std::unique_ptr<sal_uInt8[]>
- mpScanlineAlpha;
-
- bool ReadNextChunk();
-
- void ImplSetPixel( sal_uInt32 y, sal_uInt32 x, const BitmapColor & );
- void ImplSetPixel( sal_uInt32 y, sal_uInt32 x, sal_uInt8 nPalIndex );
- void ImplSetTranspPixel( sal_uInt32 y, sal_uInt32 x, const BitmapColor &, bool bTrans );
- void ImplSetAlphaPixel( sal_uInt32 y, sal_uInt32 x, sal_uInt8 nPalIndex, sal_uInt8 nAlpha );
- void ImplSetAlphaPixel( sal_uInt32 y, sal_uInt32 x, const BitmapColor&, sal_uInt8 nAlpha );
- void ImplReadIDAT();
- bool ImplPreparePass();
- void ImplApplyFilter();
- void ImplDrawScanline( sal_uInt32 nXStart, sal_uInt32 nXAdd );
- bool ImplReadTransparent();
- void ImplGetGamma();
- void ImplGetBackground();
- sal_uInt8 ImplScaleColor();
- bool ImplReadHeader();
- bool ImplReadPalette();
- void ImplGetGrayPalette( sal_uInt16 );
- sal_uInt32 ImplReadsal_uInt32();
-
-public:
-
- explicit PNGReaderImpl( SvStream& );
- ~PNGReaderImpl();
-
- BitmapEx GetBitmapEx();
- const std::vector<vcl::PNGReader::ChunkData>& GetAllChunks();
-};
-
-PNGReaderImpl::PNGReaderImpl( SvStream& rPNGStream )
-: mrPNGStream( rPNGStream ),
- mpMaskAcc ( nullptr ),
- mpScanCurrent ( nullptr ),
- mpColorTable ( const_cast<sal_uInt8*>(mpDefaultColorTable) ),
- mnChunkType ( 0 ),
- mnChunkLen ( 0 ),
- mnBPP ( 0 ),
- mnScansize ( 0 ),
- mnYpos ( 0 ),
- mnPass ( 0 ),
- mnXStart ( 0 ),
- mnXAdd ( 0 ),
- mnYAdd ( 0 ),
- mnTargetDepth ( 0 ),
- mnTransRed ( 0 ),
- mnTransGreen ( 0 ),
- mnTransBlue ( 0 ),
- mnPngDepth ( 0 ),
- mnColorType ( 0 ),
- mnCompressionType( 0 ),
- mnFilterType ( 0 ),
- mnInterlaceType ( 0 ),
- mcTranspColor ( BitmapColor( 0xFF )),
- mcOpaqueColor ( BitmapColor( 0x00 )),
- mbTransparent( false ),
- mbAlphaChannel( false ),
- mbRGBTriple( false ),
- mbPalette( false ),
- mbGrayScale( false ),
- mbzCodecInUse ( false ),
- mbStatus( true ),
- mbIDATStarted( false ),
- mbIDATComplete( false ),
- mbpHYs ( false ),
- mbIgnoreCRC( utl::ConfigManager::IsFuzzing() )
-#if OSL_DEBUG_LEVEL > 0
- ,mnAllocSizeScanline(0),
- mnAllocSizeScanlineAlpha(0)
-#endif
-{
- // prepare the PNG data stream
- mnOrigStreamMode = mrPNGStream.GetEndian();
- mrPNGStream.SetEndian( SvStreamEndian::BIG );
-
- // prepare the chunk reader
- maChunkSeq.reserve( 16 );
- maChunkIter = maChunkSeq.begin();
-
- // estimate PNG file size (to allow sanity checks)
- mnStreamSize = mrPNGStream.TellEnd();
-
- // check the PNG header magic
- sal_uInt32 nDummy = 0;
- mrPNGStream.ReadUInt32( nDummy );
- mbStatus = (nDummy == 0x89504e47);
- mrPNGStream.ReadUInt32( nDummy );
- mbStatus = (nDummy == 0x0d0a1a0a) && mbStatus;
-
- mnPreviewShift = 0;
- mnPreviewMask = (1 << mnPreviewShift) - 1;
-}
-
-PNGReaderImpl::~PNGReaderImpl()
-{
- mrPNGStream.SetEndian( mnOrigStreamMode );
-
- if ( mbzCodecInUse )
- mpZCodec.EndCompression();
-
- if( mpColorTable != mpDefaultColorTable )
- delete[] mpColorTable;
-}
-
-bool PNGReaderImpl::ReadNextChunk()
-{
- if( maChunkIter == maChunkSeq.end() )
- {
- // get the next chunk from the stream
-
- // unless we are at the end of the PNG stream
- if (!mrPNGStream.good() || mrPNGStream.remainingSize() < 8)
- return false;
- if( !maChunkSeq.empty() && (maChunkSeq.back().nType == PNGCHUNK_IEND) )
- return false;
-
- PNGReader::ChunkData aDummyChunk;
- maChunkIter = maChunkSeq.insert( maChunkSeq.end(), aDummyChunk );
- PNGReader::ChunkData& rChunkData = *maChunkIter;
-
- // read the chunk header
- mnChunkLen = 0;
- mnChunkType = 0;
- mrPNGStream.ReadInt32( mnChunkLen ).ReadUInt32( mnChunkType );
- rChunkData.nType = mnChunkType;
-
- // fdo#61847 truncate over-long, trailing chunks
- const std::size_t nStreamPos = mrPNGStream.Tell();
- if( mnChunkLen < 0 || nStreamPos + mnChunkLen >= mnStreamSize )
- mnChunkLen = mnStreamSize - nStreamPos;
-
- // calculate chunktype CRC (swap it back to original byte order)
- sal_uInt32 nChunkType = mnChunkType;
- #if defined(__LITTLEENDIAN) || defined(OSL_LITENDIAN)
- nChunkType = OSL_SWAPDWORD( nChunkType );
- #endif
- sal_uInt32 nCRC32 = rtl_crc32( 0, &nChunkType, 4 );
-
- // read the chunk data and check the CRC
- if( mnChunkLen && !mrPNGStream.eof() )
- {
- rChunkData.aData.resize( mnChunkLen );
-
- sal_Int32 nBytesRead = 0;
- do
- {
- sal_uInt8& rPtr = rChunkData.aData[nBytesRead];
- nBytesRead += mrPNGStream.ReadBytes(&rPtr, mnChunkLen - nBytesRead);
- } while (nBytesRead < mnChunkLen && mrPNGStream.good());
-
- nCRC32 = rtl_crc32( nCRC32, rChunkData.aData.data(), mnChunkLen );
- maDataIter = rChunkData.aData.begin();
- }
- sal_uInt32 nCheck(0);
- mrPNGStream.ReadUInt32( nCheck );
- if (!mbIgnoreCRC && nCRC32 != nCheck)
- return false;
- }
- else
- {
- // the next chunk was already read
- mnChunkType = (*maChunkIter).nType;
- mnChunkLen = (*maChunkIter).aData.size();
- maDataIter = (*maChunkIter).aData.begin();
- }
-
- ++maChunkIter;
- return mnChunkType != PNGCHUNK_IEND;
-}
-
-const std::vector< vcl::PNGReader::ChunkData >& PNGReaderImpl::GetAllChunks()
-{
- // read the remaining chunks from mrPNGStream
- while( ReadNextChunk() ) ;
- return maChunkSeq;
-}
-
-BitmapEx PNGReaderImpl::GetBitmapEx()
-{
- // reset to the first chunk
- maChunkIter = maChunkSeq.begin();
-
- // first chunk must be IDHR
- if( mbStatus && ReadNextChunk() )
- {
- if (mnChunkType == PNGCHUNK_IHDR)
- mbStatus = ImplReadHeader();
- else
- mbStatus = false;
- }
-
- // parse the remaining chunks
- while (mbStatus && !mbIDATComplete && ReadNextChunk())
- {
- switch( mnChunkType )
- {
- case PNGCHUNK_IHDR :
- {
- mbStatus = false; //IHDR should only appear as the first chunk
- }
- break;
-
- case PNGCHUNK_gAMA : // the gamma chunk must precede
- { // the 'IDAT' and also the 'PLTE'(if available )
- if (!mbIDATComplete)
- ImplGetGamma();
- }
- break;
-
- case PNGCHUNK_PLTE :
- {
- if (!mbPalette && !mbIDATStarted)
- mbStatus = ImplReadPalette();
- }
- break;
-
- case PNGCHUNK_tRNS :
- {
- if (!mbIDATComplete) // the tRNS chunk must precede the IDAT
- mbStatus = ImplReadTransparent();
- }
- break;
-
- case PNGCHUNK_bKGD : // the background chunk must appear
- {
- if (!mbIDATComplete && mbPalette) // before the 'IDAT' and after the
- ImplGetBackground(); // PLTE(if available ) chunk.
- }
- break;
-
- case PNGCHUNK_IDAT :
- {
- if ( !mpInflateInBuf ) // taking care that the header has properly been read
- mbStatus = false;
- else if (!mbIDATComplete) // the gfx is finished, but there may be left a zlibCRC of about 4Bytes
- ImplReadIDAT();
- }
- break;
-
- case PNGCHUNK_pHYs :
- {
- if (!mbIDATComplete && mnChunkLen == 9)
- {
- sal_uInt32 nXPixelPerMeter = ImplReadsal_uInt32();
- sal_uInt32 nYPixelPerMeter = ImplReadsal_uInt32();
-
- sal_uInt8 nUnitSpecifier = *maDataIter++;
- if( (nUnitSpecifier == 1) && nXPixelPerMeter && nYPixelPerMeter )
- {
- mbpHYs = true;
-
- // convert into MapUnit::Map100thMM
- maPhysSize.setWidth( static_cast<sal_Int32>( (100000.0 * maOrigSize.Width()) / nXPixelPerMeter ) );
- maPhysSize.setHeight( static_cast<sal_Int32>( (100000.0 * maOrigSize.Height()) / nYPixelPerMeter ) );
- }
- }
- }
- break;
-
- case PNGCHUNK_IEND:
- mbStatus = mbIDATComplete; // there is a problem if the image is not complete yet
- break;
- }
- }
-
- // release write access of the bitmaps
- mxAcc.reset();
- mxMaskAcc.reset();
- mxAlphaAcc.reset();
- mpMaskAcc = nullptr;
-
- // return the resulting BitmapEx
- BitmapEx aRet;
-
- if (!mbStatus || !mbIDATComplete)
- aRet.Clear();
- else
- {
- if ( mpAlphaMask )
- aRet = BitmapEx( *mpBmp, *mpAlphaMask );
- else if ( mpMaskBmp )
- aRet = BitmapEx( *mpBmp, *mpMaskBmp );
- else
- aRet = *mpBmp;
-
- if ( mbpHYs && maPhysSize.Width() && maPhysSize.Height() )
- {
- aRet.SetPrefMapMode(MapMode(MapUnit::Map100thMM));
- aRet.SetPrefSize( maPhysSize );
- }
- }
- return aRet;
-}
-
-bool PNGReaderImpl::ImplReadHeader()
-{
- if( mnChunkLen < 13 )
- return false;
-
- maOrigSize.setWidth( ImplReadsal_uInt32() );
- maOrigSize.setHeight( ImplReadsal_uInt32() );
-
- if (maOrigSize.IsEmpty())
- return false;
-
- mnPngDepth = *(maDataIter++);
- mnColorType = *(maDataIter++);
-
- mnCompressionType = *(maDataIter++);
- if( mnCompressionType != 0 ) // unknown compression type
- return false;
-
- mnFilterType = *(maDataIter++);
- if( mnFilterType != 0 ) // unknown filter type
- return false;
-
- mnInterlaceType = *(maDataIter++);
- switch ( mnInterlaceType ) // filter type valid ?
- {
- case 0 : // progressive image
- mnPass = 7;
- break;
- case 1 : // Adam7-interlaced image
- mnPass = 0;
- break;
- default:
- return false;
- }
-
- mbPalette = true;
- mbIDATStarted = mbIDATComplete = mbAlphaChannel = mbTransparent = false;
- mbGrayScale = mbRGBTriple = false;
- mnTargetDepth = mnPngDepth;
- sal_uInt64 nScansize64 = ( ( static_cast< sal_uInt64 >( maOrigSize.Width() ) * mnPngDepth ) + 7 ) >> 3;
-
- // valid color types are 0,2,3,4 & 6
- switch ( mnColorType )
- {
- case 0 : // each pixel is a grayscale
- {
- switch ( mnPngDepth )
- {
- case 2 : // 2bit target not available -> use four bits
- mnTargetDepth = 4; // we have to expand the bitmap
- mbGrayScale = true;
- break;
- case 16 :
- mnTargetDepth = 8; // we have to reduce the bitmap
- [[fallthrough]];
- case 1 :
- case 4 :
- case 8 :
- mbGrayScale = true;
- break;
- default :
- return false;
- }
- }
- break;
-
- case 2 : // each pixel is an RGB triple
- {
- mbRGBTriple = true;
- nScansize64 *= 3;
- switch ( mnPngDepth )
- {
- case 16 : // we have to reduce the bitmap
- case 8 :
- mnTargetDepth = 24;
- break;
- default :
- return false;
- }
- }
- break;
-
- case 3 : // each pixel is a palette index
- {
- switch ( mnPngDepth )
- {
- case 2 :
- mnTargetDepth = 4; // we have to expand the bitmap
- mbPalette = false;
- break;
- case 1 :
- case 4 :
- case 8 :
- mbPalette = false;
- break;
- default :
- return false;
- }
- }
- break;
-
- case 4 : // each pixel is a grayscale sample followed by an alpha sample
- {
- nScansize64 *= 2;
- mbAlphaChannel = true;
- switch ( mnPngDepth )
- {
- case 16 :
- mnTargetDepth = 8; // we have to reduce the bitmap
- [[fallthrough]];
- case 8 :
- mbGrayScale = true;
- break;
- default :
- return false;
- }
- }
- break;
-
- case 6 : // each pixel is an RGB triple followed by an alpha sample
- {
- mbRGBTriple = true;
- nScansize64 *= 4;
- mbAlphaChannel = true;
- switch (mnPngDepth )
- {
- case 16 : // we have to reduce the bitmap
- case 8 :
- mnTargetDepth = 24;
- break;
- default :
- return false;
- }
- }
- break;
-
- default :
- return false;
- }
-
- mnBPP = static_cast< sal_uInt32 >( nScansize64 / maOrigSize.Width() );
- if ( !mnBPP )
- mnBPP = 1;
-
- nScansize64++; // each scanline includes one filterbyte
-
- if ( nScansize64 > SAL_MAX_UINT32 )
- return false;
-
- // assume max theoretical compression of 1:1032
- sal_uInt64 nMinSizeRequired = (nScansize64 * maOrigSize.Height()) / 1032;
- if (nMinSizeRequired > mnStreamSize)
- {
- SAL_WARN("vcl.gdi", "overlarge png dimensions: " <<
- maOrigSize.Width() << " x " << maOrigSize.Height() << " depth: " << static_cast<int>(mnPngDepth) <<
- " couldn't be supplied by file length " << mnStreamSize << " at least " << nMinSizeRequired << " needed ");
- return false;
- }
-
- mnScansize = static_cast< sal_uInt32 >( nScansize64 );
-
- maTargetSize.setWidth( (maOrigSize.Width() + mnPreviewMask) >> mnPreviewShift );
- maTargetSize.setHeight( (maOrigSize.Height() + mnPreviewMask) >> mnPreviewShift );
-
- //round bits up to nearest multiple of 8 and divide by 8 to get num of bytes per pixel
- int nBytesPerPixel = ((mnTargetDepth + 7) & ~7)/8;
-
- //stupidly big, forget about it
- if (maTargetSize.Width() >= SAL_MAX_INT32 / nBytesPerPixel / maTargetSize.Height())
- {
- SAL_WARN( "vcl.gdi", "overlarge png dimensions: " <<
- maTargetSize.Width() << " x " << maTargetSize.Height() << " depth: " << mnTargetDepth);
- return false;
- }
-
- // TODO: switch between both scanlines instead of copying
- mpInflateInBuf.reset( new (std::nothrow) sal_uInt8[ mnScansize ] );
- mpScanCurrent = mpInflateInBuf.get();
- mpScanPrior.reset( new (std::nothrow) sal_uInt8[ mnScansize ] );
-
- if ( !mpInflateInBuf || !mpScanPrior )
- return false;
-
- mpBmp = std::make_unique<Bitmap>( maTargetSize, mnTargetDepth );
- mxAcc = BitmapScopedWriteAccess(*mpBmp);
- if (!mxAcc)
- return false;
-
- if ( mbAlphaChannel )
- {
- mpAlphaMask = std::make_unique<AlphaMask>( maTargetSize );
- mpAlphaMask->Erase( 128 );
- mxAlphaAcc = AlphaScopedWriteAccess(*mpAlphaMask);
- mpMaskAcc = mxAlphaAcc.get();
- if (!mpMaskAcc)
- return false;
- }
-
- if ( mbGrayScale )
- ImplGetGrayPalette( mnPngDepth );
-
- ImplPreparePass();
-
- return true;
-}
-
-void PNGReaderImpl::ImplGetGrayPalette( sal_uInt16 nBitDepth )
-{
- if( nBitDepth > 8 )
- nBitDepth = 8;
-
- sal_uInt16 nPaletteEntryCount = 1 << nBitDepth;
- sal_uInt32 nAdd = nBitDepth ? 256 / (nPaletteEntryCount - 1) : 0;
-
- // no bitdepth==2 available
- // but bitdepth==4 with two unused bits is close enough
- if( nBitDepth == 2 )
- nPaletteEntryCount = 16;
-
- mxAcc->SetPaletteEntryCount( nPaletteEntryCount );
- for ( sal_uInt32 i = 0, nStart = 0; nStart < 256; i++, nStart += nAdd )
- mxAcc->SetPaletteColor( static_cast<sal_uInt16>(i), BitmapColor( mpColorTable[ nStart ],
- mpColorTable[ nStart ], mpColorTable[ nStart ] ) );
-}
-
-bool PNGReaderImpl::ImplReadPalette()
-{
- sal_uInt16 nCount = static_cast<sal_uInt16>( mnChunkLen / 3 );
-
- if ( ( ( mnChunkLen % 3 ) == 0 ) && ( ( 0 < nCount ) && ( nCount <= 256 ) ) && mxAcc )
- {
- mbPalette = true;
- mxAcc->SetPaletteEntryCount( nCount );
-
- for ( sal_uInt16 i = 0; i < nCount; i++ )
- {
- sal_uInt8 nRed = mpColorTable[ *maDataIter++ ];
- sal_uInt8 nGreen = mpColorTable[ *maDataIter++ ];
- sal_uInt8 nBlue = mpColorTable[ *maDataIter++ ];
- mxAcc->SetPaletteColor( i, Color( nRed, nGreen, nBlue ) );
- }
- }
- else
- mbStatus = false;
-
- return mbStatus;
-}
-
-bool PNGReaderImpl::ImplReadTransparent()
-{
- bool bNeedAlpha = false;
-
- if ( mpTransTab == nullptr )
- {
- switch ( mnColorType )
- {
- case 0 :
- {
- if ( mnChunkLen == 2 )
- {
- mpTransTab.reset( new sal_uInt8[ 256 ] );
- memset( mpTransTab.get(), 0xff, 256);
- // color type 0 and 4 is always greyscale,
- // so the return value can be used as index
- sal_uInt8 nIndex = ImplScaleColor();
- mpTransTab[ nIndex ] = 0;
- mbTransparent = true;
- }
- }
- break;
-
- case 2 :
- {
- if ( mnChunkLen == 6 )
- {
- mnTransRed = ImplScaleColor();
- mnTransGreen = ImplScaleColor();
- mnTransBlue = ImplScaleColor();
- mbTransparent = true;
- }
- }
- break;
-
- case 3 :
- {
- if ( mnChunkLen <= 256 )
- {
- mbTransparent = true;
- mpTransTab.reset( new sal_uInt8 [ 256 ] );
- memset( mpTransTab.get(), 0xff, 256 );
- if (mnChunkLen > 0)
- {
- memcpy( mpTransTab.get(), &(*maDataIter), mnChunkLen );
- maDataIter += mnChunkLen;
- // need alpha transparency if not on/off masking
- for( int i = 0; i < mnChunkLen; ++i )
- bNeedAlpha |= (mpTransTab[i]!=0x00) && (mpTransTab[i]!=0xFF);
- }
- }
- }
- break;
- }
- }
-
- if( mbTransparent && !mbAlphaChannel && !mpMaskBmp )
- {
- if( bNeedAlpha)
- {
- mpAlphaMask = std::make_unique<AlphaMask>( maTargetSize );
- mxAlphaAcc = AlphaScopedWriteAccess(*mpAlphaMask);
- mpMaskAcc = mxAlphaAcc.get();
- }
- else
- {
- mpMaskBmp = std::make_unique<Bitmap>( maTargetSize, 1 );
- mxMaskAcc = BitmapScopedWriteAccess(*mpMaskBmp);
- mpMaskAcc = mxMaskAcc.get();
- }
- mbTransparent = (mpMaskAcc != nullptr);
- if( !mbTransparent )
- return false;
- mpMaskAcc->Erase( Color(0,0,0) );
- }
-
- return true;
-}
-
-void PNGReaderImpl::ImplGetGamma()
-{
- if( mnChunkLen < 4 )
- return;
-
- sal_uInt32 nGammaValue = ImplReadsal_uInt32();
- double fGamma = ( VIEWING_GAMMA / DISPLAY_GAMMA ) * ( static_cast<double>(nGammaValue) / 100000 );
- double fInvGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma );
-
- if ( fInvGamma != 1.0 )
- {
- if ( mpColorTable == mpDefaultColorTable )
- mpColorTable = new sal_uInt8[ 256 ];
-
- for ( sal_Int32 i = 0; i < 256; i++ )
- mpColorTable[ i ] = static_cast<sal_uInt8>(pow(static_cast<double>(i)/255.0, fInvGamma) * 255.0 + 0.5);
-
- if ( mbGrayScale )
- ImplGetGrayPalette( mnPngDepth );
- }
-}
-
-void PNGReaderImpl::ImplGetBackground()
-{
- switch (mnColorType)
- {
- case 3:
- {
- if (mnChunkLen == 1)
- {
- sal_uInt16 nCol = *maDataIter++;
-
- if (nCol < mxAcc->GetPaletteEntryCount())
- {
- mxAcc->Erase(mxAcc->GetPaletteColor(static_cast<sal_uInt8>(nCol)));
- break;
- }
- }
- }
- break;
-
- case 0:
- case 4:
- {
- if (mnChunkLen == 2)
- {
- // the color type 0 and 4 is always greyscale,
- // so the return value can be used as index
- mxAcc->Erase(mxAcc->GetPaletteColor(ImplScaleColor()));
- }
- }
- break;
-
- case 2:
- case 6:
- {
- if (mnChunkLen == 6)
- {
- sal_uInt8 nRed = ImplScaleColor();
- sal_uInt8 nGreen = ImplScaleColor();
- sal_uInt8 nBlue = ImplScaleColor();
- // ofz#18653 slow and uninteresting
- if (utl::ConfigManager::IsFuzzing())
- return;
- mxAcc->Erase(Color(nRed, nGreen, nBlue));
- }
- }
- break;
- }
-}
-
-// for color type 0 and 4 (greyscale) the return value is always index to the color
-// 2 and 6 (RGB) the return value is always the 8 bit color component
-sal_uInt8 PNGReaderImpl::ImplScaleColor()
-{
- sal_uInt32 nMask = ( 1 << mnPngDepth ) - 1;
- sal_uInt16 nCol = ( *maDataIter++ << 8 );
-
- nCol += *maDataIter++ & static_cast<sal_uInt16>(nMask);
-
- if ( mnPngDepth > 8 ) // convert 16bit graphics to 8
- nCol >>= 8;
-
- return static_cast<sal_uInt8>(nCol);
-}
-
-// ImplReadIDAT reads as much image data as needed
-
-void PNGReaderImpl::ImplReadIDAT()
-{
- //when fuzzing with a max len set, max decompress to 250 times that limit
- static size_t nMaxAllowedDecompression = [](const char* pEnv) { size_t nRet = pEnv ? std::atoi(pEnv) : 0; return nRet * 250; }(std::getenv("FUZZ_MAX_INPUT_LEN"));
- size_t nTotalDataRead = 0;
-
- if( mnChunkLen > 0 )
- {
- mbIDATStarted = true;
-
- if ( !mbzCodecInUse )
- {
- mbzCodecInUse = true;
- mpZCodec.BeginCompression( ZCODEC_NO_COMPRESSION );
- }
- mpZCodec.SetBreak( mnChunkLen );
- SvMemoryStream aIStrm( &(*maDataIter), mnChunkLen, StreamMode::READ );
-
- while ( mpZCodec.GetBreak() )
- {
- // get bytes needed to fill the current scanline
- sal_Int32 nToRead = mnScansize - (mpScanCurrent - mpInflateInBuf.get());
- sal_Int32 nRead = mpZCodec.ReadAsynchron( aIStrm, mpScanCurrent, nToRead );
- if ( nRead < 0 )
- {
- mbStatus = false;
- break;
- }
- nTotalDataRead += nRead;
- if (nMaxAllowedDecompression && nTotalDataRead > nMaxAllowedDecompression)
- {
- mbStatus = false;
- break;
- }
- if ( nRead < nToRead )
- {
- mpScanCurrent += nRead; // more ZStream data in the next IDAT chunk
- break;
- }
- else // this scanline is Finished
- {
- mpScanCurrent = mpInflateInBuf.get();
- ImplApplyFilter();
-
- ImplDrawScanline( mnXStart, mnXAdd );
- mnYpos += mnYAdd;
- }
-
- if ( mnYpos >= o3tl::make_unsigned(maOrigSize.Height()) )
- {
- if( (mnPass < 7) && mnInterlaceType )
- if( ImplPreparePass() )
- continue;
- mbIDATComplete = true;
- break;
- }
- }
- }
-
- if (mbIDATComplete)
- {
- mpZCodec.EndCompression();
- mbzCodecInUse = false;
- }
-}
-
-bool PNGReaderImpl::ImplPreparePass()
-{
- struct InterlaceParams{ int mnXStart, mnYStart, mnXAdd, mnYAdd; };
- static const InterlaceParams aInterlaceParams[8] =
- {
- // non-interlaced
- { 0, 0, 1, 1 },
- // Adam7-interlaced
- { 0, 0, 8, 8 }, // pass 1
- { 4, 0, 8, 8 }, // pass 2
- { 0, 4, 4, 8 }, // pass 3
- { 2, 0, 4, 4 }, // pass 4
- { 0, 2, 2, 4 }, // pass 5
- { 1, 0, 2, 2 }, // pass 6
- { 0, 1, 1, 2 } // pass 7
- };
-
- const InterlaceParams* pParam = &aInterlaceParams[ 0 ];
- if( mnInterlaceType )
- {
- while( ++mnPass <= 7 )
- {
- pParam = &aInterlaceParams[ mnPass ];
-
- // skip this pass if the original image is too small for it
- if( (pParam->mnXStart < maOrigSize.Width())
- && (pParam->mnYStart < maOrigSize.Height()) )
- break;
- }
- if( mnPass > 7 )
- return false;
-
- // skip the last passes if possible (for scaled down target images)
- if( mnPreviewMask & (pParam->mnXStart | pParam->mnYStart) )
- return false;
- }
-
- mnYpos = pParam->mnYStart;
- mnXStart = pParam->mnXStart;
- mnXAdd = pParam->mnXAdd;
- mnYAdd = pParam->mnYAdd;
-
- // in Interlace mode the size of scanline is not constant
- // so first we calculate the number of entries
- tools::Long nScanWidth = (maOrigSize.Width() - mnXStart + mnXAdd - 1) / mnXAdd;
- mnScansize = nScanWidth;
-
- if( mbRGBTriple )
- mnScansize = 3 * nScanWidth;
-
- if( mbAlphaChannel )
- mnScansize += nScanWidth;
-
- // convert to width in bytes
- mnScansize = ( mnScansize*mnPngDepth + 7 ) >> 3;
-
- ++mnScansize; // scan size also needs room for the filtertype byte
- memset( mpScanPrior.get(), 0, mnScansize );
-
- return true;
-}
-
-// ImplApplyFilter writes the complete Scanline (nY)
-// in interlace mode the parameter nXStart and nXAdd are non-zero
-
-void PNGReaderImpl::ImplApplyFilter()
-{
- OSL_ASSERT( mnScansize >= mnBPP + 1 );
- const sal_uInt8* const pScanEnd = mpInflateInBuf.get() + mnScansize;
-
- sal_uInt8 nFilterType = mpInflateInBuf[0]; // the filter type may change each scanline
- switch ( nFilterType )
- {
- default: // unknown Scanline Filter Type
- case 0: // Filter Type "None"
- // we let the pixels pass and display the data unfiltered
- break;
-
- case 1: // Scanline Filter Type "Sub"
- {
- sal_uInt8* p1 = mpInflateInBuf.get() + 1;
- const sal_uInt8* p2 = p1;
- p1 += mnBPP;
-
- // use left pixels
- while (p1 < pScanEnd)
- {
- *p1 = static_cast<sal_uInt8>( *p1 + *(p2++) );
- ++p1;
- }
- }
- break;
-
- case 2: // Scanline Filter Type "Up"
- {
- sal_uInt8* p1 = mpInflateInBuf.get() + 1;
- const sal_uInt8* p2 = mpScanPrior.get() + 1;
-
- // use pixels from prior line
- while( p1 < pScanEnd )
- {
- *p1 = static_cast<sal_uInt8>( *p1 + *(p2++) );
- ++p1;
- }
- }
- break;
-
- case 3: // Scanline Filter Type "Average"
- {
- sal_uInt8* p1 = mpInflateInBuf.get() + 1;
- const sal_uInt8* p2 = mpScanPrior.get() + 1;
- const sal_uInt8* p3 = p1;
-
- // use one pixel from prior line
- for( int n = mnBPP; --n >= 0; ++p1, ++p2)
- *p1 = static_cast<sal_uInt8>( *p1 + (*p2 >> 1) );
-
- // predict by averaging the left and prior line pixels
- while( p1 < pScanEnd )
- {
- *p1 = static_cast<sal_uInt8>( *p1 + ((*(p2++) + *(p3++)) >> 1) );
- ++p1;
- }
- }
- break;
-
- case 4: // Scanline Filter Type "PathPredictor"
- {
- sal_uInt8* p1 = mpInflateInBuf.get() + 1;
- const sal_uInt8* p2 = mpScanPrior.get() + 1;
- const sal_uInt8* p3 = p1;
- const sal_uInt8* p4 = p2;
-
- // use one pixel from prior line
- for( int n = mnBPP; --n >= 0; ++p1)
- *p1 = static_cast<sal_uInt8>( *p1 + *(p2++) );
-
- // predict by using the left and the prior line pixels
- while( p1 < pScanEnd )
- {
- int na = *(p2++);
- int nb = *(p3++);
- int nc = *(p4++);
-
- int npa = nb - nc;
- int npb = na - nc;
- int npc = npa + npb;
-
- if( npa < 0 )
- npa =-npa;
- if( npb < 0 )
- npb =-npb;
- if( npc < 0 )
- npc =-npc;
-
- if( npa > npb )
- {
- na = nb;
- npa = npb;
- }
- if( npa > npc )
- na = nc;
-
- *p1 = static_cast<sal_uInt8>( *p1 + na );
- ++p1;
- }
- }
- break;
- }
-
- memcpy( mpScanPrior.get(), mpInflateInBuf.get(), mnScansize );
-}
-
-namespace
-{
- sal_uInt8 SanitizePaletteIndex(sal_uInt8 nIndex, sal_uInt16 nPaletteEntryCount)
- {
- if (nIndex >= nPaletteEntryCount)
- {
- auto nSanitizedIndex = nIndex % nPaletteEntryCount;
- SAL_WARN_IF(nIndex != nSanitizedIndex, "vcl", "invalid colormap index: "
- << static_cast<unsigned int>(nIndex) << ", colormap len is: "
- << nPaletteEntryCount);
- nIndex = nSanitizedIndex;
- }
- return nIndex;
- }
-
- void SanitizePaletteIndexes(sal_uInt8* pEntries, int nLen, const BitmapScopedWriteAccess& rAcc)
- {
- sal_uInt16 nPaletteEntryCount = rAcc->GetPaletteEntryCount();
- for (int nX = 0; nX < nLen; ++nX)
- {
- if (pEntries[nX] >= nPaletteEntryCount)
- {
- SAL_WARN("vcl.gdi", "invalid colormap index: "
- << static_cast<unsigned int>(pEntries[nX]) << ", colormap len is: "
- << nPaletteEntryCount);
- pEntries[nX] = pEntries[nX] % nPaletteEntryCount;
- }
- }
- }
-}
-
-// ImplDrawScanlines draws the complete Scanline (nY) into the target bitmap
-// In interlace mode the parameter nXStart and nXAdd append to the currently used pass
-
-void PNGReaderImpl::ImplDrawScanline( sal_uInt32 nXStart, sal_uInt32 nXAdd )
-{
- // optimization for downscaling
- if( mnYpos & mnPreviewMask )
- return;
- if( nXStart & mnPreviewMask )
- return;
-
- // convert nY to pixel units in the target image
- // => TODO; also do this for nX here instead of in the ImplSet*Pixel() methods
- const sal_uInt32 nY = mnYpos >> mnPreviewShift;
-
- sal_uInt8* pTmp = mpInflateInBuf.get() + 1;
- if ( mxAcc->HasPalette() ) // alphachannel is not allowed by pictures including palette entries
- {
- switch ( mxAcc->GetBitCount() )
- {
- case 1 :
- {
- if ( mbTransparent )
- {
- for ( tools::Long nX = nXStart, nShift = 0; nX < maOrigSize.Width(); nX += nXAdd )
- {
- sal_uInt8 nCol;
- nShift = (nShift - 1) & 7;
- if ( nShift == 0 )
- nCol = *(pTmp++);
- else
- nCol = static_cast<sal_uInt8>( *pTmp >> nShift );
- nCol &= 1;
-
- ImplSetAlphaPixel( nY, nX, nCol, mpTransTab[ nCol ] );
- }
- }
- else
- { // ScanlineFormat::N1BitMsbPal
- for ( tools::Long nX = nXStart, nShift = 0; nX < maOrigSize.Width(); nX += nXAdd )
- {
- nShift = (nShift - 1) & 7;
-
- sal_uInt8 nCol;
- if ( nShift == 0 )
- nCol = *(pTmp++);
- else
- nCol = static_cast<sal_uInt8>( *pTmp >> nShift );
- nCol &= 1;
-
- ImplSetPixel( nY, nX, nCol );
- }
- }
- }
- break;
-
- case 4 :
- {
- if ( mbTransparent )
- {
- if ( mnPngDepth == 4 ) // check if source has a two bit pixel format
- {
- for ( tools::Long nX = nXStart, nXIndex = 0; nX < maOrigSize.Width(); nX += nXAdd, ++nXIndex )
- {
- if( nXIndex & 1 )
- {
- ImplSetAlphaPixel( nY, nX, *pTmp & 0x0f, mpTransTab[ *pTmp & 0x0f ] );
- pTmp++;
- }
- else
- {
- ImplSetAlphaPixel( nY, nX, ( *pTmp >> 4 ) & 0x0f, mpTransTab[ *pTmp >> 4 ] );
- }
- }
- }
- else // if ( mnPngDepth == 2 )
- {
- for ( tools::Long nX = nXStart, nXIndex = 0; nX < maOrigSize.Width(); nX += nXAdd, nXIndex++ )
- {
- sal_uInt8 nCol;
- switch( nXIndex & 3 )
- {
- case 0 :
- nCol = *pTmp >> 6;
- break;
-
- case 1 :
- nCol = ( *pTmp >> 4 ) & 0x03 ;
- break;
-
- case 2 :
- nCol = ( *pTmp >> 2 ) & 0x03;
- break;
-
- case 3 :
- nCol = ( *pTmp++ ) & 0x03;
- break;
-
- default: // get rid of nCol uninitialized warning
- nCol = 0;
- break;
- }
-
- ImplSetAlphaPixel( nY, nX, nCol, mpTransTab[ nCol ] );
- }
- }
- }
- else
- {
- if ( mnPngDepth == 4 ) // maybe the source is a two bitmap graphic
- { // ScanlineFormat::N4BitLsnPal
- for ( tools::Long nX = nXStart, nXIndex = 0; nX < maOrigSize.Width(); nX += nXAdd, nXIndex++ )
- {
- if( nXIndex & 1 )
- ImplSetPixel( nY, nX, *pTmp++ & 0x0f );
- else
- ImplSetPixel( nY, nX, ( *pTmp >> 4 ) & 0x0f );
- }
- }
- else // if ( mnPngDepth == 2 )
- {
- for ( tools::Long nX = nXStart, nXIndex = 0; nX < maOrigSize.Width(); nX += nXAdd, nXIndex++ )
- {
- switch( nXIndex & 3 )
- {
- case 0 :
- ImplSetPixel( nY, nX, *pTmp >> 6 );
- break;
-
- case 1 :
- ImplSetPixel( nY, nX, ( *pTmp >> 4 ) & 0x03 );
- break;
-
- case 2 :
- ImplSetPixel( nY, nX, ( *pTmp >> 2 ) & 0x03 );
- break;
-
- case 3 :
- ImplSetPixel( nY, nX, *pTmp++ & 0x03 );
- break;
- }
- }
- }
- }
- }
- break;
-
- case 8 :
- {
- if ( mbAlphaChannel )
- {
- if ( mnPngDepth == 8 ) // maybe the source is a 16 bit grayscale
- {
- for ( tools::Long nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 2 )
- ImplSetAlphaPixel( nY, nX, pTmp[ 0 ], pTmp[ 1 ] );
- }
- else
- {
- assert(mnPngDepth == 16);
- for ( tools::Long nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 4 )
- ImplSetAlphaPixel( nY, nX, pTmp[ 0 ], pTmp[ 2 ] );
- }
- }
- else if ( mbTransparent )
- {
- if ( mnPngDepth == 8 ) // maybe the source is a 16 bit grayscale
- {
- for ( tools::Long nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp++ )
- ImplSetAlphaPixel( nY, nX, *pTmp, mpTransTab[ *pTmp ] );
- }
- else if (mnPngDepth == 1 )
- {
- for ( tools::Long nX = nXStart, nShift = 0; nX < maOrigSize.Width(); nX += nXAdd )
- {
- nShift = (nShift - 1) & 7;
-
- sal_uInt8 nCol;
- if ( nShift == 0 )
- nCol = *(pTmp++);
- else
- nCol = static_cast<sal_uInt8>( *pTmp >> nShift );
- nCol &= 1;
-
- ImplSetAlphaPixel( nY, nX, nCol, mpTransTab[ nCol ] );
- }
- }
- else
- {
- for ( tools::Long nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 2 )
- ImplSetAlphaPixel( nY, nX, *pTmp, mpTransTab[ *pTmp ] );
- }
- }
- else // neither alpha nor transparency
- {
- if ( mnPngDepth == 8 ) // maybe the source is a 16 bit grayscale or 1 bit indexed
- {
- if( nXAdd == 1 && mnPreviewShift == 0 ) // copy raw line data if possible
- {
- int nLineBytes = maOrigSize.Width();
- if (mbPalette)
- SanitizePaletteIndexes(pTmp, nLineBytes, mxAcc);
- mxAcc->CopyScanline( nY, pTmp, ScanlineFormat::N8BitPal, nLineBytes );
- }
- else
- {
- for ( tools::Long nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd )
- ImplSetPixel( nY, nX, *pTmp++ );
- }
- }
- else if (mnPngDepth == 1 )
- {
- for ( tools::Long nX = nXStart, nShift = 0; nX < maOrigSize.Width(); nX += nXAdd )
- {
- nShift = (nShift - 1) & 7;
-
- sal_uInt8 nCol;
- if ( nShift == 0 )
- nCol = *(pTmp++);
- else
- nCol = static_cast<sal_uInt8>( *pTmp >> nShift );
- nCol &= 1;
-
- ImplSetPixel( nY, nX, nCol );
- }
- }
- else
- {
- for ( tools::Long nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 2 )
- ImplSetPixel( nY, nX, *pTmp );
- }
- }
- }
- break;
-
- default :
- mbStatus = false;
- break;
- }
- }
- else // no palette => truecolor
- {
- if( mbAlphaChannel )
- {
- // has RGB + alpha
- if ( mnPngDepth == 8 ) // maybe the source has 16 bit per sample
- {
- // ScanlineFormat::N32BitTcRgba
- // only use DirectScanline when we have no preview shifting stuff and accesses to content and alpha
- const bool bDoDirectScanline(
- !nXStart && 1 == nXAdd && !mnPreviewShift && mpMaskAcc);
- const bool bCustomColorTable(mpColorTable != mpDefaultColorTable);
-
- if(bDoDirectScanline)
- {
- // allocate scanlines on demand, reused for next line
- if(!mpScanline)
- {
-#if OSL_DEBUG_LEVEL > 0
- mnAllocSizeScanline = maOrigSize.Width() * 3;
-#endif
- mpScanline.reset( new sal_uInt8[maOrigSize.Width() * 3] );
- }
-
- if(!mpScanlineAlpha)
- {
-#if OSL_DEBUG_LEVEL > 0
- mnAllocSizeScanlineAlpha = maOrigSize.Width();
-#endif
- mpScanlineAlpha.reset( new sal_uInt8[maOrigSize.Width()] );
- }
- }
-
- if(bDoDirectScanline)
- {
- OSL_ENSURE(mpScanline, "No Scanline allocated (!)");
- OSL_ENSURE(mpScanlineAlpha, "No ScanlineAlpha allocated (!)");
-#if OSL_DEBUG_LEVEL > 0
- OSL_ENSURE(mnAllocSizeScanline >= maOrigSize.Width() * 3, "Allocated Scanline too small (!)");
- OSL_ENSURE(mnAllocSizeScanlineAlpha >= maOrigSize.Width(), "Allocated ScanlineAlpha too small (!)");
-#endif
- sal_uInt8* pScanline(mpScanline.get());
- sal_uInt8* pScanlineAlpha(mpScanlineAlpha.get());
-
- for (tools::Long nX(0); nX < maOrigSize.Width(); nX++, pTmp += 4)
- {
- // prepare content line as BGR by reordering when copying
- // do not forget to invert alpha (source is alpha, target is opacity)
- if(bCustomColorTable)
- {
- *pScanline++ = mpColorTable[pTmp[2]];
- *pScanline++ = mpColorTable[pTmp[1]];
- *pScanline++ = mpColorTable[pTmp[0]];
- *pScanlineAlpha++ = ~pTmp[3];
- }
- else
- {
- *pScanline++ = pTmp[2];
- *pScanline++ = pTmp[1];
- *pScanline++ = pTmp[0];
- *pScanlineAlpha++ = ~pTmp[3];
- }
- }
-
- // copy scanlines directly to bitmaps for content and alpha; use the formats which
- // are able to copy directly to BitmapBuffer
- mxAcc->CopyScanline(nY, mpScanline.get(), ScanlineFormat::N24BitTcBgr, maOrigSize.Width() * 3);
- mpMaskAcc->CopyScanline(nY, mpScanlineAlpha.get(), ScanlineFormat::N8BitPal, maOrigSize.Width());
- }
- else
- {
- for ( tools::Long nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 4 )
- {
- if(bCustomColorTable)
- {
- ImplSetAlphaPixel(
- nY,
- nX,
- BitmapColor(
- mpColorTable[ pTmp[ 0 ] ],
- mpColorTable[ pTmp[ 1 ] ],
- mpColorTable[ pTmp[ 2 ] ]),
- pTmp[ 3 ]);
- }
- else
- {
- ImplSetAlphaPixel(
- nY,
- nX,
- BitmapColor(
- pTmp[0],
- pTmp[1],
- pTmp[2]),
- pTmp[3]);
- }
- }
- }
- }
- else
- {
- // BMP_FORMAT_64BIT_TC_RGBA
- for ( tools::Long nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 8 )
- {
- ImplSetAlphaPixel(
- nY,
- nX,
- BitmapColor(
- mpColorTable[ pTmp[ 0 ] ],
- mpColorTable[ pTmp[ 2 ] ],
- mpColorTable[ pTmp[ 4 ] ]),
- pTmp[6]);
- }
- }
- }
- else if( mbTransparent ) // has RGB + transparency
- {
- // ScanlineFormat::N24BitTcRgb
- // no support currently for DirectScanline, found no real usages in current PNGs, may be added on demand
- if ( mnPngDepth == 8 ) // maybe the source has 16 bit per sample
- {
- for ( tools::Long nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 3 )
- {
- sal_uInt8 nRed = pTmp[ 0 ];
- sal_uInt8 nGreen = pTmp[ 1 ];
- sal_uInt8 nBlue = pTmp[ 2 ];
- bool bTransparent = ( ( nRed == mnTransRed )
- && ( nGreen == mnTransGreen )
- && ( nBlue == mnTransBlue ) );
-
- ImplSetTranspPixel( nY, nX, BitmapColor( mpColorTable[ nRed ],
- mpColorTable[ nGreen ],
- mpColorTable[ nBlue ] ), bTransparent );
- }
- }
- else
- {
- // BMP_FORMAT_48BIT_TC_RGB
- for ( tools::Long nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 6 )
- {
- sal_uInt8 nRed = pTmp[ 0 ];
- sal_uInt8 nGreen = pTmp[ 2 ];
- sal_uInt8 nBlue = pTmp[ 4 ];
- bool bTransparent = ( ( nRed == mnTransRed )
- && ( nGreen == mnTransGreen )
- && ( nBlue == mnTransBlue ) );
-
- ImplSetTranspPixel( nY, nX, BitmapColor( mpColorTable[ nRed ],
- mpColorTable[ nGreen ],
- mpColorTable[ nBlue ] ), bTransparent );
- }
- }
- }
- else // has RGB but neither alpha nor transparency
- {
- // ScanlineFormat::N24BitTcRgb
- // only use DirectScanline when we have no preview shifting stuff and access to content
- const bool bDoDirectScanline(
- !nXStart && 1 == nXAdd && !mnPreviewShift);
- const bool bCustomColorTable(mpColorTable != mpDefaultColorTable);
-
- if(bDoDirectScanline && !mpScanline)
- {
- // allocate scanlines on demand, reused for next line
-#if OSL_DEBUG_LEVEL > 0
- mnAllocSizeScanline = maOrigSize.Width() * 3;
-#endif
- mpScanline.reset( new sal_uInt8[maOrigSize.Width() * 3] );
- }
-
- if ( mnPngDepth == 8 ) // maybe the source has 16 bit per sample
- {
- if(bDoDirectScanline)
- {
- OSL_ENSURE(mpScanline, "No Scanline allocated (!)");
-#if OSL_DEBUG_LEVEL > 0
- OSL_ENSURE(mnAllocSizeScanline >= maOrigSize.Width() * 3, "Allocated Scanline too small (!)");
-#endif
- sal_uInt8* pScanline(mpScanline.get());
-
- for (tools::Long nX(0); nX < maOrigSize.Width(); nX++, pTmp += 3)
- {
- // prepare content line as BGR by reordering when copying
- if(bCustomColorTable)
- {
- *pScanline++ = mpColorTable[pTmp[2]];
- *pScanline++ = mpColorTable[pTmp[1]];
- *pScanline++ = mpColorTable[pTmp[0]];
- }
- else
- {
- *pScanline++ = pTmp[2];
- *pScanline++ = pTmp[1];
- *pScanline++ = pTmp[0];
- }
- }
-
- // copy scanline directly to bitmap for content; use the format which is able to
- // copy directly to BitmapBuffer
- mxAcc->CopyScanline(nY, mpScanline.get(), ScanlineFormat::N24BitTcBgr, maOrigSize.Width() * 3);
- }
- else
- {
- for ( tools::Long nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 3 )
- {
- if(bCustomColorTable)
- {
- ImplSetPixel(
- nY,
- nX,
- BitmapColor(
- mpColorTable[ pTmp[ 0 ] ],
- mpColorTable[ pTmp[ 1 ] ],
- mpColorTable[ pTmp[ 2 ] ]));
- }
- else
- {
- ImplSetPixel(
- nY,
- nX,
- BitmapColor(
- pTmp[0],
- pTmp[1],
- pTmp[2]));
- }
- }
- }
- }
- else
- {
- // BMP_FORMAT_48BIT_TC_RGB
- // no support currently for DirectScanline, found no real usages in current PNGs, may be added on demand
- for ( tools::Long nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 6 )
- {
- ImplSetPixel(
- nY,
- nX,
- BitmapColor(
- mpColorTable[ pTmp[ 0 ] ],
- mpColorTable[ pTmp[ 2 ] ],
- mpColorTable[ pTmp[ 4 ] ]));
- }
- }
- }
- }
-}
-
-void PNGReaderImpl::ImplSetPixel( sal_uInt32 nY, sal_uInt32 nX, const BitmapColor& rBitmapColor )
-{
- // TODO: get preview mode checks out of inner loop
- if( nX & mnPreviewMask )
- return;
- nX >>= mnPreviewShift;
-
- mxAcc->SetPixel( nY, nX, rBitmapColor );
-}
-
-void PNGReaderImpl::ImplSetPixel( sal_uInt32 nY, sal_uInt32 nX, sal_uInt8 nPalIndex )
-{
- // TODO: get preview mode checks out of inner loop
- if( nX & mnPreviewMask )
- return;
- nX >>= mnPreviewShift;
-
- mxAcc->SetPixelIndex(nY, nX, SanitizePaletteIndex(nPalIndex, mxAcc->GetPaletteEntryCount()));
-}
-
-void PNGReaderImpl::ImplSetTranspPixel( sal_uInt32 nY, sal_uInt32 nX, const BitmapColor& rBitmapColor, bool bTrans )
-{
- // TODO: get preview mode checks out of inner loop
- if( nX & mnPreviewMask )
- return;
- nX >>= mnPreviewShift;
-
- mxAcc->SetPixel( nY, nX, rBitmapColor );
-
- if ( bTrans )
- mpMaskAcc->SetPixel( nY, nX, mcTranspColor );
- else
- mpMaskAcc->SetPixel( nY, nX, mcOpaqueColor );
-}
-
-void PNGReaderImpl::ImplSetAlphaPixel( sal_uInt32 nY, sal_uInt32 nX,
- sal_uInt8 nPalIndex, sal_uInt8 nAlpha )
-{
- // TODO: get preview mode checks out of inner loop
- if( nX & mnPreviewMask )
- return;
- nX >>= mnPreviewShift;
-
- mxAcc->SetPixelIndex(nY, nX, SanitizePaletteIndex(nPalIndex, mxAcc->GetPaletteEntryCount()));
- mpMaskAcc->SetPixel(nY, nX, BitmapColor(~nAlpha));
-}
-
-void PNGReaderImpl::ImplSetAlphaPixel( sal_uInt32 nY, sal_uInt32 nX,
- const BitmapColor& rBitmapColor, sal_uInt8 nAlpha )
-{
- // TODO: get preview mode checks out of inner loop
- if( nX & mnPreviewMask )
- return;
- nX >>= mnPreviewShift;
-
- mxAcc->SetPixel( nY, nX, rBitmapColor );
- if (!mpMaskAcc)
- return;
- mpMaskAcc->SetPixel(nY, nX, BitmapColor(~nAlpha));
-}
-
-sal_uInt32 PNGReaderImpl::ImplReadsal_uInt32()
-{
- sal_uInt32 nRet;
- nRet = *maDataIter++;
- nRet <<= 8;
- nRet |= *maDataIter++;
- nRet <<= 8;
- nRet |= *maDataIter++;
- nRet <<= 8;
- nRet |= *maDataIter++;
- return nRet;
-}
-
-PNGReader::PNGReader(SvStream& rIStream) :
- mpImpl(new vcl::PNGReaderImpl(rIStream))
-{
-}
-
-PNGReader::~PNGReader()
-{
-}
-
-BitmapEx PNGReader::Read()
-{
- return mpImpl->GetBitmapEx();
-}
-
-const std::vector< vcl::PNGReader::ChunkData >& PNGReader::GetChunks() const
-{
- return mpImpl->GetAllChunks();
-}
-
-} // namespace vcl
-
-/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/treelist/transfer.cxx b/vcl/source/treelist/transfer.cxx
index bee628edc60b..e659eef56c04 100644
--- a/vcl/source/treelist/transfer.cxx
+++ b/vcl/source/treelist/transfer.cxx
@@ -60,7 +60,7 @@
#include <rtl/strbuf.hxx>
#include <cstdio>
#include <vcl/dibtools.hxx>
-#include <vcl/pngread.hxx>
+#include <vcl/filter/PngImageReader.hxx>
#include <vcl/pngwrite.hxx>
#include <vcl/graphicfilter.hxx>
#include <memory>
@@ -1590,9 +1590,8 @@ bool TransferableDataHelper::GetBitmapEx( const DataFlavor& rFlavor, BitmapEx& r
if(!bSuppressPNG && rFlavor.MimeType.equalsIgnoreAsciiCase("image/png"))
{
// it's a PNG, import to BitmapEx
- vcl::PNGReader aPNGReader(*xStm);
-
- rBmpEx = aPNGReader.Read();
+ vcl::PngImageReader aPNGReader(*xStm);
+ rBmpEx = aPNGReader.read();
}
else if(!bSuppressJPEG && rFlavor.MimeType.equalsIgnoreAsciiCase("image/jpeg"))
{
diff --git a/vcl/workben/fftester.cxx b/vcl/workben/fftester.cxx
index 640bd1f54832..7d165d5a5957 100644
--- a/vcl/workben/fftester.cxx
+++ b/vcl/workben/fftester.cxx
@@ -41,7 +41,7 @@
#include <vcl/dibtools.hxx>
#include <vcl/event.hxx>
#include <vcl/graphicfilter.hxx>
-#include <vcl/pngread.hxx>
+#include <vcl/filter/PngImageReader.hxx>
#include <vcl/svapp.hxx>
#include <vcl/wmf.hxx>
#include <vcl/wrkwin.hxx>
@@ -155,8 +155,8 @@ SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv)
else if (strcmp(argv[2], "png") == 0)
{
SvFileStream aFileStream(out, StreamMode::READ);
- vcl::PNGReader aReader(aFileStream);
- ret = static_cast<int>(!!aReader.Read());
+ vcl::PngImageReader aReader(aFileStream);
+ ret = static_cast<int>(!!aReader.read());
}
else if (strcmp(argv[2], "bmp") == 0)
{
diff --git a/vcl/workben/pngfuzzer.cxx b/vcl/workben/pngfuzzer.cxx
index 2a3357830007..e5e3c9e8a239 100644
--- a/vcl/workben/pngfuzzer.cxx
+++ b/vcl/workben/pngfuzzer.cxx
@@ -8,7 +8,7 @@
*/
#include <tools/stream.hxx>
-#include <vcl/pngread.hxx>
+#include <vcl/filter/PngImageReader.hxx>
#include "commonfuzzer.hxx"
#include <config_features.h>
@@ -48,8 +48,8 @@ extern "C" void* lo_get_custom_widget_func(const char*)
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
SvMemoryStream aStream(const_cast<uint8_t*>(data), size, StreamMode::READ);
- vcl::PNGReader aReader(aStream);
- (void)aReader.Read();
+ vcl::PngImageReader aReader(aStream);
+ (void)aReader.read();
return 0;
}
diff --git a/vcl/workben/vcldemo.cxx b/vcl/workben/vcldemo.cxx
index e9df921c293e..e37ac96eba9b 100644
--- a/vcl/workben/vcldemo.cxx
+++ b/vcl/workben/vcldemo.cxx
@@ -39,7 +39,6 @@
#include <tools/urlobj.hxx>
#include <tools/stream.hxx>
#include <vcl/svapp.hxx>
-#include <vcl/pngread.hxx>
#include <vcl/wrkwin.hxx>
#include <vcl/virdev.hxx>
#include <vcl/graphicfilter.hxx>