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 
20 #include <tools/diagnose_ex.h>
21 #include <tools/stream.hxx>
22 #include <sal/log.hxx>
25 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
26 #include <com/sun/star/graphic/PdfTools.hpp>
27 #include <com/sun/star/graphic/SvgTools.hpp>
28 #include <com/sun/star/graphic/EmfTools.hpp>
29 #include <com/sun/star/graphic/Primitive2DTools.hpp>
30 #include <com/sun/star/rendering/XIntegerReadOnlyBitmap.hpp>
31 #include <com/sun/star/util/XAccounting.hpp>
32 #include <com/sun/star/util/XBinaryDataContainer.hpp>
34 #include <vcl/canvastools.hxx>
35 #include <comphelper/seqstream.hxx>
36 #include <comphelper/sequence.hxx>
39 #include <vcl/svapp.hxx>
40 #include <vcl/outdev.hxx>
41 #include <vcl/wmfexternal.hxx>
42 #include <vcl/pdfread.hxx>
43 #include <unotools/streamwrap.hxx>
45 
46 using namespace ::com::sun::star;
47 
49  const std::deque< css::uno::Reference< css::graphic::XPrimitive2D > >& rSequence,
50  const basegfx::B2DRange& rTargetRange,
51  const sal_uInt32 nMaximumQuadraticPixels)
52 {
53  BitmapEx aRetval;
54 
55  if(!rSequence.empty())
56  {
57  // create replacement graphic from maSequence
58  // create XPrimitive2DRenderer
59  try
60  {
61  uno::Reference< uno::XComponentContext > xContext(::comphelper::getProcessComponentContext());
62  const uno::Reference< graphic::XPrimitive2DRenderer > xPrimitive2DRenderer = graphic::Primitive2DTools::create(xContext);
63 
64  uno::Sequence< beans::PropertyValue > aViewParameters;
65  geometry::RealRectangle2D aRealRect;
66 
67  aRealRect.X1 = rTargetRange.getMinX();
68  aRealRect.Y1 = rTargetRange.getMinY();
69  aRealRect.X2 = rTargetRange.getMaxX();
70  aRealRect.Y2 = rTargetRange.getMaxY();
71 
72  // get system DPI
73  const Size aDPI(Application::GetDefaultDevice()->LogicToPixel(Size(1, 1), MapMode(MapUnit::MapInch)));
74 
75  const uno::Reference< rendering::XBitmap > xBitmap(
76  xPrimitive2DRenderer->rasterize(
78  aViewParameters,
79  aDPI.getWidth(),
80  aDPI.getHeight(),
81  aRealRect,
82  nMaximumQuadraticPixels));
83 
84  if(xBitmap.is())
85  {
86  const uno::Reference< rendering::XIntegerReadOnlyBitmap> xIntBmp(xBitmap, uno::UNO_QUERY_THROW);
87  aRetval = vcl::unotools::bitmapExFromXBitmap(xIntBmp);
88  }
89  }
90  catch (const uno::Exception&)
91  {
92  TOOLS_WARN_EXCEPTION("vcl", "Got no graphic::XPrimitive2DRenderer!");
93  }
94  catch (const std::exception& e)
95  {
96  SAL_WARN("vcl", "Got no graphic::XPrimitive2DRenderer! : " << e.what());
97  }
98  }
99 
100  return aRetval;
101 }
102 
103 static size_t estimateSize(
104  std::deque<uno::Reference<graphic::XPrimitive2D>> const& rSequence)
105 {
106  size_t nRet(0);
107  for (auto& it : rSequence)
108  {
109  uno::Reference<util::XAccounting> const xAcc(it, uno::UNO_QUERY);
110  assert(xAcc.is()); // we expect only BasePrimitive2D from SVG parser
111  nRet += xAcc->estimateUsage();
112  }
113  return nRet;
114 }
115 
117 {
118  if (getType() == rCandidate.getType())
119  {
120  if (maDataContainer.getSize() == rCandidate.maDataContainer.getSize())
121  {
122  if (0 == memcmp(
124  rCandidate.maDataContainer.getData(),
126  {
127  return true;
128  }
129  }
130  }
131 
132  return false;
133 }
134 
136 {
137  if (!mpExternalHeader)
138  {
139  mpExternalHeader.reset( new WmfExternal );
140  }
141 
142  *mpExternalHeader = aExtHeader;
143 }
144 
146 {
148 
149  if (!maReplacement.IsEmpty())
150  return; // nothing to do
151 
152  // use PDFium directly
153  std::vector<BitmapEx> aBitmaps;
154  sal_Int32 nUsePageIndex = 0;
155  if (mnPageIndex >= 0)
156  nUsePageIndex = mnPageIndex;
158  maDataContainer.getSize(), aBitmaps, nUsePageIndex, 1,
159  &maSizeHint);
160  if (!aBitmaps.empty())
161  maReplacement = aBitmaps[0];
162 }
163 
165 {
166  if (!maReplacement.IsEmpty())
167  return; // nothing to do
168 
169  // shortcut for PDF - PDFium can generate the replacement bitmap for us
170  // directly
172  {
174  return;
175  }
176 
178 
179  if (!maSequence.empty())
180  {
182  }
183 }
184 
186 {
188  return;
189 
190  // import SVG to maSequence, also set maRange
191  maRange.reset();
192 
193  // create Vector Graphic Data interpreter
194  uno::Reference<uno::XComponentContext> xContext(::comphelper::getProcessComponentContext());
195 
196  switch (getType())
197  {
199  {
200  css::uno::Sequence<sal_Int8> aDataSequence(maDataContainer.getSize());
201  std::copy(maDataContainer.cbegin(), maDataContainer.cend(), aDataSequence.begin());
202  const uno::Reference<io::XInputStream> xInputStream(new comphelper::SequenceInputStream(aDataSequence));
203 
204 
205  const uno::Reference< graphic::XSvgParser > xSvgParser = graphic::SvgTools::create(xContext);
206 
207  if (xInputStream.is())
208  maSequence = comphelper::sequenceToContainer<std::deque<css::uno::Reference< css::graphic::XPrimitive2D >>>(xSvgParser->getDecomposition(xInputStream, OUString()));
209 
210  break;
211  }
214  {
215  const uno::Reference< graphic::XEmfParser > xEmfParser = graphic::EmfTools::create(xContext);
216 
217  css::uno::Sequence<sal_Int8> aDataSequence(maDataContainer.getSize());
218  std::copy(maDataContainer.cbegin(), maDataContainer.cend(), aDataSequence.begin());
219  const uno::Reference<io::XInputStream> xInputStream(new comphelper::SequenceInputStream(aDataSequence));
220 
221  uno::Sequence< ::beans::PropertyValue > aPropertySequence;
222 
223  if (mpExternalHeader)
224  {
225  aPropertySequence = mpExternalHeader->getSequence();
226  }
227 
228  if (xInputStream.is())
229  {
230  // Pass the size hint of the graphic to the EMF parser.
231  geometry::RealPoint2D aSizeHint;
232  aSizeHint.X = maSizeHint.getX();
233  aSizeHint.Y = maSizeHint.getY();
234  xEmfParser->setSizeHint(aSizeHint);
235 
236  if (!mbEnableEMFPlus)
237  {
238  auto aVector = comphelper::sequenceToContainer<std::vector<beans::PropertyValue>>(aPropertySequence);
239  aVector.push_back(comphelper::makePropertyValue("EMFPlusEnable", uno::makeAny(false)));
240  aPropertySequence = comphelper::containerToSequence(aVector);
241  }
242 
243  maSequence = comphelper::sequenceToContainer<std::deque<css::uno::Reference< css::graphic::XPrimitive2D >>>(xEmfParser->getDecomposition(xInputStream, OUString(), aPropertySequence));
244  }
245 
246  break;
247  }
249  {
250  const uno::Reference<graphic::XPdfDecomposer> xPdfDecomposer = graphic::PdfTools::create(xContext);
251  uno::Sequence<beans::PropertyValue> aDecompositionParameters = comphelper::InitPropertySequence({
252  {"PageIndex", uno::makeAny<sal_Int32>(mnPageIndex)},
253  });
254 
256 
257  auto xPrimitive2D = xPdfDecomposer->getDecomposition(xDataContainer, aDecompositionParameters);
258  maSequence = comphelper::sequenceToContainer<std::deque<uno::Reference<graphic::XPrimitive2D>>>(xPrimitive2D);
259 
260  break;
261  }
262  }
263 
264  if(!maSequence.empty())
265  {
266  const sal_Int32 nCount(maSequence.size());
267  geometry::RealRectangle2D aRealRect;
268  uno::Sequence< beans::PropertyValue > aViewParameters;
269 
270  for(sal_Int32 a(0); a < nCount; a++)
271  {
272  // get reference
273  const css::uno::Reference< css::graphic::XPrimitive2D > xReference(maSequence[a]);
274 
275  if(xReference.is())
276  {
277  aRealRect = xReference->getRange(aViewParameters);
278 
279  maRange.expand(
281  aRealRect.X1,
282  aRealRect.Y1,
283  aRealRect.X2,
284  aRealRect.Y2));
285  }
286  }
287  }
289  mbSequenceCreated = true;
290 }
291 
292 std::pair<VectorGraphicData::State, size_t> VectorGraphicData::getSizeBytes() const
293 {
294  if (!maSequence.empty() && !maDataContainer.isEmpty())
295  {
296  return std::make_pair(State::PARSED, maDataContainer.getSize() + mNestedBitmapSize);
297  }
298  else
299  {
300  return std::make_pair(State::UNPARSED, maDataContainer.getSize());
301  }
302 }
303 
305  const BinaryDataContainer& rDataContainer,
306  VectorGraphicDataType eVectorDataType,
307  sal_Int32 nPageIndex)
308 : maDataContainer(rDataContainer),
309  mbSequenceCreated(false),
310  maRange(),
311  maSequence(),
312  maReplacement(),
314  meType(eVectorDataType),
315  mnPageIndex(nPageIndex)
316 {
317 }
318 
320  const OUString& rPath,
321  VectorGraphicDataType eVectorDataType)
322 : mbSequenceCreated(false),
323  maRange(),
324  maSequence(),
325  maReplacement(),
326  mNestedBitmapSize(0),
327  meType(eVectorDataType),
328  mnPageIndex(-1)
329 {
330  SvFileStream rIStm(rPath, StreamMode::STD_READ);
331  if(rIStm.GetError())
332  return;
333  const sal_uInt32 nStmLen(rIStm.remainingSize());
334  if (nStmLen)
335  {
336  VectorGraphicDataArray aVectorGraphicDataArray(nStmLen);
337  rIStm.ReadBytes(aVectorGraphicDataArray.begin(), nStmLen);
338 
339  if (!rIStm.GetError())
340  {
341  maDataContainer = BinaryDataContainer(reinterpret_cast<const sal_uInt8*>(aVectorGraphicDataArray.begin()), aVectorGraphicDataArray.getLength());
342  }
343  }
344 }
345 
347 {
348 }
349 
351 {
352  const_cast< VectorGraphicData* >(this)->ensureSequenceAndRange();
353 
354  return maRange;
355 }
356 
357 const std::deque< css::uno::Reference< css::graphic::XPrimitive2D > >& VectorGraphicData::getPrimitive2DSequence() const
358 {
359  const_cast< VectorGraphicData* >(this)->ensureSequenceAndRange();
360 
361  return maSequence;
362 }
363 
365 {
366  const_cast< VectorGraphicData* >(this)->ensureReplacement();
367 
368  return maReplacement;
369 }
370 
372 {
374 }
375 
376 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const BitmapEx & getReplacement() const
VectorGraphicDataType
sal_uInt64 BitmapChecksum
Definition: checksum.hxx:30
void expand(const B2DTuple &rTuple)
sal_Int32 mnPageIndex
If the vector format has more pages this denotes which page to render.
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:135
const std::deque< css::uno::Reference< css::graphic::XPrimitive2D > > & getPrimitive2DSequence() const
basegfx::B2DTuple maSizeHint
Useful for PDF, which is vector-based, but still rendered to a bitmap.
double getX() const
double getY() const
BitmapChecksum vcl_get_checksum(BitmapChecksum Checksum, const void *Data, sal_uInt32 DatLen)
Definition: checksum.hxx:72
const basegfx::B2DRange & getRange() const
data read and evtl. on demand creation
void setWmfExternalHeader(const WmfExternal &aExtHeader)
special: needed for emf/wmf, maybe replaced by scaling the result later (?)
const BinaryDataContainer & getBinaryDataContainer() const
data read
::BitmapEx bitmapExFromXBitmap(const uno::Reference< rendering::XIntegerReadOnlyBitmap > &xInputBitmap)
double getMaxX() const
static OutputDevice * GetDefaultDevice()
Get the default "device" (in this case the default window).
Definition: svapp.cxx:1073
DstType sequenceToContainer(const css::uno::Sequence< SrcType > &i_Sequence)
ErrCode GetError() const
Container for the binary data, whose responsibility is to manage the make it as simple as possible to...
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
int nCount
BitmapChecksum GetChecksum() const
constexpr tools::Long getHeight() const
sal_uInt64 remainingSize()
double getMaxY() const
css::uno::Sequence< css::beans::PropertyValue > InitPropertySequence(::std::initializer_list< ::std::pair< OUString, css::uno::Any > > vInit)
basegfx::B2DRange maRange
std::pair< State, size_t > getSizeBytes() const
bool IsEmpty() const
Definition: BitmapEx.cxx:196
#define TOOLS_WARN_EXCEPTION(area, stream)
uno_Any a
bool operator==(const VectorGraphicData &rCandidate) const
compare op
const sal_uInt8 * getData() const
std::size_t ReadBytes(void *pData, std::size_t nSize)
css::uno::Sequence< sal_Int8 > VectorGraphicDataArray
std::unique_ptr< WmfExternal > mpExternalHeader
double getMinY() const
static size_t estimateSize(std::deque< uno::Reference< graphic::XPrimitive2D >> const &rSequence)
css::beans::PropertyValue makePropertyValue(const OUString &rName, T &&rValue)
VectorGraphicDataType meType
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
VectorGraphicData(const VectorGraphicData &)=delete
Reference< XComponentContext > getProcessComponentContext()
BitmapEx convertPrimitive2DSequenceToBitmapEx(const std::deque< css::uno::Reference< css::graphic::XPrimitive2D > > &rSequence, const basegfx::B2DRange &rTargetRange, const sal_uInt32 nMaximumQuadraticPixels)
#define SAL_WARN(area, stream)
const VectorGraphicDataType & getType() const
double getMinX() const
constexpr tools::Long getWidth() const
std::deque< css::uno::Reference< css::graphic::XPrimitive2D > > maSequence
RedlineType meType
B2DRange maRange
BinaryDataContainer maDataContainer