Fix GNU C++ version check
[LibreOffice.git] / vcl / source / gdi / vectorgraphicdata.cxx
blob953c0b66c822b0763a46b49ce88f2641f5402173
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <comphelper/diagnose_ex.hxx>
21 #include <tools/stream.hxx>
22 #include <sal/log.hxx>
23 #include <utility>
24 #include <vcl/vectorgraphicdata.hxx>
25 #include <comphelper/processfactory.hxx>
26 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
27 #include <com/sun/star/graphic/PdfTools.hpp>
28 #include <com/sun/star/graphic/SvgTools.hpp>
29 #include <com/sun/star/graphic/EmfTools.hpp>
30 #include <com/sun/star/graphic/Primitive2DTools.hpp>
31 #include <com/sun/star/rendering/XIntegerReadOnlyBitmap.hpp>
32 #include <com/sun/star/util/XAccounting.hpp>
33 #include <com/sun/star/util/XBinaryDataContainer.hpp>
34 #include <basegfx/matrix/b2dhommatrixtools.hxx>
35 #include <vcl/canvastools.hxx>
36 #include <comphelper/seqstream.hxx>
37 #include <comphelper/sequence.hxx>
38 #include <comphelper/propertysequence.hxx>
39 #include <comphelper/propertyvalue.hxx>
40 #include <pdf/PdfConfig.hxx>
41 #include <rtl/crc.h>
42 #include <vcl/svapp.hxx>
43 #include <vcl/outdev.hxx>
44 #include <vcl/wmfexternal.hxx>
45 #include <vcl/pdfread.hxx>
46 #include <unotools/streamwrap.hxx>
47 #include <graphic/UnoBinaryDataContainer.hxx>
49 using namespace ::com::sun::star;
51 BitmapEx convertPrimitive2DSequenceToBitmapEx(
52 const std::deque< css::uno::Reference< css::graphic::XPrimitive2D > >& rSequence,
53 const basegfx::B2DRange& rTargetRange,
54 const sal_uInt32 nMaximumQuadraticPixels,
55 const o3tl::Length eTargetUnit,
56 const std::optional<Size>& rTargetDPI)
58 BitmapEx aRetval;
60 if(!rSequence.empty())
62 // create replacement graphic from maSequence
63 // create XPrimitive2DRenderer
64 try
66 const uno::Reference< uno::XComponentContext >& xContext(::comphelper::getProcessComponentContext());
67 const uno::Reference< graphic::XPrimitive2DRenderer > xPrimitive2DRenderer = graphic::Primitive2DTools::create(xContext);
69 uno::Sequence< beans::PropertyValue > aViewParameters = {
70 comphelper::makePropertyValue(u"RangeUnit"_ustr, static_cast<sal_Int32>(eTargetUnit)),
72 geometry::RealRectangle2D aRealRect;
74 aRealRect.X1 = rTargetRange.getMinX();
75 aRealRect.Y1 = rTargetRange.getMinY();
76 aRealRect.X2 = rTargetRange.getMaxX();
77 aRealRect.Y2 = rTargetRange.getMaxY();
79 // get system DPI
80 Size aDPI(Application::GetDefaultDevice()->LogicToPixel(Size(1, 1), MapMode(MapUnit::MapInch)));
81 if (rTargetDPI.has_value())
83 aDPI = *rTargetDPI;
86 const uno::Reference< rendering::XBitmap > xBitmap(
87 xPrimitive2DRenderer->rasterize(
88 comphelper::containerToSequence(rSequence),
89 aViewParameters,
90 aDPI.getWidth(),
91 aDPI.getHeight(),
92 aRealRect,
93 nMaximumQuadraticPixels));
95 if(xBitmap.is())
97 const uno::Reference< rendering::XIntegerReadOnlyBitmap> xIntBmp(xBitmap, uno::UNO_QUERY_THROW);
98 aRetval = vcl::unotools::bitmapExFromXBitmap(xIntBmp);
101 catch (const uno::Exception&)
103 TOOLS_WARN_EXCEPTION("vcl", "Got no graphic::XPrimitive2DRenderer!");
105 catch (const std::exception& e)
107 SAL_WARN("vcl", "Got no graphic::XPrimitive2DRenderer! : " << e.what());
111 return aRetval;
114 static size_t estimateSize(
115 std::deque<uno::Reference<graphic::XPrimitive2D>> const& rSequence)
117 size_t nRet(0);
118 for (auto& it : rSequence)
120 uno::Reference<util::XAccounting> const xAcc(it, uno::UNO_QUERY);
121 assert(xAcc.is()); // we expect only BasePrimitive2D from SVG parser
122 nRet += xAcc->estimateUsage();
124 return nRet;
127 bool VectorGraphicData::operator==(const VectorGraphicData& rCandidate) const
129 if (getType() == rCandidate.getType())
131 if (maDataContainer.getSize() == rCandidate.maDataContainer.getSize())
133 if (0 == memcmp(
134 maDataContainer.getData(),
135 rCandidate.maDataContainer.getData(),
136 maDataContainer.getSize()))
138 return true;
143 return false;
146 void VectorGraphicData::ensurePdfReplacement()
148 assert(getType() == VectorGraphicDataType::Pdf);
150 if (!maReplacement.IsEmpty())
151 return; // nothing to do
153 // use PDFium directly
154 std::vector<BitmapEx> aBitmaps;
155 sal_Int32 nUsePageIndex = 0;
156 if (mnPageIndex >= 0)
157 nUsePageIndex = mnPageIndex;
158 vcl::RenderPDFBitmaps(maDataContainer.getData(),
159 maDataContainer.getSize(), aBitmaps, nUsePageIndex, 1,
160 &maSizeHint);
161 if (!aBitmaps.empty())
162 maReplacement = aBitmaps[0];
165 void VectorGraphicData::ensureReplacement()
167 if (!maReplacement.IsEmpty())
168 return; // nothing to do
170 // shortcut for PDF - PDFium can generate the replacement bitmap for us
171 // directly
172 if (getType() == VectorGraphicDataType::Pdf)
174 ensurePdfReplacement();
175 return;
178 ensureSequenceAndRange();
180 if (!maSequence.empty())
182 maReplacement = convertPrimitive2DSequenceToBitmapEx(maSequence, getRange());
186 BitmapEx VectorGraphicData::getBitmap(const Size& pixelSize) const
188 if (!maReplacement.IsEmpty() && maReplacement.GetSizePixel() == pixelSize)
189 return maReplacement;
191 if (getType() == VectorGraphicDataType::Pdf)
193 // use PDFium directly
194 const sal_Int32 nUsePageIndex = mnPageIndex > 0 ? mnPageIndex : 0;
195 const double dpi = vcl::pdf::getDefaultPdfResolutionDpi();
196 basegfx::B2DTuple sizeMM100(
197 o3tl::convert(pixelSize.Width() / dpi / vcl::PDF_INSERT_MAGIC_SCALE_FACTOR, o3tl::Length::in, o3tl::Length::mm100),
198 o3tl::convert(pixelSize.Height() / dpi / vcl::PDF_INSERT_MAGIC_SCALE_FACTOR, o3tl::Length::in, o3tl::Length::mm100));
199 std::vector<BitmapEx> aBitmaps;
200 vcl::RenderPDFBitmaps(maDataContainer.getData(), maDataContainer.getSize(), aBitmaps,
201 nUsePageIndex, 1, &sizeMM100);
202 if (!aBitmaps.empty())
203 return aBitmaps[0];
206 if (getPrimitive2DSequence().empty())
207 return {};
209 Size dpi(
210 std::round(pixelSize.Width() / o3tl::convert(maRange.getWidth(), o3tl::Length::mm100, o3tl::Length::in)),
211 std::round(pixelSize.Height() / o3tl::convert(maRange.getHeight(), o3tl::Length::mm100, o3tl::Length::in)));
212 return convertPrimitive2DSequenceToBitmapEx(maSequence, maRange, 4096 * 4096, o3tl::Length::mm100, dpi);
215 void VectorGraphicData::ensureSequenceAndRange()
217 if (mbSequenceCreated || maDataContainer.isEmpty())
218 return;
220 // import SVG to maSequence, also set maRange
221 maRange.reset();
223 // create Vector Graphic Data interpreter
224 const uno::Reference<uno::XComponentContext>& xContext(::comphelper::getProcessComponentContext());
226 switch (getType())
228 case VectorGraphicDataType::Svg:
230 const uno::Reference<io::XInputStream> xInputStream = maDataContainer.getAsXInputStream();
232 const uno::Reference< graphic::XSvgParser > xSvgParser = graphic::SvgTools::create(xContext);
234 if (xInputStream.is())
235 maSequence = comphelper::sequenceToContainer<std::deque<css::uno::Reference< css::graphic::XPrimitive2D >>>(xSvgParser->getDecomposition(xInputStream, OUString()));
237 break;
239 case VectorGraphicDataType::Emf:
240 case VectorGraphicDataType::Wmf:
242 const uno::Reference< graphic::XEmfParser > xEmfParser = graphic::EmfTools::create(xContext);
244 const uno::Reference<io::XInputStream> xInputStream = maDataContainer.getAsXInputStream();
246 if (xInputStream.is())
248 uno::Sequence< ::beans::PropertyValue > aPropertySequence;
250 // Pass the size hint of the graphic to the EMF parser.
251 geometry::RealPoint2D aSizeHint;
252 aSizeHint.X = maSizeHint.getX();
253 aSizeHint.Y = maSizeHint.getY();
254 xEmfParser->setSizeHint(aSizeHint);
256 if (!mbEnableEMFPlus)
258 aPropertySequence = { comphelper::makePropertyValue(u"EMFPlusEnable"_ustr, uno::Any(false)) };
261 maSequence = comphelper::sequenceToContainer<std::deque<css::uno::Reference< css::graphic::XPrimitive2D >>>(xEmfParser->getDecomposition(xInputStream, OUString(), aPropertySequence));
264 break;
266 case VectorGraphicDataType::Pdf:
268 const uno::Reference<graphic::XPdfDecomposer> xPdfDecomposer = graphic::PdfTools::create(xContext);
269 uno::Sequence<beans::PropertyValue> aDecompositionParameters = comphelper::InitPropertySequence({
270 {"PageIndex", uno::Any(sal_Int32(mnPageIndex))},
273 rtl::Reference<UnoBinaryDataContainer> xDataContainer = new UnoBinaryDataContainer(getBinaryDataContainer());
275 auto xPrimitive2D = xPdfDecomposer->getDecomposition(xDataContainer, aDecompositionParameters);
276 maSequence = comphelper::sequenceToContainer<std::deque<uno::Reference<graphic::XPrimitive2D>>>(xPrimitive2D);
278 break;
282 if(!maSequence.empty())
284 const sal_Int32 nCount(maSequence.size());
285 geometry::RealRectangle2D aRealRect;
286 uno::Sequence< beans::PropertyValue > aViewParameters;
288 for(sal_Int32 a(0); a < nCount; a++)
290 // get reference
291 const css::uno::Reference< css::graphic::XPrimitive2D > xReference(maSequence[a]);
293 if(xReference.is())
295 aRealRect = xReference->getRange(aViewParameters);
297 maRange.expand(
298 basegfx::B2DRange(
299 aRealRect.X1,
300 aRealRect.Y1,
301 aRealRect.X2,
302 aRealRect.Y2));
306 mNestedBitmapSize = estimateSize(maSequence);
307 mbSequenceCreated = true;
310 std::pair<VectorGraphicData::State, size_t> VectorGraphicData::getSizeBytes() const
312 if (!maSequence.empty() && !maDataContainer.isEmpty())
314 return std::make_pair(State::PARSED, maDataContainer.getSize() + mNestedBitmapSize);
316 else
318 return std::make_pair(State::UNPARSED, maDataContainer.getSize());
322 VectorGraphicData::VectorGraphicData(
323 BinaryDataContainer aDataContainer,
324 VectorGraphicDataType eVectorDataType,
325 sal_Int32 nPageIndex)
326 : maDataContainer(std::move(aDataContainer)),
327 mbSequenceCreated(false),
328 mNestedBitmapSize(0),
329 meType(eVectorDataType),
330 mnPageIndex(nPageIndex)
334 VectorGraphicData::VectorGraphicData(
335 const OUString& rPath,
336 VectorGraphicDataType eVectorDataType)
337 : mbSequenceCreated(false),
338 mNestedBitmapSize(0),
339 meType(eVectorDataType),
340 mnPageIndex(-1)
342 SvFileStream rIStm(rPath, StreamMode::STD_READ);
343 if(rIStm.GetError())
344 return;
345 const sal_uInt32 nStmLen(rIStm.remainingSize());
346 if (nStmLen)
348 BinaryDataContainer aData(rIStm, nStmLen);
350 if (!rIStm.GetError())
352 maDataContainer = std::move(aData);
357 VectorGraphicData::~VectorGraphicData()
361 const basegfx::B2DRange& VectorGraphicData::getRange() const
363 const_cast< VectorGraphicData* >(this)->ensureSequenceAndRange();
365 return maRange;
368 const std::deque< css::uno::Reference< css::graphic::XPrimitive2D > >& VectorGraphicData::getPrimitive2DSequence() const
370 const_cast< VectorGraphicData* >(this)->ensureSequenceAndRange();
372 return maSequence;
375 const BitmapEx& VectorGraphicData::getReplacement() const
377 const_cast< VectorGraphicData* >(this)->ensureReplacement();
379 return maReplacement;
382 BitmapChecksum VectorGraphicData::GetChecksum() const
384 return rtl_crc32(0, maDataContainer.getData(), maDataContainer.getSize());
387 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */