LibreOffice Module vcl (master) 1
GraphicObject.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 <sal/config.h>
21
22#include <algorithm>
23
24#include <o3tl/string_view.hxx>
25#include <osl/diagnose.h>
26#include <tools/fract.hxx>
27#include <tools/helpers.hxx>
28#include <utility>
29#include <vcl/svapp.hxx>
30#include <vcl/metaact.hxx>
31#include <vcl/GraphicObject.hxx>
32#include <vcl/GraphicLoader.hxx>
33#include <vcl/outdev.hxx>
34
35#include <com/sun/star/container/XNameContainer.hpp>
36#include <com/sun/star/beans/XPropertySet.hpp>
37#include <com/sun/star/graphic/XGraphic.hpp>
38#include <memory>
39
40
41using namespace css;
43using com::sun::star::uno::XInterface;
44using com::sun::star::uno::UNO_QUERY;
46using com::sun::star::container::XNameContainer;
48
49#define WATERMARK_LUM_OFFSET 50
50#define WATERMARK_CON_OFFSET -70
51
52namespace vcl::graphic
53{
54
55void SearchForGraphics(uno::Reference<uno::XInterface> const & xInterface,
56 std::vector<uno::Reference<css::graphic::XGraphic>> & raGraphicList)
57{
58 uno::Reference<beans::XPropertySet> xPropertySet(xInterface, UNO_QUERY);
59 if (xPropertySet.is())
60 {
61 if (xPropertySet->getPropertySetInfo()->hasPropertyByName("ImageURL"))
62 {
63 OUString sURL;
64 xPropertySet->getPropertyValue("ImageURL") >>= sURL;
65 if (!sURL.isEmpty() && !GraphicObject::isGraphicObjectUniqueIdURL(sURL))
66 {
67 Graphic aGraphic = vcl::graphic::loadFromURL(sURL);
68 if (!aGraphic.IsNone())
69 {
70 raGraphicList.push_back(aGraphic.GetXGraphic());
71 }
72 }
73 } else if (xPropertySet->getPropertySetInfo()->hasPropertyByName("Graphic"))
74 {
75 uno::Reference<css::graphic::XGraphic> xGraphic;
76 xPropertySet->getPropertyValue("Graphic") >>= xGraphic;
77 if (xGraphic.is())
78 {
79 raGraphicList.push_back(xGraphic);
80 }
81 }
82 }
83 Reference<XNameContainer> xContainer(xInterface, UNO_QUERY);
84 if (xContainer.is())
85 {
86 const css::uno::Sequence<OUString> aElementNames = xContainer->getElementNames();
87 for (OUString const & rName : aElementNames)
88 {
89 uno::Reference<XInterface> xInnerInterface;
90 xContainer->getByName(rName) >>= xInnerInterface;
91 SearchForGraphics(xInnerInterface, raGraphicList);
92 }
93 }
94}
95
96} // end namespace vcl::graphic
97
98namespace
99{
100
101bool lclDrawObj(OutputDevice& rOut, const Point& rPt, const Size& rSz,
102 GraphicObject const & rObj, const GraphicAttr& rAttr)
103{
104 Point aPt( rPt );
105 Size aSz( rSz );
106 bool bRet = false;
107
108 if( ( rObj.GetType() == GraphicType::Bitmap ) || ( rObj.GetType() == GraphicType::GdiMetafile ) )
109 {
110 // simple output of transformed graphic
111 const Graphic aGraphic( rObj.GetTransformedGraphic( &rAttr ) );
112
113 if( aGraphic.IsSupportedGraphic() )
114 {
115 const Degree10 nRot10 = rAttr.GetRotation() % 3600_deg10;
116
117 if( nRot10 )
118 {
119 tools::Polygon aPoly( tools::Rectangle( aPt, aSz ) );
120
121 aPoly.Rotate( aPt, nRot10 );
122 const tools::Rectangle aRotBoundRect( aPoly.GetBoundRect() );
123 aPt = aRotBoundRect.TopLeft();
124 aSz = aRotBoundRect.GetSize();
125 }
126
127 aGraphic.Draw(rOut, aPt, aSz);
128 }
129
130 bRet = true;
131 }
132
133 return bRet;
134}
135
136void lclImplAdjust( BitmapEx& rBmpEx, const GraphicAttr& rAttr, GraphicAdjustmentFlags nAdjustmentFlags )
137{
138 GraphicAttr aAttr( rAttr );
139
140 if( ( nAdjustmentFlags & GraphicAdjustmentFlags::DRAWMODE ) && aAttr.IsSpecialDrawMode() )
141 {
142 switch( aAttr.GetDrawMode() )
143 {
146 break;
147
150 break;
151
153 {
154 aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET );
155 aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET );
156 }
157 break;
158
159 default:
160 break;
161 }
162 }
163
164 if( ( nAdjustmentFlags & GraphicAdjustmentFlags::COLORS ) && aAttr.IsAdjusted() )
165 {
166 rBmpEx.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(),
167 aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(),
168 aAttr.GetGamma(), aAttr.IsInvert() );
169 }
170
171 if( ( nAdjustmentFlags & GraphicAdjustmentFlags::MIRROR ) && aAttr.IsMirrored() )
172 {
173 rBmpEx.Mirror( aAttr.GetMirrorFlags() );
174 }
175
176 if( ( nAdjustmentFlags & GraphicAdjustmentFlags::ROTATE ) && aAttr.IsRotated() )
177 {
178 rBmpEx.Rotate( aAttr.GetRotation(), COL_TRANSPARENT );
179 }
180
181 if( ( nAdjustmentFlags & GraphicAdjustmentFlags::TRANSPARENCY ) && aAttr.IsTransparent() )
182 {
183 rBmpEx.AdjustTransparency(255 - aAttr.GetAlpha());
184 }
185}
186
187void lclImplAdjust( GDIMetaFile& rMtf, const GraphicAttr& rAttr, GraphicAdjustmentFlags nAdjustmentFlags )
188{
189 GraphicAttr aAttr( rAttr );
190
191 if( ( nAdjustmentFlags & GraphicAdjustmentFlags::DRAWMODE ) && aAttr.IsSpecialDrawMode() )
192 {
193 switch( aAttr.GetDrawMode() )
194 {
197 break;
198
201 break;
202
204 {
205 aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET );
206 aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET );
207 }
208 break;
209
210 default:
211 break;
212 }
213 }
214
215 if( ( nAdjustmentFlags & GraphicAdjustmentFlags::COLORS ) && aAttr.IsAdjusted() )
216 {
217 rMtf.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(),
218 aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(),
219 aAttr.GetGamma(), aAttr.IsInvert() );
220 }
221
222 if( ( nAdjustmentFlags & GraphicAdjustmentFlags::MIRROR ) && aAttr.IsMirrored() )
223 {
224 rMtf.Mirror( aAttr.GetMirrorFlags() );
225 }
226
227 if( ( nAdjustmentFlags & GraphicAdjustmentFlags::ROTATE ) && aAttr.IsRotated() )
228 {
229 rMtf.Rotate( aAttr.GetRotation() );
230 }
231
232 if( ( nAdjustmentFlags & GraphicAdjustmentFlags::TRANSPARENCY ) && aAttr.IsTransparent() )
233 {
234 OSL_FAIL( "Missing implementation: Mtf-Transparency" );
235 }
236}
237
238void lclImplAdjust( Animation& rAnimation, const GraphicAttr& rAttr, GraphicAdjustmentFlags nAdjustmentFlags )
239{
240 GraphicAttr aAttr( rAttr );
241
242 if( ( nAdjustmentFlags & GraphicAdjustmentFlags::DRAWMODE ) && aAttr.IsSpecialDrawMode() )
243 {
244 switch( aAttr.GetDrawMode() )
245 {
248 break;
249
252 break;
253
255 {
256 aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET );
257 aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET );
258 }
259 break;
260
261 default:
262 break;
263 }
264 }
265
266 if( ( nAdjustmentFlags & GraphicAdjustmentFlags::COLORS ) && aAttr.IsAdjusted() )
267 {
268 rAnimation.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(),
269 aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(),
270 aAttr.GetGamma(), aAttr.IsInvert() );
271 }
272
273 if( ( nAdjustmentFlags & GraphicAdjustmentFlags::MIRROR ) && aAttr.IsMirrored() )
274 {
275 rAnimation.Mirror( aAttr.GetMirrorFlags() );
276 }
277
278 if( ( nAdjustmentFlags & GraphicAdjustmentFlags::ROTATE ) && aAttr.IsRotated() )
279 {
280 OSL_FAIL( "Missing implementation: Animation-Rotation" );
281 }
282
283 if( ( nAdjustmentFlags & GraphicAdjustmentFlags::TRANSPARENCY ) && aAttr.IsTransparent() )
284 {
285 OSL_FAIL( "Missing implementation: Animation-Transparency" );
286 }
287}
288
289} // end anonymous namespace
290
292{
295
296 GrfSimpleCacheObj( Graphic aGraphic, const GraphicAttr& rAttr ) :
297 maGraphic(std::move( aGraphic )), maAttr( rAttr ) {}
298};
299
301{
302}
303
305 : maGraphic(std::move(aGraphic))
306{
307}
308
310 : maGraphic(rGraphicObj.GetGraphic())
311 , maAttr(rGraphicObj.maAttr)
312 , maUserData(rGraphicObj.maUserData)
313{
314}
315
317{
318}
319
321{
322 return maGraphic.GetType();
323}
324
326{
327 return maGraphic.GetPrefSize();
328}
329
331{
332 return maGraphic.GetPrefMapMode();
333}
334
336{
337 return maGraphic.IsTransparent();
338}
339
341{
342 return maGraphic.IsAnimated();
343}
344
346{
347 return maGraphic.IsEPS();
348}
349
350bool GraphicObject::ImplGetCropParams(const OutputDevice& rOut, Point& rPt, Size& rSz, const GraphicAttr* pAttr,
351 tools::PolyPolygon& rClipPolyPoly, bool& bRectClipRegion) const
352{
353 bool bRet = false;
354
355 if( GetType() != GraphicType::NONE )
356 {
357 tools::Polygon aClipPoly( tools::Rectangle( rPt, rSz ) );
358 const Degree10 nRot10 = pAttr->GetRotation() % 3600_deg10;
359 const Point aOldOrigin( rPt );
360 const MapMode aMap100( MapUnit::Map100thMM );
361 Size aSize100;
362 tools::Long nTotalWidth, nTotalHeight;
363
364 if( nRot10 )
365 {
366 aClipPoly.Rotate( rPt, nRot10 );
367 bRectClipRegion = false;
368 }
369 else
370 bRectClipRegion = true;
371
372 rClipPolyPoly = tools::PolyPolygon(aClipPoly);
373
374 if (maGraphic.GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel)
376 else
377 {
379 aSize100 = rOut.LogicToLogic( maGraphic.GetPrefSize(), &m, &aMap100 );
380 }
381
382 nTotalWidth = aSize100.Width() - pAttr->GetLeftCrop() - pAttr->GetRightCrop();
383 nTotalHeight = aSize100.Height() - pAttr->GetTopCrop() - pAttr->GetBottomCrop();
384
385 if( !aSize100.IsEmpty() && nTotalWidth > 0 && nTotalHeight > 0 )
386 {
387 double fScale = static_cast<double>(aSize100.Width()) / nTotalWidth;
388 const tools::Long nNewLeft = -FRound( ( ( pAttr->GetMirrorFlags() & BmpMirrorFlags::Horizontal ) ? pAttr->GetRightCrop() : pAttr->GetLeftCrop() ) * fScale );
389 const tools::Long nNewRight = nNewLeft + FRound( aSize100.Width() * fScale ) - 1;
390
391 fScale = static_cast<double>(rSz.Width()) / aSize100.Width();
392 rPt.AdjustX(FRound( nNewLeft * fScale ) );
393 rSz.setWidth( FRound( ( nNewRight - nNewLeft + 1 ) * fScale ) );
394
395 fScale = static_cast<double>(aSize100.Height()) / nTotalHeight;
396 const tools::Long nNewTop = -FRound( ( ( pAttr->GetMirrorFlags() & BmpMirrorFlags::Vertical ) ? pAttr->GetBottomCrop() : pAttr->GetTopCrop() ) * fScale );
397 const tools::Long nNewBottom = nNewTop + FRound( aSize100.Height() * fScale ) - 1;
398
399 fScale = static_cast<double>(rSz.Height()) / aSize100.Height();
400 rPt.AdjustY(FRound( nNewTop * fScale ) );
401 rSz.setHeight( FRound( ( nNewBottom - nNewTop + 1 ) * fScale ) );
402
403 if( nRot10 )
404 {
405 tools::Polygon aOriginPoly( 1 );
406
407 aOriginPoly[ 0 ] = rPt;
408 aOriginPoly.Rotate( aOldOrigin, nRot10 );
409 rPt = aOriginPoly[ 0 ];
410 }
411
412 bRet = true;
413 }
414 }
415
416 return bRet;
417}
418
420{
421 if( &rGraphicObj != this )
422 {
423 mxSimpleCache.reset();
424 maGraphic = rGraphicObj.GetGraphic();
425 maAttr = rGraphicObj.maAttr;
426 maUserData = rGraphicObj.maUserData;
427 }
428
429 return *this;
430}
431
432bool GraphicObject::operator==( const GraphicObject& rGraphicObj ) const
433{
434 return rGraphicObj.maGraphic == maGraphic
435 && rGraphicObj.maAttr == maAttr;
436}
437
439{
440 return GetGraphic().getUniqueID();
441}
442
444{
445 maAttr = rAttr;
446
447 if (mxSimpleCache && (mxSimpleCache->maAttr != rAttr))
448 mxSimpleCache.reset();
449}
450
452{
453 maUserData.clear();
454}
455
456void GraphicObject::SetUserData( const OUString& rUserData )
457{
458 maUserData = rUserData;
459}
460
461bool GraphicObject::Draw(OutputDevice& rOut, const Point& rPt, const Size& rSz,
462 const GraphicAttr* pAttr) const
463{
464 GraphicAttr aAttr( pAttr ? *pAttr : GetAttr() );
465 Point aPt( rPt );
466 Size aSz( rSz );
467 const DrawModeFlags nOldDrawMode = rOut.GetDrawMode();
468 bool bCropped = aAttr.IsCropped();
469 bool bRet;
470
472
473 // mirrored horizontally
474 if( aSz.Width() < 0 )
475 {
476 aPt.AdjustX(aSz.Width() + 1 );
477 aSz.setWidth( -aSz.Width() );
479 }
480
481 // mirrored vertically
482 if( aSz.Height() < 0 )
483 {
484 aPt.AdjustY(aSz.Height() + 1 );
485 aSz.setHeight( -aSz.Height() );
487 }
488
489 if( bCropped )
490 {
491 tools::PolyPolygon aClipPolyPoly;
492 bool bRectClip;
493 const bool bCrop = ImplGetCropParams(rOut, aPt, aSz, &aAttr, aClipPolyPoly, bRectClip);
494
496
497 if( bCrop )
498 {
499 if( bRectClip )
500 {
501 // #i29534# Store crop rect for later forwarding to
502 // PDF writer
503 tools::Rectangle aCropRect = aClipPolyPoly.GetBoundRect();
504 rOut.IntersectClipRegion(aCropRect);
505 }
506 else
507 {
508 rOut.IntersectClipRegion(vcl::Region(aClipPolyPoly));
509 }
510 }
511 }
512
513 bRet = lclDrawObj(rOut, aPt, aSz, *this, aAttr);
514
515 if( bCropped )
516 rOut.Pop();
517
518 rOut.SetDrawMode( nOldDrawMode );
519
520 return bRet;
521}
522
523void GraphicObject::DrawTiled(OutputDevice& rOut, const tools::Rectangle& rArea, const Size& rSize,
524 const Size& rOffset, int nTileCacheSize1D)
525{
526 if (rSize.IsEmpty())
527 return;
528
529 const MapMode aOutMapMode(rOut.GetMapMode());
530 // #106258# Clamp size to 1 for zero values. This is okay, since
531 // logical size of zero is handled above already
532 const Size aOutTileSize( ::std::max( tools::Long(1), rOut.LogicToPixel( rSize, aOutMapMode ).Width() ),
533 ::std::max( tools::Long(1), rOut.LogicToPixel( rSize, aOutMapMode ).Height() ) );
534
535 //#i69780 clip final tile size to a sane max size
536 while ((static_cast<sal_Int64>(rSize.Width()) * nTileCacheSize1D) > SAL_MAX_UINT16)
537 nTileCacheSize1D /= 2;
538 while ((static_cast<sal_Int64>(rSize.Height()) * nTileCacheSize1D) > SAL_MAX_UINT16)
539 nTileCacheSize1D /= 2;
540
541 ImplDrawTiled(rOut, rArea, aOutTileSize, rOffset, nullptr, nTileCacheSize1D);
542}
543
544bool GraphicObject::StartAnimation(OutputDevice& rOut, const Point& rPt, const Size& rSz,
545 tools::Long nRendererId,
546 OutputDevice* pFirstFrameOutDev)
547{
548 bool bRet = false;
549
550 GetGraphic();
551
552 const GraphicAttr aAttr( GetAttr() );
553
554 if (IsAnimated())
555 {
556 Point aPt( rPt );
557 Size aSz( rSz );
558 bool bCropped = aAttr.IsCropped();
559
560 if( bCropped )
561 {
562 tools::PolyPolygon aClipPolyPoly;
563 bool bRectClip;
564 const bool bCrop = ImplGetCropParams(rOut, aPt, aSz, &aAttr, aClipPolyPoly, bRectClip);
565
567
568 if( bCrop )
569 {
570 if( bRectClip )
571 rOut.IntersectClipRegion(aClipPolyPoly.GetBoundRect());
572 else
573 rOut.IntersectClipRegion(vcl::Region(aClipPolyPoly));
574 }
575 }
576
577 if (!mxSimpleCache || (mxSimpleCache->maAttr != aAttr) || pFirstFrameOutDev)
578 {
579 mxSimpleCache.reset(new GrfSimpleCacheObj(GetTransformedGraphic(&aAttr), aAttr));
580 mxSimpleCache->maGraphic.SetAnimationNotifyHdl(GetGraphic().GetAnimationNotifyHdl());
581 }
582
583 mxSimpleCache->maGraphic.StartAnimation(rOut, aPt, aSz, nRendererId, pFirstFrameOutDev);
584
585 if( bCropped )
586 rOut.Pop();
587
588 bRet = true;
589 }
590 else
591 bRet = Draw(rOut, rPt, rSz, &aAttr);
592
593 return bRet;
594}
595
597{
598 if (mxSimpleCache)
599 mxSimpleCache->maGraphic.StopAnimation(pOut, nRendererId);
600}
601
603{
604 return maGraphic;
605}
606
607void GraphicObject::SetGraphic( const Graphic& rGraphic)
608{
609 maGraphic = rGraphic;
610}
611
612Graphic GraphicObject::GetTransformedGraphic( const Size& rDestSize, const MapMode& rDestMap, const GraphicAttr& rAttr ) const
613{
614 // #104550# Extracted from svx/source/svdraw/svdograf.cxx
615 Graphic aTransGraphic( GetGraphic() );
616 const GraphicType eType = GetType();
617 const Size aSrcSize( aTransGraphic.GetPrefSize() );
618
619 // #104115# Convert the crop margins to graphic object mapmode
620 const MapMode aMapGraph( aTransGraphic.GetPrefMapMode() );
621 const MapMode aMap100( MapUnit::Map100thMM );
622
623 Size aCropLeftTop;
624 Size aCropRightBottom;
625
627 {
628 GDIMetaFile aMtf( aTransGraphic.GetGDIMetaFile() );
629
630 if (aMapGraph.GetMapUnit() == MapUnit::MapPixel)
631 {
632 // crops are in 1/100th mm -> to aMapGraph -> to MapUnit::MapPixel
634 Size(rAttr.GetLeftCrop(), rAttr.GetTopCrop()),
635 aMap100);
636 aCropRightBottom = Application::GetDefaultDevice()->LogicToPixel(
637 Size(rAttr.GetRightCrop(), rAttr.GetBottomCrop()),
638 aMap100);
639 }
640 else
641 {
642 // crops are in GraphicObject units -> to aMapGraph
643 aCropLeftTop = OutputDevice::LogicToLogic(
644 Size(rAttr.GetLeftCrop(), rAttr.GetTopCrop()),
645 aMap100,
646 aMapGraph);
647 aCropRightBottom = OutputDevice::LogicToLogic(
648 Size(rAttr.GetRightCrop(), rAttr.GetBottomCrop()),
649 aMap100,
650 aMapGraph);
651 }
652
653 // #104115# If the metafile is cropped, give it a special
654 // treatment: clip against the remaining area, scale up such
655 // that this area later fills the desired size, and move the
656 // origin to the upper left edge of that area.
657 if( rAttr.IsCropped() )
658 {
659 const MapMode aMtfMapMode( aMtf.GetPrefMapMode() );
660
661 tools::Rectangle aClipRect( aMtfMapMode.GetOrigin().X() + aCropLeftTop.Width(),
662 aMtfMapMode.GetOrigin().Y() + aCropLeftTop.Height(),
663 aMtfMapMode.GetOrigin().X() + aSrcSize.Width() - aCropRightBottom.Width(),
664 aMtfMapMode.GetOrigin().Y() + aSrcSize.Height() - aCropRightBottom.Height() );
665
666 // #104115# To correctly crop rotated metafiles, clip by view rectangle
667 aMtf.AddAction( new MetaISectRectClipRegionAction( aClipRect ), 0 );
668
669 // #104115# To crop the metafile, scale larger than the output rectangle
670 aMtf.Scale( static_cast<double>(rDestSize.Width()) / (aSrcSize.Width() - aCropLeftTop.Width() - aCropRightBottom.Width()),
671 static_cast<double>(rDestSize.Height()) / (aSrcSize.Height() - aCropLeftTop.Height() - aCropRightBottom.Height()) );
672
673 // #104115# Adapt the pref size by hand (scale changes it
674 // proportionally, but we want it to be smaller than the
675 // former size, to crop the excess out)
676 aMtf.SetPrefSize( Size( static_cast<tools::Long>(static_cast<double>(rDestSize.Width()) * (1.0 + (aCropLeftTop.Width() + aCropRightBottom.Width()) / aSrcSize.Width()) + .5),
677 static_cast<tools::Long>(static_cast<double>(rDestSize.Height()) * (1.0 + (aCropLeftTop.Height() + aCropRightBottom.Height()) / aSrcSize.Height()) + .5) ) );
678
679 // #104115# Adapt the origin of the new mapmode, such that it
680 // is shifted to the place where the cropped output starts
681 Point aNewOrigin( static_cast<tools::Long>(static_cast<double>(aMtfMapMode.GetOrigin().X()) + rDestSize.Width() * aCropLeftTop.Width() / (aSrcSize.Width() - aCropLeftTop.Width() - aCropRightBottom.Width()) + .5),
682 static_cast<tools::Long>(static_cast<double>(aMtfMapMode.GetOrigin().Y()) + rDestSize.Height() * aCropLeftTop.Height() / (aSrcSize.Height() - aCropLeftTop.Height() - aCropRightBottom.Height()) + .5) );
683 MapMode aNewMap( rDestMap );
684 aNewMap.SetOrigin( OutputDevice::LogicToLogic(aNewOrigin, aMtfMapMode, rDestMap) );
685 aMtf.SetPrefMapMode( aNewMap );
686 }
687 else
688 {
689 aMtf.Scale( Fraction( rDestSize.Width(), aSrcSize.Width() ), Fraction( rDestSize.Height(), aSrcSize.Height() ) );
690 aMtf.SetPrefMapMode( rDestMap );
691 }
692
693 aTransGraphic = aMtf;
694 }
695 else if( GraphicType::Bitmap == eType )
696 {
697 BitmapEx aBitmapEx( aTransGraphic.GetBitmapEx() );
698 tools::Rectangle aCropRect;
699
700 // convert crops to pixel
701 if(rAttr.IsCropped())
702 {
703 if (aMapGraph.GetMapUnit() == MapUnit::MapPixel)
704 {
705 // crops are in 1/100th mm -> to MapUnit::MapPixel
707 Size(rAttr.GetLeftCrop(), rAttr.GetTopCrop()),
708 aMap100);
709 aCropRightBottom = Application::GetDefaultDevice()->LogicToPixel(
710 Size(rAttr.GetRightCrop(), rAttr.GetBottomCrop()),
711 aMap100);
712 }
713 else
714 {
715 // crops are in GraphicObject units -> to MapUnit::MapPixel
717 Size(rAttr.GetLeftCrop(), rAttr.GetTopCrop()),
718 aMapGraph);
719 aCropRightBottom = Application::GetDefaultDevice()->LogicToPixel(
720 Size(rAttr.GetRightCrop(), rAttr.GetBottomCrop()),
721 aMapGraph);
722 }
723
724 // convert from prefmapmode to pixel
725 Size aSrcSizePixel(
726 Application::GetDefaultDevice()->LogicToPixel(
727 aSrcSize,
728 aMapGraph));
729
730 if(rAttr.IsCropped()
731 && (aSrcSizePixel.Width() != aBitmapEx.GetSizePixel().Width() || aSrcSizePixel.Height() != aBitmapEx.GetSizePixel().Height())
732 && aSrcSizePixel.Width())
733 {
734 // the size in pixels calculated from Graphic's internal MapMode (aTransGraphic.GetPrefMapMode())
735 // and its internal size (aTransGraphic.GetPrefSize()) is different from its real pixel size.
736 // This can be interpreted as this values to be set wrong, but needs to be corrected since e.g.
737 // existing cropping is calculated based on this logic values already.
738 // aBitmapEx.Scale(aSrcSizePixel);
739
740 // another possibility is to adapt the values created so far with a factor; this
741 // will keep the original Bitmap untouched and thus quality will not change
742 // caution: convert to double first, else pretty big errors may occur
743 const double fFactorX(static_cast<double>(aBitmapEx.GetSizePixel().Width()) / aSrcSizePixel.Width());
744 const double fFactorY(static_cast<double>(aBitmapEx.GetSizePixel().Height()) / aSrcSizePixel.Height());
745
746 aCropLeftTop.setWidth( basegfx::fround(aCropLeftTop.Width() * fFactorX) );
747 aCropLeftTop.setHeight( basegfx::fround(aCropLeftTop.Height() * fFactorY) );
748 aCropRightBottom.setWidth( basegfx::fround(aCropRightBottom.Width() * fFactorX) );
749 aCropRightBottom.setHeight( basegfx::fround(aCropRightBottom.Height() * fFactorY) );
750
751 aSrcSizePixel = aBitmapEx.GetSizePixel();
752 }
753
754 // setup crop rectangle in pixel
755 aCropRect = tools::Rectangle( aCropLeftTop.Width(), aCropLeftTop.Height(),
756 aSrcSizePixel.Width() - aCropRightBottom.Width(),
757 aSrcSizePixel.Height() - aCropRightBottom.Height() );
758 }
759
760 // #105641# Also crop animations
761 if( aTransGraphic.IsAnimated() )
762 {
763 Animation aAnim( aTransGraphic.GetAnimation() );
764
765 for( size_t nFrame=0; nFrame<aAnim.Count(); ++nFrame )
766 {
767 AnimationFrame aAnimationFrame( aAnim.Get( nFrame ) );
768
769 if( !aCropRect.Contains( tools::Rectangle(aAnimationFrame.maPositionPixel, aAnimationFrame.maSizePixel) ) )
770 {
771 // setup actual cropping (relative to frame position)
772 tools::Rectangle aCropRectRel( aCropRect );
773 aCropRectRel.Move( -aAnimationFrame.maPositionPixel.X(),
774 -aAnimationFrame.maPositionPixel.Y() );
775
776 // cropping affects this frame, apply it then
777 // do _not_ apply enlargement, this is done below
778 ImplTransformBitmap( aAnimationFrame.maBitmapEx, rAttr, Size(), Size(),
779 aCropRectRel, rDestSize, false );
780
781 aAnim.Replace( aAnimationFrame, nFrame );
782 }
783 // else: bitmap completely within crop area,
784 // i.e. nothing is cropped away
785 }
786
787 // now, apply enlargement (if any) through global animation size
788 if( aCropLeftTop.Width() < 0 ||
789 aCropLeftTop.Height() < 0 ||
790 aCropRightBottom.Width() < 0 ||
791 aCropRightBottom.Height() < 0 )
792 {
793 Size aNewSize( aAnim.GetDisplaySizePixel() );
794 aNewSize.AdjustWidth(aCropRightBottom.Width() < 0 ? -aCropRightBottom.Width() : 0 );
795 aNewSize.AdjustWidth(aCropLeftTop.Width() < 0 ? -aCropLeftTop.Width() : 0 );
796 aNewSize.AdjustHeight(aCropRightBottom.Height() < 0 ? -aCropRightBottom.Height() : 0 );
797 aNewSize.AdjustHeight(aCropLeftTop.Height() < 0 ? -aCropLeftTop.Height() : 0 );
798 aAnim.SetDisplaySizePixel( aNewSize );
799 }
800
801 // if topleft has changed, we must move all frames to the
802 // right and bottom, resp.
803 if( aCropLeftTop.Width() < 0 ||
804 aCropLeftTop.Height() < 0 )
805 {
806 Point aPosOffset( aCropLeftTop.Width() < 0 ? -aCropLeftTop.Width() : 0,
807 aCropLeftTop.Height() < 0 ? -aCropLeftTop.Height() : 0 );
808
809 for( size_t nFrame=0; nFrame<aAnim.Count(); ++nFrame )
810 {
811 AnimationFrame aAnimationFrame( aAnim.Get( nFrame ) );
812
813 aAnimationFrame.maPositionPixel += aPosOffset;
814
815 aAnim.Replace( aAnimationFrame, nFrame );
816 }
817 }
818
819 aTransGraphic = aAnim;
820 }
821 else
822 {
823 ImplTransformBitmap( aBitmapEx, rAttr, aCropLeftTop, aCropRightBottom,
824 aCropRect, rDestSize, true );
825
826 aTransGraphic = aBitmapEx;
827 }
828
829 aTransGraphic.SetPrefSize( rDestSize );
830 aTransGraphic.SetPrefMapMode( rDestMap );
831 }
832
833 GraphicObject aGrfObj( aTransGraphic );
834 aTransGraphic = aGrfObj.GetTransformedGraphic( &rAttr );
835
836 return aTransGraphic;
837}
838
840{
841 GetGraphic();
842
843 Graphic aGraphic;
844 GraphicAttr aAttr( pAttr ? *pAttr : GetAttr() );
845
847 {
848 if( aAttr.IsSpecialDrawMode() || aAttr.IsAdjusted() || aAttr.IsMirrored() || aAttr.IsRotated() || aAttr.IsTransparent() )
849 {
851 {
852 if( IsAnimated() )
853 {
854 Animation aAnimation( maGraphic.GetAnimation() );
855 lclImplAdjust( aAnimation, aAttr, GraphicAdjustmentFlags::ALL );
857 aGraphic = aAnimation;
858 }
859 else
860 {
861 BitmapEx aBmpEx( maGraphic.GetBitmapEx() );
862 lclImplAdjust( aBmpEx, aAttr, GraphicAdjustmentFlags::ALL );
863 aGraphic = aBmpEx;
864 }
865 }
866 else
867 {
869 lclImplAdjust( aMtf, aAttr, GraphicAdjustmentFlags::ALL );
870 aGraphic = aMtf;
871 }
872 }
873 else
874 {
875 if( ( GetType() == GraphicType::Bitmap ) && IsAnimated() )
876 {
877 Animation aAnimation( maGraphic.GetAnimation() );
879 aGraphic = aAnimation;
880 }
881 else
882 aGraphic = maGraphic;
883 }
884 }
885
886 return aGraphic;
887}
888
889bool GraphicObject::isGraphicObjectUniqueIdURL(std::u16string_view rURL)
890{
891 return o3tl::starts_with(rURL, u"vnd.sun.star.GraphicObject:");
892}
893
894// calculate scalings between real image size and logic object size. This
895// is necessary since the crop values are relative to original bitmap size
897 double fWidth,
898 double fHeight,
899 double fLeftCrop,
900 double fTopCrop,
901 double fRightCrop,
902 double fBottomCrop) const
903{
904 const MapMode aMapMode100thmm(MapUnit::Map100thMM);
905 Size aBitmapSize(GetPrefSize());
906 double fFactorX(1.0);
907 double fFactorY(1.0);
908
909 if(MapUnit::MapPixel == GetPrefMapMode().GetMapUnit())
910 {
911 aBitmapSize = Application::GetDefaultDevice()->PixelToLogic(aBitmapSize, aMapMode100thmm);
912 }
913 else
914 {
915 aBitmapSize = OutputDevice::LogicToLogic(aBitmapSize, GetPrefMapMode(), aMapMode100thmm);
916 }
917
918 const double fDivX(aBitmapSize.Width() - fLeftCrop - fRightCrop);
919 const double fDivY(aBitmapSize.Height() - fTopCrop - fBottomCrop);
920
922 {
923 fFactorX = fabs(fWidth) / fDivX;
924 }
925
927 {
928 fFactorY = fabs(fHeight) / fDivY;
929 }
930
931 return basegfx::B2DVector(fFactorX,fFactorY);
932}
933
934
935/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
DrawModeFlags
#define WATERMARK_CON_OFFSET
#define WATERMARK_LUM_OFFSET
GraphicAdjustmentFlags
Sequence< NamedValue > maUserData
void Replace(const AnimationFrame &rNewAnimationBmp, sal_uInt16 nAnimation)
Definition: Animation.cxx:440
void Convert(BmpConversion eConversion)
Definition: Animation.cxx:467
size_t Count() const
Definition: Animation.hxx:71
const Size & GetDisplaySizePixel() const
Definition: Animation.hxx:57
void Mirror(BmpMirrorFlags nMirrorFlags)
Definition: Animation.cxx:531
void SetLoopCount(const sal_uInt32 nLoopCount)
Definition: Animation.cxx:455
const AnimationFrame & Get(sal_uInt16 nAnimation) const
Definition: Animation.cxx:434
void Adjust(short nLuminancePercent, short nContrastPercent, short nChannelRPercent, short nChannelGPercent, short nChannelBPercent, double fGamma=1.0, bool bInvert=false)
Definition: Animation.cxx:566
void SetDisplaySizePixel(const Size &rSize)
Definition: Animation.hxx:58
static OutputDevice * GetDefaultDevice()
Get the default "device" (in this case the default window).
Definition: svapp.cxx:1043
bool Convert(BmpConversion eConversion)
Convert bitmap format.
Definition: BitmapEx.cxx:383
bool Rotate(Degree10 nAngle10, const Color &rFillColor)
Rotate bitmap by the specified angle.
Definition: BitmapEx.cxx:325
bool Mirror(BmpMirrorFlags nMirrorFlags)
Mirror the bitmap.
Definition: BitmapEx.cxx:268
void AdjustTransparency(sal_uInt8 cTrans)
Definition: BitmapEx.cxx:1388
bool Adjust(short nLuminancePercent, short nContrastPercent, short nChannelRPercent, short nChannelGPercent, short nChannelBPercent, double fGamma=1.0, bool bInvert=false, bool msoBrightness=false)
Change various global color characteristics.
Definition: BitmapEx.cxx:494
const Size & GetSizePixel() const
Definition: bitmapex.hxx:73
void Scale(double fScaleX, double fScaleY)
Definition: gdimtf.cxx:748
void Rotate(Degree10 nAngle10)
Definition: gdimtf.cxx:846
void Mirror(BmpMirrorFlags nMirrorFlags)
Definition: gdimtf.cxx:617
void AddAction(const rtl::Reference< MetaAction > &pAction)
Definition: gdimtf.cxx:585
void Adjust(short nLuminancePercent, short nContrastPercent, short nChannelRPercent=0, short nChannelGPercent=0, short nChannelBPercent=0, double fGamma=1.0, bool bInvert=false, bool msoBrightness=false)
Definition: gdimtf.cxx:2067
void Convert(MtfConversion eConversion)
Definition: gdimtf.cxx:2148
void SetPrefMapMode(const MapMode &rMapMode)
Definition: gdimtf.hxx:180
const MapMode & GetPrefMapMode() const
Definition: gdimtf.hxx:179
void SetPrefSize(const Size &rSize)
Definition: gdimtf.hxx:177
bool IsCropped() const
Degree10 GetRotation() const
tools::Long GetTopCrop() const
bool IsTransparent() const
bool IsSpecialDrawMode() const
tools::Long GetBottomCrop() const
tools::Long GetRightCrop() const
void SetMirrorFlags(BmpMirrorFlags nMirrFlags)
bool IsMirrored() const
bool IsRotated() const
BmpMirrorFlags GetMirrorFlags() const
bool IsAdjusted() const
tools::Long GetLeftCrop() const
void VCL_DLLPRIVATE ImplTransformBitmap(BitmapEx &rBmpEx, const GraphicAttr &rAttr, const Size &rCropLeftTop, const Size &rCropRightBottom, const tools::Rectangle &rCropRect, const Size &rDstSize, bool bEnlarge) const
static bool isGraphicObjectUniqueIdURL(std::u16string_view rURL)
basegfx::B2DVector calculateCropScaling(double fWidth, double fHeight, double fLeftCrop, double fTopCrop, double fRightCrop, double fBottomCrop) const
void SetGraphic(const Graphic &rGraphic)
Size GetPrefSize() const
MapMode GetPrefMapMode() const
const Graphic & GetGraphic() const
GraphicType GetType() const
Graphic GetTransformedGraphic(const Size &rDestSize, const MapMode &rDestMap, const GraphicAttr &rAttr) const
Get graphic transformed according to given attributes.
bool IsEPS() const
bool VCL_DLLPRIVATE ImplDrawTiled(OutputDevice &rOut, const tools::Rectangle &rArea, const Size &rSizePixel, const Size &rOffset, const GraphicAttr *pAttr, int nTileCacheSize1D)
void StopAnimation(const OutputDevice *pOut=nullptr, tools::Long nExtraData=0)
const GraphicAttr & GetAttr() const
bool IsAnimated() const
bool StartAnimation(OutputDevice &rOut, const Point &rPt, const Size &rSz, tools::Long nExtraData=0, OutputDevice *pFirstFrameOutDev=nullptr)
OUString maUserData
bool IsTransparent() const
bool operator==(const GraphicObject &rCacheObj) const
void DrawTiled(OutputDevice &rOut, const tools::Rectangle &rArea, const Size &rSize, const Size &rOffset, int nTileCacheSize1D=128)
Draw the graphic repeatedly into the given output rectangle.
GraphicObject & operator=(const GraphicObject &rCacheObj)
bool Draw(OutputDevice &rOut, const Point &rPt, const Size &rSz, const GraphicAttr *pAttr=nullptr) const
GraphicAttr maAttr
bool VCL_DLLPRIVATE ImplGetCropParams(const OutputDevice &rOut, Point &rPt, Size &rSz, const GraphicAttr *pAttr, tools::PolyPolygon &rClipPolyPoly, bool &bRectClipRegion) const
OString GetUniqueID() const
void SetAttr(const GraphicAttr &rAttr)
std::unique_ptr< GrfSimpleCacheObj > mxSimpleCache
css::uno::Reference< css::graphic::XGraphic > GetXGraphic() const
Definition: graph.cxx:350
Size GetPrefSize() const
Definition: graph.cxx:364
OString getUniqueID() const
Definition: graph.cxx:552
Animation GetAnimation() const
Definition: graph.cxx:335
void SetPrefMapMode(const MapMode &rPrefMapMode)
Definition: graph.cxx:380
bool IsSupportedGraphic() const
Definition: graph.cxx:305
sal_uInt32 GetAnimationLoopCount() const
Definition: graph.cxx:474
const GDIMetaFile & GetGDIMetaFile() const
Definition: graph.cxx:340
GraphicType GetType() const
Definition: graph.cxx:294
bool IsAnimated() const
Definition: graph.cxx:320
bool IsNone() const
Definition: graph.cxx:283
BitmapEx GetBitmapEx(const GraphicConversionParameters &rParameters=GraphicConversionParameters()) const
Definition: graph.cxx:330
MapMode GetPrefMapMode() const
Definition: graph.cxx:375
bool IsEPS() const
Definition: graph.cxx:325
void SetPrefSize(const Size &rPrefSize)
Definition: graph.cxx:369
bool IsTransparent() const
Definition: graph.cxx:310
void SetOrigin(const Point &rOrigin)
Definition: mapmod.cxx:138
MapUnit GetMapUnit() const
Definition: mapmod.cxx:181
const Point & GetOrigin() const
Definition: mapmod.cxx:183
Some things multiple-inherit from VclAbstractDialog and OutputDevice, so we need to use virtual inher...
Definition: outdev.hxx:170
SAL_WARN_UNUSED_RESULT Point PixelToLogic(const Point &rDevicePt) const
Definition: map.cxx:1110
SAL_WARN_UNUSED_RESULT Point LogicToLogic(const Point &rPtSource, const MapMode *pMapModeSource, const MapMode *pMapModeDest) const
Definition: map.cxx:1580
SAL_WARN_UNUSED_RESULT Point LogicToPixel(const Point &rLogicPt) const
Definition: map.cxx:879
const MapMode & GetMapMode() const
Definition: outdev.hxx:1557
void Push(vcl::PushFlags nFlags=vcl::PushFlags::ALL)
Definition: stack.cxx:32
void Pop()
Definition: stack.cxx:91
void SetDrawMode(DrawModeFlags nDrawMode)
Definition: outdev.cxx:364
DrawModeFlags GetDrawMode() const
Definition: outdev.hxx:487
void IntersectClipRegion(const tools::Rectangle &rRect)
constexpr tools::Long Y() const
tools::Long AdjustY(tools::Long nVertMove)
tools::Long AdjustX(tools::Long nHorzMove)
constexpr tools::Long X() const
bool IsEmpty() const
constexpr tools::Long Height() const
tools::Long AdjustHeight(tools::Long n)
void setWidth(tools::Long nWidth)
tools::Long AdjustWidth(tools::Long n)
void setHeight(tools::Long nHeight)
constexpr tools::Long Width() const
tools::Rectangle GetBoundRect() const
void Rotate(const Point &rCenter, double fSin, double fCos)
bool Contains(const Point &rPOINT) const
void Move(tools::Long nHorzMoveDelta, tools::Long nVertMoveDelta)
float u
DocumentType eType
GraphicType
Definition: graph.hxx:35
const Graphic maGraphic
tools::Long FRound(double fVal)
MapUnit GetMapUnit()
bool equalZero(const T &rfVal)
B2IRange fround(const B2DRange &rRange)
class SAL_NO_VTABLE XPropertySet
m
constexpr bool starts_with(std::basic_string_view< charT, traits > sv, std::basic_string_view< charT, traits > x) noexcept
long Long
void SearchForGraphics(uno::Reference< uno::XInterface > const &xInterface, std::vector< uno::Reference< css::graphic::XGraphic > > &raGraphicList)
Graphic loadFromURL(OUString const &rURL, weld::Window *pParentWin)
GrfSimpleCacheObj(Graphic aGraphic, const GraphicAttr &rAttr)
#define SAL_MAX_UINT16
oslFileHandle & pOut