[Libreoffice-commits] core.git: include/vcl vcl/source
LuboÅ¡ LuÅák (via logerrit)
logerrit at kemper.freedesktop.org
Fri Mar 12 14:37:19 UTC 2021
include/vcl/filter/PngImageReader.hxx | 5 +
vcl/source/filter/png/PngImageReader.cxx | 87 ++++++++++++++++++++++++++++---
2 files changed, 85 insertions(+), 7 deletions(-)
New commits:
commit e286bd791bfaa00746ea143303761f76e0af1f0d
Author: Luboš Luňák <l.lunak at collabora.com>
AuthorDate: Fri Mar 5 19:42:41 2021 +0100
Commit: Luboš Luňák <l.lunak at collabora.com>
CommitDate: Fri Mar 12 15:36:32 2021 +0100
add support for Microsoft Gif chunk to PngImageReader
Change-Id: I7d7f47041c48eb1a19e2aaee0c6da8c675ada4b1
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/112039
Tested-by: Jenkins
Reviewed-by: Luboš Luňák <l.lunak at collabora.com>
diff --git a/include/vcl/filter/PngImageReader.hxx b/include/vcl/filter/PngImageReader.hxx
index 97b2616883b2..2cd57549cf49 100644
--- a/include/vcl/filter/PngImageReader.hxx
+++ b/include/vcl/filter/PngImageReader.hxx
@@ -34,6 +34,11 @@ public:
PngImageReader(SvStream& rStream);
bool read(BitmapEx& rBitmap);
+
+ // Returns the contents of the msOG chunk (containing a Gif image), if it exists.
+ // Does not change position in the stream.
+ static std::unique_ptr<sal_uInt8[]> getMicrosoftGifChunk(SvStream& rStream,
+ sal_Int32* chunkSize = nullptr);
};
} // namespace vcl
diff --git a/vcl/source/filter/png/PngImageReader.cxx b/vcl/source/filter/png/PngImageReader.cxx
index 3351e314b3fe..829f3dd45bca 100644
--- a/vcl/source/filter/png/PngImageReader.cxx
+++ b/vcl/source/filter/png/PngImageReader.cxx
@@ -10,6 +10,7 @@
#include <vcl/filter/PngImageReader.hxx>
#include <png.h>
+#include <rtl/crc.h>
#include <tools/stream.hxx>
#include <vcl/bitmap.hxx>
#include <vcl/alpha.hxx>
@@ -40,18 +41,20 @@ void lclReadStream(png_structp pPng, png_bytep pOutBytes, png_size_t nBytesToRea
}
}
-bool reader(SvStream& rStream, BitmapEx& rBitmapEx, bool bUseBitmap32)
-{
- enum
- {
- PNG_SIGNATURE_SIZE = 8
- };
+constexpr int PNG_SIGNATURE_SIZE = 8;
+bool isPng(SvStream& rStream)
+{
// Check signature bytes
sal_uInt8 aHeader[PNG_SIGNATURE_SIZE];
rStream.ReadBytes(aHeader, PNG_SIGNATURE_SIZE);
- if (png_sig_cmp(aHeader, 0, PNG_SIGNATURE_SIZE))
+ return png_sig_cmp(aHeader, 0, PNG_SIGNATURE_SIZE) == 0;
+}
+
+bool reader(SvStream& rStream, BitmapEx& rBitmapEx, bool bUseBitmap32)
+{
+ if (!isPng(rStream))
return false;
png_structp pPng = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
@@ -347,6 +350,64 @@ bool reader(SvStream& rStream, BitmapEx& rBitmapEx, bool bUseBitmap32)
return true;
}
+std::unique_ptr<sal_uInt8[]> getMsGifChunk(SvStream& rStream, sal_Int32* chunkSize)
+{
+ if (chunkSize)
+ *chunkSize = 0;
+ if (!isPng(rStream))
+ return nullptr;
+ // It's easier to read manually the contents and find the chunk than
+ // try to get it using libpng.
+ // https://en.wikipedia.org/wiki/Portable_Network_Graphics#File_format
+ // Each chunk is: 4 bytes length, 4 bytes type, <length> bytes, 4 bytes crc
+ for (;;)
+ {
+ sal_uInt32 length, type, crc;
+ rStream.ReadUInt32(length);
+ rStream.ReadUInt32(type);
+ if (!rStream.good())
+ return nullptr;
+ constexpr sal_uInt32 PNGCHUNK_msOG = 0x6d734f47; // Microsoft Office Animated GIF
+ constexpr sal_uInt64 MSGifHeaderSize = 11; // "MSOFFICE9.0"
+ if (type == PNGCHUNK_msOG && length > MSGifHeaderSize)
+ {
+ // calculate chunktype CRC (swap it back to original byte order)
+ sal_uInt32 typeForCrc = type;
+#if defined(__LITTLEENDIAN) || defined(OSL_LITENDIAN)
+ typeForCrc = OSL_SWAPDWORD(typeForCrc);
+#endif
+ sal_uInt32 computedCrc = rtl_crc32(0, &typeForCrc, 4);
+ const sal_uInt64 pos = rStream.Tell();
+ if (pos + length >= rStream.TellEnd())
+ return nullptr; // broken PNG
+
+ char msHeader[MSGifHeaderSize];
+ if (rStream.ReadBytes(msHeader, MSGifHeaderSize) != MSGifHeaderSize)
+ return nullptr;
+ computedCrc = rtl_crc32(computedCrc, msHeader, MSGifHeaderSize);
+ length -= MSGifHeaderSize;
+
+ std::unique_ptr<sal_uInt8[]> chunk(new sal_uInt8[length]);
+ if (rStream.ReadBytes(chunk.get(), length) != length)
+ return nullptr;
+ computedCrc = rtl_crc32(computedCrc, chunk.get(), length);
+ rStream.ReadUInt32(crc);
+ if (crc != computedCrc)
+ continue; // invalid chunk, ignore
+ if (chunkSize)
+ *chunkSize = length;
+ return chunk;
+ }
+ if (rStream.remainingSize() < length)
+ return nullptr;
+ rStream.SeekRel(length);
+ rStream.ReadUInt32(crc);
+ constexpr sal_uInt32 PNGCHUNK_IEND = 0x49454e44;
+ if (type == PNGCHUNK_IEND)
+ return nullptr;
+ }
+}
+
} // anonymous namespace
namespace vcl
@@ -364,6 +425,18 @@ bool PngImageReader::read(BitmapEx& rBitmapEx)
return reader(mrStream, rBitmapEx, bSupportsBitmap32);
}
+std::unique_ptr<sal_uInt8[]> PngImageReader::getMicrosoftGifChunk(SvStream& rStream,
+ sal_Int32* chunkSize)
+{
+ sal_uInt64 originalPosition = rStream.Tell();
+ SvStreamEndian originalEndian = rStream.GetEndian();
+ rStream.SetEndian(SvStreamEndian::BIG);
+ std::unique_ptr<sal_uInt8[]> chunk = getMsGifChunk(rStream, chunkSize);
+ rStream.SetEndian(originalEndian);
+ rStream.Seek(originalPosition);
+ return chunk;
+}
+
} // namespace vcl
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
More information about the Libreoffice-commits
mailing list