summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorTomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>2020-05-01 19:24:01 +0200
committerTomaž Vajngerl <quikee@gmail.com>2020-05-03 13:04:51 +0200
commit1114ebb37487bd0f7ad0e327fa571a5c925b237c (patch)
tree5c779904a6757730b1b9ed9d702e060e3e5e02a6 /vcl
parent92b0a4d933d682bfce10fa5f04c7a966f20cde7a (diff)
vcl: add Graphic reading to TypeSerializer + tests
Change-Id: I73aafc4f9a6f964a31d116610df6cf15dc51770c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/93334 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Diffstat (limited to 'vcl')
-rw-r--r--vcl/inc/TypeSerializer.hxx8
-rw-r--r--vcl/qa/cppunit/TypeSerializerTest.cxx68
-rw-r--r--vcl/source/gdi/TypeSerializer.cxx172
3 files changed, 234 insertions, 14 deletions
diff --git a/vcl/inc/TypeSerializer.hxx b/vcl/inc/TypeSerializer.hxx
index 4ac7e06471ea..060876593aa5 100644
--- a/vcl/inc/TypeSerializer.hxx
+++ b/vcl/inc/TypeSerializer.hxx
@@ -26,6 +26,12 @@
#include <vcl/gfxlink.hxx>
#include <vcl/graph.hxx>
+constexpr sal_uInt32 createMagic(char char1, char char2, char char3, char char4)
+{
+ return (static_cast<sal_uInt32>(char1) << 24) | (static_cast<sal_uInt32>(char2) << 16)
+ | (static_cast<sal_uInt32>(char3) << 8) | (static_cast<sal_uInt32>(char4) << 0);
+}
+
class VCL_DLLPUBLIC TypeSerializer : public tools::GenericTypeSerializer
{
public:
@@ -37,7 +43,7 @@ public:
void readGfxLink(GfxLink& rGfxLink);
void writeGfxLink(const GfxLink& rGfxLink);
- static void readGraphic(Graphic& rGraphic);
+ void readGraphic(Graphic& rGraphic);
void writeGraphic(const Graphic& rGraphic);
};
diff --git a/vcl/qa/cppunit/TypeSerializerTest.cxx b/vcl/qa/cppunit/TypeSerializerTest.cxx
index 0c737a4c4f03..c7ad8827a28d 100644
--- a/vcl/qa/cppunit/TypeSerializerTest.cxx
+++ b/vcl/qa/cppunit/TypeSerializerTest.cxx
@@ -51,12 +51,12 @@ std::string toHexString(const std::vector<unsigned char>& a)
class TypeSerializerTest : public CppUnit::TestFixture
{
void testGradient();
- void testGraphic();
+ void testGraphic_Vector();
void testGraphic_Bitmap_NoGfxLink();
CPPUNIT_TEST_SUITE(TypeSerializerTest);
CPPUNIT_TEST(testGradient);
- CPPUNIT_TEST(testGraphic);
+ CPPUNIT_TEST(testGraphic_Vector);
CPPUNIT_TEST(testGraphic_Bitmap_NoGfxLink);
CPPUNIT_TEST_SUITE_END();
};
@@ -91,7 +91,7 @@ void TypeSerializerTest::testGradient()
CPPUNIT_ASSERT_EQUAL(sal_uInt16(30), aReadGradient.GetSteps());
}
-void TypeSerializerTest::testGraphic()
+void TypeSerializerTest::testGraphic_Vector()
{
test::Directories aDirectories;
OUString aURL = aDirectories.getURLFromSrc(DATA_DIRECTORY) + "SimpleExample.svg";
@@ -99,6 +99,7 @@ void TypeSerializerTest::testGraphic()
GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
Graphic aGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream);
aGraphic.makeAvailable();
+ BitmapChecksum aChecksum = aGraphic.getVectorGraphicData()->GetChecksum();
// Test WriteGraphic - Native Format 5
{
@@ -117,6 +118,13 @@ void TypeSerializerTest::testGraphic()
sal_uInt32 nType;
aMemoryStream.ReadUInt32(nType);
CPPUNIT_ASSERT_EQUAL(COMPAT_FORMAT('N', 'A', 'T', '5'), nType);
+
+ // Read it back
+ aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN);
+ Graphic aNewGraphic;
+ ReadGraphic(aMemoryStream, aNewGraphic);
+ CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aNewGraphic.GetType());
+ CPPUNIT_ASSERT_EQUAL(aChecksum, aNewGraphic.getVectorGraphicData()->GetChecksum());
}
// Test WriteGraphic - Normal
@@ -129,6 +137,18 @@ void TypeSerializerTest::testGraphic()
std::vector<unsigned char> aHash = calculateHash(aMemoryStream);
CPPUNIT_ASSERT_EQUAL(std::string("c2bed2099ce617f1cc035701de5186f0d43e3064"),
toHexString(aHash));
+
+ aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN);
+ sal_uInt32 nType;
+ aMemoryStream.ReadUInt32(nType);
+ CPPUNIT_ASSERT_EQUAL(createMagic('s', 'v', 'g', '0'), nType);
+
+ // Read it back
+ aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN);
+ Graphic aNewGraphic;
+ ReadGraphic(aMemoryStream, aNewGraphic);
+ CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aNewGraphic.GetType());
+ CPPUNIT_ASSERT_EQUAL(aChecksum, aNewGraphic.getVectorGraphicData()->GetChecksum());
}
// Test TypeSerializer - Native Format 5
@@ -151,6 +171,16 @@ void TypeSerializerTest::testGraphic()
sal_uInt32 nType;
aMemoryStream.ReadUInt32(nType);
CPPUNIT_ASSERT_EQUAL(COMPAT_FORMAT('N', 'A', 'T', '5'), nType);
+
+ // Read it back
+ aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN);
+ Graphic aNewGraphic;
+ {
+ TypeSerializer aSerializer(aMemoryStream);
+ aSerializer.readGraphic(aNewGraphic);
+ }
+ CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aNewGraphic.GetType());
+ CPPUNIT_ASSERT_EQUAL(aChecksum, aNewGraphic.getVectorGraphicData()->GetChecksum());
}
// Test TypeSerializer - Normal
@@ -166,6 +196,21 @@ void TypeSerializerTest::testGraphic()
std::vector<unsigned char> aHash = calculateHash(aMemoryStream);
CPPUNIT_ASSERT_EQUAL(std::string("c2bed2099ce617f1cc035701de5186f0d43e3064"),
toHexString(aHash));
+
+ aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN);
+ sal_uInt32 nType;
+ aMemoryStream.ReadUInt32(nType);
+ CPPUNIT_ASSERT_EQUAL(createMagic('s', 'v', 'g', '0'), nType);
+
+ // Read it back
+ aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN);
+ Graphic aNewGraphic;
+ {
+ TypeSerializer aSerializer(aMemoryStream);
+ aSerializer.readGraphic(aNewGraphic);
+ }
+ CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aNewGraphic.GetType());
+ CPPUNIT_ASSERT_EQUAL(aChecksum, aNewGraphic.getVectorGraphicData()->GetChecksum());
}
}
@@ -191,6 +236,13 @@ void TypeSerializerTest::testGraphic_Bitmap_NoGfxLink()
sal_uInt16 nType;
aMemoryStream.ReadUInt16(nType);
CPPUNIT_ASSERT_EQUAL(sal_uInt16(0x4D42), nType); // Magic written with WriteDIBBitmapEx
+
+ // Read it back
+ aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN);
+ Graphic aNewGraphic;
+ ReadGraphic(aMemoryStream, aNewGraphic);
+ CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aNewGraphic.GetType());
+ CPPUNIT_ASSERT_EQUAL(aBitmapEx.GetChecksum(), aNewGraphic.GetBitmapExRef().GetChecksum());
}
// Test TypeSerializer
@@ -211,6 +263,16 @@ void TypeSerializerTest::testGraphic_Bitmap_NoGfxLink()
sal_uInt16 nType;
aMemoryStream.ReadUInt16(nType);
CPPUNIT_ASSERT_EQUAL(sal_uInt16(0x4D42), nType); // Magic written with WriteDIBBitmapEx
+
+ // Read it back
+ aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN);
+ Graphic aNewGraphic;
+ {
+ TypeSerializer aSerializer(aMemoryStream);
+ aSerializer.readGraphic(aNewGraphic);
+ }
+ CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aNewGraphic.GetType());
+ CPPUNIT_ASSERT_EQUAL(aBitmapEx.GetChecksum(), aNewGraphic.GetBitmapExRef().GetChecksum());
}
}
diff --git a/vcl/source/gdi/TypeSerializer.cxx b/vcl/source/gdi/TypeSerializer.cxx
index 8266c6ac9813..0f1fd0ee43b9 100644
--- a/vcl/source/gdi/TypeSerializer.cxx
+++ b/vcl/source/gdi/TypeSerializer.cxx
@@ -22,6 +22,7 @@
#include <sal/log.hxx>
#include <comphelper/fileformat.h>
#include <vcl/gdimtf.hxx>
+#include <vcl/dibtools.hxx>
TypeSerializer::TypeSerializer(SvStream& rStream)
: GenericTypeSerializer(rStream)
@@ -152,20 +153,171 @@ void TypeSerializer::writeGfxLink(const GfxLink& rGfxLink)
namespace
{
-constexpr sal_uInt32 constSvgMagic((sal_uInt32('s') << 24) | (sal_uInt32('v') << 16)
- | (sal_uInt32('g') << 8) | sal_uInt32('0'));
-constexpr sal_uInt32 constWmfMagic((sal_uInt32('w') << 24) | (sal_uInt32('m') << 16)
- | (sal_uInt32('f') << 8) | sal_uInt32('0'));
-constexpr sal_uInt32 constEmfMagic((sal_uInt32('e') << 24) | (sal_uInt32('m') << 16)
- | (sal_uInt32('f') << 8) | sal_uInt32('0'));
-constexpr sal_uInt32 constPdfMagic((sal_uInt32('s') << 24) | (sal_uInt32('v') << 16)
- | (sal_uInt32('g') << 8) | sal_uInt32('0'));
-
#define NATIVE_FORMAT_50 COMPAT_FORMAT('N', 'A', 'T', '5')
+constexpr sal_uInt32 constSvgMagic = createMagic('s', 'v', 'g', '0');
+constexpr sal_uInt32 constWmfMagic = createMagic('w', 'm', 'f', '0');
+constexpr sal_uInt32 constEmfMagic = createMagic('e', 'm', 'f', '0');
+constexpr sal_uInt32 constPdfMagic = createMagic('p', 'd', 'f', '0');
+
} // end anonymous namespace
-void TypeSerializer::readGraphic(Graphic& /*rGraphic*/) {}
+void TypeSerializer::readGraphic(Graphic& rGraphic)
+{
+ if (mrStream.GetError())
+ return;
+
+ const sal_uLong nInitialStreamPosition = mrStream.Tell();
+ sal_uInt32 nType;
+
+ // read Id
+ mrStream.ReadUInt32(nType);
+
+ // if there is no more data, avoid further expensive
+ // reading which will create VDevs and other stuff, just to
+ // read nothing. CAUTION: Eof is only true AFTER reading another
+ // byte, a speciality of SvMemoryStream (!)
+ if (!mrStream.good())
+ return;
+
+ if (NATIVE_FORMAT_50 == nType)
+ {
+ Graphic aGraphic;
+ GfxLink aLink;
+
+ // read compat info, destructor writes stuff into the header
+ {
+ VersionCompat aCompat(mrStream, StreamMode::READ);
+ }
+
+ readGfxLink(aLink);
+
+ if (!mrStream.GetError() && aLink.LoadNative(aGraphic))
+ {
+ if (aLink.IsPrefMapModeValid())
+ aGraphic.SetPrefMapMode(aLink.GetPrefMapMode());
+
+ if (aLink.IsPrefSizeValid())
+ aGraphic.SetPrefSize(aLink.GetPrefSize());
+ }
+ else
+ {
+ mrStream.Seek(nInitialStreamPosition);
+ mrStream.SetError(ERRCODE_IO_WRONGFORMAT);
+ }
+ rGraphic = aGraphic;
+ }
+ else
+ {
+ BitmapEx aBitmapEx;
+ const SvStreamEndian nOldFormat = mrStream.GetEndian();
+
+ mrStream.SeekRel(-4);
+ mrStream.SetEndian(SvStreamEndian::LITTLE);
+ ReadDIBBitmapEx(aBitmapEx, mrStream);
+
+ if (!mrStream.GetError())
+ {
+ sal_uInt32 nMagic1 = 0;
+ sal_uInt32 nMagic2 = 0;
+ sal_uInt64 nBeginPoisition = mrStream.Tell();
+
+ mrStream.ReadUInt32(nMagic1);
+ mrStream.ReadUInt32(nMagic2);
+ mrStream.Seek(nBeginPoisition);
+
+ if (!mrStream.GetError())
+ {
+ if (nMagic1 == 0x5344414e && nMagic2 == 0x494d4931)
+ {
+ Animation aAnimation;
+ ReadAnimation(mrStream, aAnimation);
+
+ // #108077# manually set loaded BmpEx to Animation
+ // (which skips loading its BmpEx if already done)
+ aAnimation.SetBitmapEx(aBitmapEx);
+ rGraphic = Graphic(aAnimation);
+ }
+ else
+ {
+ rGraphic = Graphic(aBitmapEx);
+ }
+ }
+ else
+ {
+ mrStream.ResetError();
+ }
+ }
+ else
+ {
+ Graphic aGraphic;
+ GDIMetaFile aMetaFile;
+
+ mrStream.Seek(nInitialStreamPosition);
+ mrStream.ResetError();
+ ReadGDIMetaFile(mrStream, aMetaFile);
+
+ if (!mrStream.GetError())
+ {
+ rGraphic = Graphic(aMetaFile);
+ }
+ else
+ {
+ ErrCode nOriginalError = mrStream.GetErrorCode();
+ // try to stream in Svg defining data (length, byte array and evtl. path)
+ // See below (operator<<) for more information
+ sal_uInt32 nMagic;
+ mrStream.Seek(nInitialStreamPosition);
+ mrStream.ResetError();
+ mrStream.ReadUInt32(nMagic);
+
+ if (constSvgMagic == nMagic || constWmfMagic == nMagic || constEmfMagic == nMagic
+ || constPdfMagic == nMagic)
+ {
+ sal_uInt32 nLength = 0;
+ mrStream.ReadUInt32(nLength);
+
+ if (nLength)
+ {
+ VectorGraphicDataArray aData(nLength);
+
+ mrStream.ReadBytes(aData.getArray(), nLength);
+ OUString aPath = mrStream.ReadUniOrByteString(mrStream.GetStreamCharSet());
+
+ if (!mrStream.GetError())
+ {
+ VectorGraphicDataType aDataType(VectorGraphicDataType::Svg);
+
+ switch (nMagic)
+ {
+ case constWmfMagic:
+ aDataType = VectorGraphicDataType::Wmf;
+ break;
+ case constEmfMagic:
+ aDataType = VectorGraphicDataType::Emf;
+ break;
+ case constPdfMagic:
+ aDataType = VectorGraphicDataType::Pdf;
+ break;
+ }
+
+ auto aVectorGraphicDataPtr
+ = std::make_shared<VectorGraphicData>(aData, aPath, aDataType);
+ rGraphic = Graphic(aVectorGraphicDataPtr);
+ }
+ }
+ }
+ else
+ {
+ mrStream.SetError(nOriginalError);
+ }
+
+ mrStream.Seek(nInitialStreamPosition);
+ }
+ }
+ mrStream.SetEndian(nOldFormat);
+ }
+}
void TypeSerializer::writeGraphic(const Graphic& rGraphic)
{