LibreOffice Module vcl (master) 1
vectorgraphicdata.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
21#include <tools/stream.hxx>
22#include <sal/log.hxx>
23#include <utility>
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>
35#include <vcl/canvastools.hxx>
40#include <vcl/svapp.hxx>
41#include <vcl/outdev.hxx>
42#include <vcl/wmfexternal.hxx>
43#include <vcl/pdfread.hxx>
46
47using namespace ::com::sun::star;
48
50 const std::deque< css::uno::Reference< css::graphic::XPrimitive2D > >& rSequence,
51 const basegfx::B2DRange& rTargetRange,
52 const sal_uInt32 nMaximumQuadraticPixels,
53 const o3tl::Length eTargetUnit,
54 const std::optional<Size>& rTargetDPI)
55{
56 BitmapEx aRetval;
57
58 if(!rSequence.empty())
59 {
60 // create replacement graphic from maSequence
61 // create XPrimitive2DRenderer
62 try
63 {
64 uno::Reference< uno::XComponentContext > xContext(::comphelper::getProcessComponentContext());
65 const uno::Reference< graphic::XPrimitive2DRenderer > xPrimitive2DRenderer = graphic::Primitive2DTools::create(xContext);
66
67 uno::Sequence< beans::PropertyValue > aViewParameters = {
68 comphelper::makePropertyValue("RangeUnit", static_cast<sal_Int32>(eTargetUnit)),
69 };
70 geometry::RealRectangle2D aRealRect;
71
72 aRealRect.X1 = rTargetRange.getMinX();
73 aRealRect.Y1 = rTargetRange.getMinY();
74 aRealRect.X2 = rTargetRange.getMaxX();
75 aRealRect.Y2 = rTargetRange.getMaxY();
76
77 // get system DPI
78 Size aDPI(Application::GetDefaultDevice()->LogicToPixel(Size(1, 1), MapMode(MapUnit::MapInch)));
79 if (rTargetDPI.has_value())
80 {
81 aDPI = *rTargetDPI;
82 }
83
84 const uno::Reference< rendering::XBitmap > xBitmap(
85 xPrimitive2DRenderer->rasterize(
87 aViewParameters,
88 aDPI.getWidth(),
89 aDPI.getHeight(),
90 aRealRect,
91 nMaximumQuadraticPixels));
92
93 if(xBitmap.is())
94 {
95 const uno::Reference< rendering::XIntegerReadOnlyBitmap> xIntBmp(xBitmap, uno::UNO_QUERY_THROW);
96 aRetval = vcl::unotools::bitmapExFromXBitmap(xIntBmp);
97 }
98 }
99 catch (const uno::Exception&)
100 {
101 TOOLS_WARN_EXCEPTION("vcl", "Got no graphic::XPrimitive2DRenderer!");
102 }
103 catch (const std::exception& e)
104 {
105 SAL_WARN("vcl", "Got no graphic::XPrimitive2DRenderer! : " << e.what());
106 }
107 }
108
109 return aRetval;
110}
111
112static size_t estimateSize(
113 std::deque<uno::Reference<graphic::XPrimitive2D>> const& rSequence)
114{
115 size_t nRet(0);
116 for (auto& it : rSequence)
117 {
118 uno::Reference<util::XAccounting> const xAcc(it, uno::UNO_QUERY);
119 assert(xAcc.is()); // we expect only BasePrimitive2D from SVG parser
120 nRet += xAcc->estimateUsage();
121 }
122 return nRet;
123}
124
126{
127 if (getType() == rCandidate.getType())
128 {
129 if (maDataContainer.getSize() == rCandidate.maDataContainer.getSize())
130 {
131 if (0 == memcmp(
133 rCandidate.maDataContainer.getData(),
135 {
136 return true;
137 }
138 }
139 }
140
141 return false;
142}
143
145{
147
148 if (!maReplacement.IsEmpty())
149 return; // nothing to do
150
151 // use PDFium directly
152 std::vector<BitmapEx> aBitmaps;
153 sal_Int32 nUsePageIndex = 0;
154 if (mnPageIndex >= 0)
155 nUsePageIndex = mnPageIndex;
157 maDataContainer.getSize(), aBitmaps, nUsePageIndex, 1,
158 &maSizeHint);
159 if (!aBitmaps.empty())
160 maReplacement = aBitmaps[0];
161}
162
164{
165 if (!maReplacement.IsEmpty())
166 return; // nothing to do
167
168 // shortcut for PDF - PDFium can generate the replacement bitmap for us
169 // directly
171 {
173 return;
174 }
175
177
178 if (!maSequence.empty())
179 {
181 }
182}
183
185{
187 return;
188
189 // import SVG to maSequence, also set maRange
190 maRange.reset();
191
192 // create Vector Graphic Data interpreter
193 uno::Reference<uno::XComponentContext> xContext(::comphelper::getProcessComponentContext());
194
195 switch (getType())
196 {
198 {
199 const uno::Reference<io::XInputStream> xInputStream = maDataContainer.getAsXInputStream();
200
201 const uno::Reference< graphic::XSvgParser > xSvgParser = graphic::SvgTools::create(xContext);
202
203 if (xInputStream.is())
204 maSequence = comphelper::sequenceToContainer<std::deque<css::uno::Reference< css::graphic::XPrimitive2D >>>(xSvgParser->getDecomposition(xInputStream, OUString()));
205
206 break;
207 }
210 {
211 const uno::Reference< graphic::XEmfParser > xEmfParser = graphic::EmfTools::create(xContext);
212
213 const uno::Reference<io::XInputStream> xInputStream = maDataContainer.getAsXInputStream();
214
215 if (xInputStream.is())
216 {
217 uno::Sequence< ::beans::PropertyValue > aPropertySequence;
218
219 // Pass the size hint of the graphic to the EMF parser.
220 geometry::RealPoint2D aSizeHint;
221 aSizeHint.X = maSizeHint.getX();
222 aSizeHint.Y = maSizeHint.getY();
223 xEmfParser->setSizeHint(aSizeHint);
224
225 if (!mbEnableEMFPlus)
226 {
227 aPropertySequence = { comphelper::makePropertyValue("EMFPlusEnable", uno::Any(false)) };
228 }
229
230 maSequence = comphelper::sequenceToContainer<std::deque<css::uno::Reference< css::graphic::XPrimitive2D >>>(xEmfParser->getDecomposition(xInputStream, OUString(), aPropertySequence));
231 }
232
233 break;
234 }
236 {
237 const uno::Reference<graphic::XPdfDecomposer> xPdfDecomposer = graphic::PdfTools::create(xContext);
238 uno::Sequence<beans::PropertyValue> aDecompositionParameters = comphelper::InitPropertySequence({
239 {"PageIndex", uno::Any(sal_Int32(mnPageIndex))},
240 });
241
243
244 auto xPrimitive2D = xPdfDecomposer->getDecomposition(xDataContainer, aDecompositionParameters);
245 maSequence = comphelper::sequenceToContainer<std::deque<uno::Reference<graphic::XPrimitive2D>>>(xPrimitive2D);
246
247 break;
248 }
249 }
250
251 if(!maSequence.empty())
252 {
253 const sal_Int32 nCount(maSequence.size());
254 geometry::RealRectangle2D aRealRect;
255 uno::Sequence< beans::PropertyValue > aViewParameters;
256
257 for(sal_Int32 a(0); a < nCount; a++)
258 {
259 // get reference
260 const css::uno::Reference< css::graphic::XPrimitive2D > xReference(maSequence[a]);
261
262 if(xReference.is())
263 {
264 aRealRect = xReference->getRange(aViewParameters);
265
268 aRealRect.X1,
269 aRealRect.Y1,
270 aRealRect.X2,
271 aRealRect.Y2));
272 }
273 }
274 }
276 mbSequenceCreated = true;
277}
278
279std::pair<VectorGraphicData::State, size_t> VectorGraphicData::getSizeBytes() const
280{
281 if (!maSequence.empty() && !maDataContainer.isEmpty())
282 {
283 return std::make_pair(State::PARSED, maDataContainer.getSize() + mNestedBitmapSize);
284 }
285 else
286 {
287 return std::make_pair(State::UNPARSED, maDataContainer.getSize());
288 }
289}
290
292 BinaryDataContainer aDataContainer,
293 VectorGraphicDataType eVectorDataType,
294 sal_Int32 nPageIndex)
295: maDataContainer(std::move(aDataContainer)),
296 mbSequenceCreated(false),
297 mNestedBitmapSize(0),
298 meType(eVectorDataType),
299 mnPageIndex(nPageIndex)
300{
301}
302
304 const OUString& rPath,
305 VectorGraphicDataType eVectorDataType)
306: mbSequenceCreated(false),
307 mNestedBitmapSize(0),
308 meType(eVectorDataType),
309 mnPageIndex(-1)
310{
311 SvFileStream rIStm(rPath, StreamMode::STD_READ);
312 if(rIStm.GetError())
313 return;
314 const sal_uInt32 nStmLen(rIStm.remainingSize());
315 if (nStmLen)
316 {
317 BinaryDataContainer aData(rIStm, nStmLen);
318
319 if (!rIStm.GetError())
320 {
322 }
323 }
324}
325
327{
328}
329
331{
332 const_cast< VectorGraphicData* >(this)->ensureSequenceAndRange();
333
334 return maRange;
335}
336
337const std::deque< css::uno::Reference< css::graphic::XPrimitive2D > >& VectorGraphicData::getPrimitive2DSequence() const
338{
339 const_cast< VectorGraphicData* >(this)->ensureSequenceAndRange();
340
341 return maSequence;
342}
343
345{
346 const_cast< VectorGraphicData* >(this)->ensureReplacement();
347
348 return maReplacement;
349}
350
352{
354}
355
356/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_uInt64 BitmapChecksum
Definition: checksum.hxx:30
BitmapChecksum vcl_get_checksum(BitmapChecksum Checksum, const void *Data, sal_uInt32 DatLen)
Definition: checksum.hxx:72
static OutputDevice * GetDefaultDevice()
Get the default "device" (in this case the default window).
Definition: svapp.cxx:1043
Container for the binary data, whose responsibility is to manage the make it as simple as possible to...
css::uno::Reference< css::io::XInputStream > getAsXInputStream()
const sal_uInt8 * getData() const
bool IsEmpty() const
Definition: BitmapEx.cxx:186
constexpr tools::Long getHeight() const
constexpr tools::Long getWidth() const
ErrCode GetError() const
sal_uInt64 remainingSize()
const std::deque< css::uno::Reference< css::graphic::XPrimitive2D > > & getPrimitive2DSequence() const
bool operator==(const VectorGraphicData &rCandidate) const
compare op
BitmapChecksum GetChecksum() const
std::deque< css::uno::Reference< css::graphic::XPrimitive2D > > maSequence
const BitmapEx & getReplacement() const
VectorGraphicData(const VectorGraphicData &)=delete
const basegfx::B2DRange & getRange() const
data read and evtl. on demand creation
BinaryDataContainer maDataContainer
basegfx::B2DRange maRange
basegfx::B2DTuple maSizeHint
Useful for PDF, which is vector-based, but still rendered to a bitmap.
std::pair< State, size_t > getSizeBytes() const
sal_Int32 mnPageIndex
If the vector format has more pages this denotes which page to render.
const VectorGraphicDataType & getType() const
const BinaryDataContainer & getBinaryDataContainer() const
data read
TYPE getMaxX() const
TYPE getMinX() const
TYPE getMinY() const
void expand(const Tuple2D< TYPE > &rTuple)
TYPE getMaxY() const
TYPE getX() const
TYPE getY() const
int nCount
#define TOOLS_WARN_EXCEPTION(area, stream)
uno_Any a
#define SAL_WARN(area, stream)
constexpr OUStringLiteral aData
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
css::uno::Sequence< css::beans::PropertyValue > InitPropertySequence(::std::initializer_list< ::std::pair< OUString, css::uno::Any > > vInit)
css::beans::PropertyValue makePropertyValue(const OUString &rName, T &&rValue)
::BitmapEx bitmapExFromXBitmap(const uno::Reference< rendering::XIntegerReadOnlyBitmap > &xInputBitmap)
size_t RenderPDFBitmaps(const void *pBuffer, int nSize, std::vector< BitmapEx > &rBitmaps, const size_t nFirstPage, int nPages, const basegfx::B2DTuple *pSizeHint)
Fills the rBitmaps vector with rendered pages.
Definition: pdfread.cxx:26
BitmapEx convertPrimitive2DSequenceToBitmapEx(const std::deque< css::uno::Reference< css::graphic::XPrimitive2D > > &rSequence, const basegfx::B2DRange &rTargetRange, const sal_uInt32 nMaximumQuadraticPixels, const o3tl::Length eTargetUnit, const std::optional< Size > &rTargetDPI)
static size_t estimateSize(std::deque< uno::Reference< graphic::XPrimitive2D > > const &rSequence)
VectorGraphicDataType
RedlineType meType