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 css::uno::Sequence<sal_Int8> aDataSequence(maDataContainer.getSize());
200 std::copy(maDataContainer.cbegin(), maDataContainer.cend(), aDataSequence.getArray());
201 const uno::Reference<io::XInputStream> xInputStream(new comphelper::SequenceInputStream(aDataSequence));
202
203
204 const uno::Reference< graphic::XSvgParser > xSvgParser = graphic::SvgTools::create(xContext);
205
206 if (xInputStream.is())
207 maSequence = comphelper::sequenceToContainer<std::deque<css::uno::Reference< css::graphic::XPrimitive2D >>>(xSvgParser->getDecomposition(xInputStream, OUString()));
208
209 break;
210 }
213 {
214 const uno::Reference< graphic::XEmfParser > xEmfParser = graphic::EmfTools::create(xContext);
215
216 css::uno::Sequence<sal_Int8> aDataSequence(maDataContainer.getSize());
217 std::copy(maDataContainer.cbegin(), maDataContainer.cend(), aDataSequence.getArray());
218 const uno::Reference<io::XInputStream> xInputStream(new comphelper::SequenceInputStream(aDataSequence));
219
220 if (xInputStream.is())
221 {
222 uno::Sequence< ::beans::PropertyValue > aPropertySequence;
223
224 // Pass the size hint of the graphic to the EMF parser.
225 geometry::RealPoint2D aSizeHint;
226 aSizeHint.X = maSizeHint.getX();
227 aSizeHint.Y = maSizeHint.getY();
228 xEmfParser->setSizeHint(aSizeHint);
229
230 if (!mbEnableEMFPlus)
231 {
232 aPropertySequence = { comphelper::makePropertyValue("EMFPlusEnable", uno::Any(false)) };
233 }
234
235 maSequence = comphelper::sequenceToContainer<std::deque<css::uno::Reference< css::graphic::XPrimitive2D >>>(xEmfParser->getDecomposition(xInputStream, OUString(), aPropertySequence));
236 }
237
238 break;
239 }
241 {
242 const uno::Reference<graphic::XPdfDecomposer> xPdfDecomposer = graphic::PdfTools::create(xContext);
243 uno::Sequence<beans::PropertyValue> aDecompositionParameters = comphelper::InitPropertySequence({
244 {"PageIndex", uno::Any(sal_Int32(mnPageIndex))},
245 });
246
248
249 auto xPrimitive2D = xPdfDecomposer->getDecomposition(xDataContainer, aDecompositionParameters);
250 maSequence = comphelper::sequenceToContainer<std::deque<uno::Reference<graphic::XPrimitive2D>>>(xPrimitive2D);
251
252 break;
253 }
254 }
255
256 if(!maSequence.empty())
257 {
258 const sal_Int32 nCount(maSequence.size());
259 geometry::RealRectangle2D aRealRect;
260 uno::Sequence< beans::PropertyValue > aViewParameters;
261
262 for(sal_Int32 a(0); a < nCount; a++)
263 {
264 // get reference
265 const css::uno::Reference< css::graphic::XPrimitive2D > xReference(maSequence[a]);
266
267 if(xReference.is())
268 {
269 aRealRect = xReference->getRange(aViewParameters);
270
273 aRealRect.X1,
274 aRealRect.Y1,
275 aRealRect.X2,
276 aRealRect.Y2));
277 }
278 }
279 }
281 mbSequenceCreated = true;
282}
283
284std::pair<VectorGraphicData::State, size_t> VectorGraphicData::getSizeBytes() const
285{
286 if (!maSequence.empty() && !maDataContainer.isEmpty())
287 {
288 return std::make_pair(State::PARSED, maDataContainer.getSize() + mNestedBitmapSize);
289 }
290 else
291 {
292 return std::make_pair(State::UNPARSED, maDataContainer.getSize());
293 }
294}
295
297 BinaryDataContainer aDataContainer,
298 VectorGraphicDataType eVectorDataType,
299 sal_Int32 nPageIndex)
300: maDataContainer(std::move(aDataContainer)),
301 mbSequenceCreated(false),
302 mNestedBitmapSize(0),
303 meType(eVectorDataType),
304 mnPageIndex(nPageIndex)
305{
306}
307
309 const OUString& rPath,
310 VectorGraphicDataType eVectorDataType)
311: mbSequenceCreated(false),
312 mNestedBitmapSize(0),
313 meType(eVectorDataType),
314 mnPageIndex(-1)
315{
316 SvFileStream rIStm(rPath, StreamMode::STD_READ);
317 if(rIStm.GetError())
318 return;
319 const sal_uInt32 nStmLen(rIStm.remainingSize());
320 if (nStmLen)
321 {
322 VectorGraphicDataArray aVectorGraphicDataArray(nStmLen);
323 auto pData = aVectorGraphicDataArray.getArray();
324 rIStm.ReadBytes(pData, nStmLen);
325
326 if (!rIStm.GetError())
327 {
328 maDataContainer = BinaryDataContainer(reinterpret_cast<const sal_uInt8*>(pData), nStmLen);
329 }
330 }
331}
332
334{
335}
336
338{
339 const_cast< VectorGraphicData* >(this)->ensureSequenceAndRange();
340
341 return maRange;
342}
343
344const std::deque< css::uno::Reference< css::graphic::XPrimitive2D > >& VectorGraphicData::getPrimitive2DSequence() const
345{
346 const_cast< VectorGraphicData* >(this)->ensureSequenceAndRange();
347
348 return maSequence;
349}
350
352{
353 const_cast< VectorGraphicData* >(this)->ensureReplacement();
354
355 return maReplacement;
356}
357
359{
361}
362
363/* 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:1166
Container for the binary data, whose responsibility is to manage the make it as simple as possible to...
const sal_uInt8 * getData() const
bool IsEmpty() const
Definition: BitmapEx.cxx:177
constexpr tools::Long getHeight() const
constexpr tools::Long getWidth() const
std::size_t ReadBytes(void *pData, std::size_t nSize)
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)
std::unique_ptr< sal_Int32[]> pData
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:121
unsigned char sal_uInt8
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)
css::uno::Sequence< sal_Int8 > VectorGraphicDataArray
VectorGraphicDataType
RedlineType meType