1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <sal/config.h>
24 #include <osl/diagnose.h>
25 #include <tools/fract.hxx>
26 #include <tools/helpers.hxx>
27 #include <vcl/svapp.hxx>
28 #include <vcl/metaact.hxx>
29 #include <vcl/GraphicObject.hxx>
30 #include <vcl/GraphicLoader.hxx>
31 #include <vcl/outdev.hxx>
33 #include <com/sun/star/container/XNameContainer.hpp>
34 #include <com/sun/star/beans/XPropertySet.hpp>
35 #include <com/sun/star/graphic/XGraphic.hpp>
40 using com::sun::star::uno::Reference
;
41 using com::sun::star::uno::XInterface
;
42 using com::sun::star::uno::UNO_QUERY
;
43 using com::sun::star::uno::Sequence
;
44 using com::sun::star::container::XNameContainer
;
45 using com::sun::star::beans::XPropertySet
;
47 #define WATERMARK_LUM_OFFSET 50
48 #define WATERMARK_CON_OFFSET -70
55 void SearchForGraphics(uno::Reference
<uno::XInterface
> const & xInterface
,
56 std::vector
<uno::Reference
<css::graphic::XGraphic
>> & raGraphicList
)
58 uno::Reference
<beans::XPropertySet
> xPropertySet(xInterface
, UNO_QUERY
);
59 if (xPropertySet
.is())
61 if (xPropertySet
->getPropertySetInfo()->hasPropertyByName("ImageURL"))
64 xPropertySet
->getPropertyValue("ImageURL") >>= sURL
;
65 if (!sURL
.isEmpty() && !GraphicObject::isGraphicObjectUniqueIdURL(sURL
))
67 Graphic aGraphic
= vcl::graphic::loadFromURL(sURL
);
68 if (!aGraphic
.IsNone())
70 raGraphicList
.push_back(aGraphic
.GetXGraphic());
73 } else if (xPropertySet
->getPropertySetInfo()->hasPropertyByName("Graphic"))
75 uno::Reference
<css::graphic::XGraphic
> xGraphic
;
76 xPropertySet
->getPropertyValue("Graphic") >>= xGraphic
;
79 raGraphicList
.push_back(xGraphic
);
83 Reference
<XNameContainer
> xContainer(xInterface
, UNO_QUERY
);
86 const css::uno::Sequence
<OUString
> aElementNames
= xContainer
->getElementNames();
87 for (OUString
const & rName
: aElementNames
)
89 uno::Reference
<XInterface
> xInnerInterface
;
90 xContainer
->getByName(rName
) >>= xInnerInterface
;
91 SearchForGraphics(xInnerInterface
, raGraphicList
);
96 }} // end namespace vcl::graphic
101 bool lclDrawObj( OutputDevice
* pOut
, const Point
& rPt
, const Size
& rSz
,
102 GraphicObject
const & rObj
, const GraphicAttr
& rAttr
)
108 if( ( rObj
.GetType() == GraphicType::Bitmap
) || ( rObj
.GetType() == GraphicType::GdiMetafile
) )
110 // simple output of transformed graphic
111 const Graphic
aGraphic( rObj
.GetTransformedGraphic( &rAttr
) );
113 if( aGraphic
.IsSupportedGraphic() )
115 const sal_uInt16 nRot10
= rAttr
.GetRotation() % 3600;
119 tools::Polygon
aPoly( tools::Rectangle( aPt
, aSz
) );
121 aPoly
.Rotate( aPt
, nRot10
);
122 const tools::Rectangle
aRotBoundRect( aPoly
.GetBoundRect() );
123 aPt
= aRotBoundRect
.TopLeft();
124 aSz
= aRotBoundRect
.GetSize();
127 aGraphic
.Draw( pOut
, aPt
, aSz
);
136 void lclImplAdjust( BitmapEx
& rBmpEx
, const GraphicAttr
& rAttr
, GraphicAdjustmentFlags nAdjustmentFlags
)
138 GraphicAttr
aAttr( rAttr
);
140 if( ( nAdjustmentFlags
& GraphicAdjustmentFlags::DRAWMODE
) && aAttr
.IsSpecialDrawMode() )
142 switch( aAttr
.GetDrawMode() )
144 case GraphicDrawMode::Mono
:
145 rBmpEx
.Convert( BmpConversion::N1BitThreshold
);
148 case GraphicDrawMode::Greys
:
149 rBmpEx
.Convert( BmpConversion::N8BitGreys
);
152 case GraphicDrawMode::Watermark
:
154 aAttr
.SetLuminance( aAttr
.GetLuminance() + WATERMARK_LUM_OFFSET
);
155 aAttr
.SetContrast( aAttr
.GetContrast() + WATERMARK_CON_OFFSET
);
164 if( ( nAdjustmentFlags
& GraphicAdjustmentFlags::COLORS
) && aAttr
.IsAdjusted() )
166 rBmpEx
.Adjust( aAttr
.GetLuminance(), aAttr
.GetContrast(),
167 aAttr
.GetChannelR(), aAttr
.GetChannelG(), aAttr
.GetChannelB(),
168 aAttr
.GetGamma(), aAttr
.IsInvert() );
171 if( ( nAdjustmentFlags
& GraphicAdjustmentFlags::MIRROR
) && aAttr
.IsMirrored() )
173 rBmpEx
.Mirror( aAttr
.GetMirrorFlags() );
176 if( ( nAdjustmentFlags
& GraphicAdjustmentFlags::ROTATE
) && aAttr
.IsRotated() )
178 rBmpEx
.Rotate( aAttr
.GetRotation(), COL_TRANSPARENT
);
181 if( ( nAdjustmentFlags
& GraphicAdjustmentFlags::TRANSPARENCY
) && aAttr
.IsTransparent() )
183 rBmpEx
.AdjustTransparency(aAttr
.GetTransparency());
187 void lclImplAdjust( GDIMetaFile
& rMtf
, const GraphicAttr
& rAttr
, GraphicAdjustmentFlags nAdjustmentFlags
)
189 GraphicAttr
aAttr( rAttr
);
191 if( ( nAdjustmentFlags
& GraphicAdjustmentFlags::DRAWMODE
) && aAttr
.IsSpecialDrawMode() )
193 switch( aAttr
.GetDrawMode() )
195 case GraphicDrawMode::Mono
:
196 rMtf
.Convert( MtfConversion::N1BitThreshold
);
199 case GraphicDrawMode::Greys
:
200 rMtf
.Convert( MtfConversion::N8BitGreys
);
203 case GraphicDrawMode::Watermark
:
205 aAttr
.SetLuminance( aAttr
.GetLuminance() + WATERMARK_LUM_OFFSET
);
206 aAttr
.SetContrast( aAttr
.GetContrast() + WATERMARK_CON_OFFSET
);
215 if( ( nAdjustmentFlags
& GraphicAdjustmentFlags::COLORS
) && aAttr
.IsAdjusted() )
217 rMtf
.Adjust( aAttr
.GetLuminance(), aAttr
.GetContrast(),
218 aAttr
.GetChannelR(), aAttr
.GetChannelG(), aAttr
.GetChannelB(),
219 aAttr
.GetGamma(), aAttr
.IsInvert() );
222 if( ( nAdjustmentFlags
& GraphicAdjustmentFlags::MIRROR
) && aAttr
.IsMirrored() )
224 rMtf
.Mirror( aAttr
.GetMirrorFlags() );
227 if( ( nAdjustmentFlags
& GraphicAdjustmentFlags::ROTATE
) && aAttr
.IsRotated() )
229 rMtf
.Rotate( aAttr
.GetRotation() );
232 if( ( nAdjustmentFlags
& GraphicAdjustmentFlags::TRANSPARENCY
) && aAttr
.IsTransparent() )
234 OSL_FAIL( "Missing implementation: Mtf-Transparency" );
238 void lclImplAdjust( Animation
& rAnimation
, const GraphicAttr
& rAttr
, GraphicAdjustmentFlags nAdjustmentFlags
)
240 GraphicAttr
aAttr( rAttr
);
242 if( ( nAdjustmentFlags
& GraphicAdjustmentFlags::DRAWMODE
) && aAttr
.IsSpecialDrawMode() )
244 switch( aAttr
.GetDrawMode() )
246 case GraphicDrawMode::Mono
:
247 rAnimation
.Convert( BmpConversion::N1BitThreshold
);
250 case GraphicDrawMode::Greys
:
251 rAnimation
.Convert( BmpConversion::N8BitGreys
);
254 case GraphicDrawMode::Watermark
:
256 aAttr
.SetLuminance( aAttr
.GetLuminance() + WATERMARK_LUM_OFFSET
);
257 aAttr
.SetContrast( aAttr
.GetContrast() + WATERMARK_CON_OFFSET
);
266 if( ( nAdjustmentFlags
& GraphicAdjustmentFlags::COLORS
) && aAttr
.IsAdjusted() )
268 rAnimation
.Adjust( aAttr
.GetLuminance(), aAttr
.GetContrast(),
269 aAttr
.GetChannelR(), aAttr
.GetChannelG(), aAttr
.GetChannelB(),
270 aAttr
.GetGamma(), aAttr
.IsInvert() );
273 if( ( nAdjustmentFlags
& GraphicAdjustmentFlags::MIRROR
) && aAttr
.IsMirrored() )
275 rAnimation
.Mirror( aAttr
.GetMirrorFlags() );
278 if( ( nAdjustmentFlags
& GraphicAdjustmentFlags::ROTATE
) && aAttr
.IsRotated() )
280 OSL_FAIL( "Missing implementation: Animation-Rotation" );
283 if( ( nAdjustmentFlags
& GraphicAdjustmentFlags::TRANSPARENCY
) && aAttr
.IsTransparent() )
285 OSL_FAIL( "Missing implementation: Animation-Transparency" );
289 } // end anonymous namespace
291 struct GrfSimpleCacheObj
294 GraphicAttr
const maAttr
;
296 GrfSimpleCacheObj( const Graphic
& rGraphic
, const GraphicAttr
& rAttr
) :
297 maGraphic( rGraphic
), maAttr( rAttr
) {}
300 GraphicObject::GraphicObject()
304 GraphicObject::GraphicObject(const Graphic
& rGraphic
)
305 : maGraphic(rGraphic
)
309 GraphicObject::GraphicObject(const GraphicObject
& rGraphicObj
)
310 : maGraphic(rGraphicObj
.GetGraphic())
311 , maAttr(rGraphicObj
.maAttr
)
312 , maUserData(rGraphicObj
.maUserData
)
316 GraphicObject::~GraphicObject()
320 GraphicType
GraphicObject::GetType() const
322 return maGraphic
.GetType();
325 Size
GraphicObject::GetPrefSize() const
327 return maGraphic
.GetPrefSize();
330 MapMode
GraphicObject::GetPrefMapMode() const
332 return maGraphic
.GetPrefMapMode();
335 bool GraphicObject::IsTransparent() const
337 return maGraphic
.IsTransparent();
340 bool GraphicObject::IsAnimated() const
342 return maGraphic
.IsAnimated();
345 bool GraphicObject::IsEPS() const
347 return maGraphic
.IsEPS();
350 bool GraphicObject::ImplGetCropParams( OutputDevice
const * pOut
, Point
& rPt
, Size
& rSz
, const GraphicAttr
* pAttr
,
351 tools::PolyPolygon
& rClipPolyPoly
, bool& bRectClipRegion
) const
355 if( GetType() != GraphicType::NONE
)
357 tools::Polygon
aClipPoly( tools::Rectangle( rPt
, rSz
) );
358 const sal_uInt16 nRot10
= pAttr
->GetRotation() % 3600;
359 const Point
aOldOrigin( rPt
);
360 const MapMode
aMap100( MapUnit::Map100thMM
);
362 long nTotalWidth
, nTotalHeight
;
366 aClipPoly
.Rotate( rPt
, nRot10
);
367 bRectClipRegion
= false;
370 bRectClipRegion
= true;
372 rClipPolyPoly
= aClipPoly
;
374 if (maGraphic
.GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel
)
375 aSize100
= Application::GetDefaultDevice()->PixelToLogic( maGraphic
.GetPrefSize(), aMap100
);
378 MapMode
m(maGraphic
.GetPrefMapMode());
379 aSize100
= pOut
->LogicToLogic( maGraphic
.GetPrefSize(), &m
, &aMap100
);
382 nTotalWidth
= aSize100
.Width() - pAttr
->GetLeftCrop() - pAttr
->GetRightCrop();
383 nTotalHeight
= aSize100
.Height() - pAttr
->GetTopCrop() - pAttr
->GetBottomCrop();
385 if( aSize100
.Width() > 0 && aSize100
.Height() > 0 && nTotalWidth
> 0 && nTotalHeight
> 0 )
387 double fScale
= static_cast<double>(aSize100
.Width()) / nTotalWidth
;
388 const long nNewLeft
= -FRound( ( ( pAttr
->GetMirrorFlags() & BmpMirrorFlags::Horizontal
) ? pAttr
->GetRightCrop() : pAttr
->GetLeftCrop() ) * fScale
);
389 const long nNewRight
= nNewLeft
+ FRound( aSize100
.Width() * fScale
) - 1;
391 fScale
= static_cast<double>(rSz
.Width()) / aSize100
.Width();
392 rPt
.AdjustX(FRound( nNewLeft
* fScale
) );
393 rSz
.setWidth( FRound( ( nNewRight
- nNewLeft
+ 1 ) * fScale
) );
395 fScale
= static_cast<double>(aSize100
.Height()) / nTotalHeight
;
396 const long nNewTop
= -FRound( ( ( pAttr
->GetMirrorFlags() & BmpMirrorFlags::Vertical
) ? pAttr
->GetBottomCrop() : pAttr
->GetTopCrop() ) * fScale
);
397 const long nNewBottom
= nNewTop
+ FRound( aSize100
.Height() * fScale
) - 1;
399 fScale
= static_cast<double>(rSz
.Height()) / aSize100
.Height();
400 rPt
.AdjustY(FRound( nNewTop
* fScale
) );
401 rSz
.setHeight( FRound( ( nNewBottom
- nNewTop
+ 1 ) * fScale
) );
405 tools::Polygon
aOriginPoly( 1 );
407 aOriginPoly
[ 0 ] = rPt
;
408 aOriginPoly
.Rotate( aOldOrigin
, nRot10
);
409 rPt
= aOriginPoly
[ 0 ];
419 GraphicObject
& GraphicObject::operator=( const GraphicObject
& rGraphicObj
)
421 if( &rGraphicObj
!= this )
423 mxSimpleCache
.reset();
424 maGraphic
= rGraphicObj
.GetGraphic();
425 maAttr
= rGraphicObj
.maAttr
;
426 maUserData
= rGraphicObj
.maUserData
;
432 bool GraphicObject::operator==( const GraphicObject
& rGraphicObj
) const
434 return rGraphicObj
.maGraphic
== maGraphic
435 && rGraphicObj
.maAttr
== maAttr
;
438 OString
GraphicObject::GetUniqueID() const
440 return GetGraphic().getUniqueID();
443 void GraphicObject::SetAttr( const GraphicAttr
& rAttr
)
447 if (mxSimpleCache
&& (mxSimpleCache
->maAttr
!= rAttr
))
448 mxSimpleCache
.reset();
451 void GraphicObject::SetUserData()
456 void GraphicObject::SetUserData( const OUString
& rUserData
)
458 maUserData
= rUserData
;
461 bool GraphicObject::Draw( OutputDevice
* pOut
, const Point
& rPt
, const Size
& rSz
,
462 const GraphicAttr
* pAttr
)
464 GraphicAttr
aAttr( pAttr
? *pAttr
: GetAttr() );
467 const DrawModeFlags nOldDrawMode
= pOut
->GetDrawMode();
468 bool bCropped
= aAttr
.IsCropped();
471 // #i29534# Provide output rects for PDF writer
472 tools::Rectangle aCropRect
;
474 pOut
->SetDrawMode( nOldDrawMode
& ~DrawModeFlags( DrawModeFlags::SettingsLine
| DrawModeFlags::SettingsFill
| DrawModeFlags::SettingsText
| DrawModeFlags::SettingsGradient
) );
476 // mirrored horizontically
477 if( aSz
.Width() < 0 )
479 aPt
.AdjustX(aSz
.Width() + 1 );
480 aSz
.setWidth( -aSz
.Width() );
481 aAttr
.SetMirrorFlags( aAttr
.GetMirrorFlags() ^ BmpMirrorFlags::Horizontal
);
484 // mirrored vertically
485 if( aSz
.Height() < 0 )
487 aPt
.AdjustY(aSz
.Height() + 1 );
488 aSz
.setHeight( -aSz
.Height() );
489 aAttr
.SetMirrorFlags( aAttr
.GetMirrorFlags() ^ BmpMirrorFlags::Vertical
);
494 tools::PolyPolygon aClipPolyPoly
;
496 const bool bCrop
= ImplGetCropParams( pOut
, aPt
, aSz
, &aAttr
, aClipPolyPoly
, bRectClip
);
498 pOut
->Push( PushFlags::CLIPREGION
);
504 // #i29534# Store crop rect for later forwarding to
506 aCropRect
= aClipPolyPoly
.GetBoundRect();
507 pOut
->IntersectClipRegion( aCropRect
);
511 pOut
->IntersectClipRegion(vcl::Region(aClipPolyPoly
));
516 bRet
= lclDrawObj(pOut
, aPt
, aSz
, *this, aAttr
);
521 pOut
->SetDrawMode( nOldDrawMode
);
526 void GraphicObject::DrawTiled( OutputDevice
* pOut
, const tools::Rectangle
& rArea
, const Size
& rSize
,
527 const Size
& rOffset
, int nTileCacheSize1D
)
529 if( pOut
== nullptr || rSize
.Width() == 0 || rSize
.Height() == 0 )
532 const MapMode
aOutMapMode( pOut
->GetMapMode() );
533 const MapMode
aMapMode( aOutMapMode
.GetMapUnit(), Point(), aOutMapMode
.GetScaleX(), aOutMapMode
.GetScaleY() );
534 // #106258# Clamp size to 1 for zero values. This is okay, since
535 // logical size of zero is handled above already
536 const Size
aOutTileSize( ::std::max( 1L, pOut
->LogicToPixel( rSize
, aOutMapMode
).Width() ),
537 ::std::max( 1L, pOut
->LogicToPixel( rSize
, aOutMapMode
).Height() ) );
539 //#i69780 clip final tile size to a sane max size
540 while ((static_cast<sal_Int64
>(rSize
.Width()) * nTileCacheSize1D
) > SAL_MAX_UINT16
)
541 nTileCacheSize1D
/= 2;
542 while ((static_cast<sal_Int64
>(rSize
.Height()) * nTileCacheSize1D
) > SAL_MAX_UINT16
)
543 nTileCacheSize1D
/= 2;
545 ImplDrawTiled( pOut
, rArea
, aOutTileSize
, rOffset
, nullptr, nTileCacheSize1D
);
548 bool GraphicObject::StartAnimation( OutputDevice
* pOut
, const Point
& rPt
, const Size
& rSz
,
550 OutputDevice
* pFirstFrameOutDev
)
556 const GraphicAttr
aAttr( GetAttr() );
562 bool bCropped
= aAttr
.IsCropped();
566 tools::PolyPolygon aClipPolyPoly
;
568 const bool bCrop
= ImplGetCropParams( pOut
, aPt
, aSz
, &aAttr
, aClipPolyPoly
, bRectClip
);
570 pOut
->Push( PushFlags::CLIPREGION
);
575 pOut
->IntersectClipRegion( aClipPolyPoly
.GetBoundRect() );
577 pOut
->IntersectClipRegion(vcl::Region(aClipPolyPoly
));
581 if (!mxSimpleCache
|| (mxSimpleCache
->maAttr
!= aAttr
) || pFirstFrameOutDev
)
583 mxSimpleCache
.reset(new GrfSimpleCacheObj(GetTransformedGraphic(&aAttr
), aAttr
));
584 mxSimpleCache
->maGraphic
.SetAnimationNotifyHdl(GetGraphic().GetAnimationNotifyHdl());
587 mxSimpleCache
->maGraphic
.StartAnimation(pOut
, aPt
, aSz
, nExtraData
, pFirstFrameOutDev
);
595 bRet
= Draw( pOut
, rPt
, rSz
, &aAttr
);
600 void GraphicObject::StopAnimation( OutputDevice
* pOut
, long nExtraData
)
603 mxSimpleCache
->maGraphic
.StopAnimation(pOut
, nExtraData
);
606 const Graphic
& GraphicObject::GetGraphic() const
611 void GraphicObject::SetGraphic( const Graphic
& rGraphic
, const GraphicObject
* /*pCopyObj*/)
613 maGraphic
= rGraphic
;
616 void GraphicObject::SetGraphic( const Graphic
& rGraphic
, const OUString
& /*rLink*/ )
618 SetGraphic( rGraphic
);
621 Graphic
GraphicObject::GetTransformedGraphic( const Size
& rDestSize
, const MapMode
& rDestMap
, const GraphicAttr
& rAttr
) const
623 // #104550# Extracted from svx/source/svdraw/svdograf.cxx
624 Graphic
aTransGraphic( GetGraphic() );
625 const GraphicType eType
= GetType();
626 const Size
aSrcSize( aTransGraphic
.GetPrefSize() );
628 // #104115# Convert the crop margins to graphic object mapmode
629 const MapMode
aMapGraph( aTransGraphic
.GetPrefMapMode() );
630 const MapMode
aMap100( MapUnit::Map100thMM
);
633 Size aCropRightBottom
;
635 if( GraphicType::GdiMetafile
== eType
)
637 GDIMetaFile
aMtf( aTransGraphic
.GetGDIMetaFile() );
639 if (aMapGraph
.GetMapUnit() == MapUnit::MapPixel
)
641 // crops are in 1/100th mm -> to aMapGraph -> to MapUnit::MapPixel
642 aCropLeftTop
= Application::GetDefaultDevice()->LogicToPixel(
643 Size(rAttr
.GetLeftCrop(), rAttr
.GetTopCrop()),
645 aCropRightBottom
= Application::GetDefaultDevice()->LogicToPixel(
646 Size(rAttr
.GetRightCrop(), rAttr
.GetBottomCrop()),
651 // crops are in GraphicObject units -> to aMapGraph
652 aCropLeftTop
= OutputDevice::LogicToLogic(
653 Size(rAttr
.GetLeftCrop(), rAttr
.GetTopCrop()),
656 aCropRightBottom
= OutputDevice::LogicToLogic(
657 Size(rAttr
.GetRightCrop(), rAttr
.GetBottomCrop()),
662 // #104115# If the metafile is cropped, give it a special
663 // treatment: clip against the remaining area, scale up such
664 // that this area later fills the desired size, and move the
665 // origin to the upper left edge of that area.
666 if( rAttr
.IsCropped() )
668 const MapMode
aMtfMapMode( aMtf
.GetPrefMapMode() );
670 tools::Rectangle
aClipRect( aMtfMapMode
.GetOrigin().X() + aCropLeftTop
.Width(),
671 aMtfMapMode
.GetOrigin().Y() + aCropLeftTop
.Height(),
672 aMtfMapMode
.GetOrigin().X() + aSrcSize
.Width() - aCropRightBottom
.Width(),
673 aMtfMapMode
.GetOrigin().Y() + aSrcSize
.Height() - aCropRightBottom
.Height() );
675 // #104115# To correctly crop rotated metafiles, clip by view rectangle
676 aMtf
.AddAction( new MetaISectRectClipRegionAction( aClipRect
), 0 );
678 // #104115# To crop the metafile, scale larger than the output rectangle
679 aMtf
.Scale( static_cast<double>(rDestSize
.Width()) / (aSrcSize
.Width() - aCropLeftTop
.Width() - aCropRightBottom
.Width()),
680 static_cast<double>(rDestSize
.Height()) / (aSrcSize
.Height() - aCropLeftTop
.Height() - aCropRightBottom
.Height()) );
682 // #104115# Adapt the pref size by hand (scale changes it
683 // proportionally, but we want it to be smaller than the
684 // former size, to crop the excess out)
685 aMtf
.SetPrefSize( Size( static_cast<long>(static_cast<double>(rDestSize
.Width()) * (1.0 + (aCropLeftTop
.Width() + aCropRightBottom
.Width()) / aSrcSize
.Width()) + .5),
686 static_cast<long>(static_cast<double>(rDestSize
.Height()) * (1.0 + (aCropLeftTop
.Height() + aCropRightBottom
.Height()) / aSrcSize
.Height()) + .5) ) );
688 // #104115# Adapt the origin of the new mapmode, such that it
689 // is shifted to the place where the cropped output starts
690 Point
aNewOrigin( static_cast<long>(static_cast<double>(aMtfMapMode
.GetOrigin().X()) + rDestSize
.Width() * aCropLeftTop
.Width() / (aSrcSize
.Width() - aCropLeftTop
.Width() - aCropRightBottom
.Width()) + .5),
691 static_cast<long>(static_cast<double>(aMtfMapMode
.GetOrigin().Y()) + rDestSize
.Height() * aCropLeftTop
.Height() / (aSrcSize
.Height() - aCropLeftTop
.Height() - aCropRightBottom
.Height()) + .5) );
692 MapMode
aNewMap( rDestMap
);
693 aNewMap
.SetOrigin( OutputDevice::LogicToLogic(aNewOrigin
, aMtfMapMode
, rDestMap
) );
694 aMtf
.SetPrefMapMode( aNewMap
);
698 aMtf
.Scale( Fraction( rDestSize
.Width(), aSrcSize
.Width() ), Fraction( rDestSize
.Height(), aSrcSize
.Height() ) );
699 aMtf
.SetPrefMapMode( rDestMap
);
702 aTransGraphic
= aMtf
;
704 else if( GraphicType::Bitmap
== eType
)
706 BitmapEx
aBitmapEx( aTransGraphic
.GetBitmapEx() );
707 tools::Rectangle aCropRect
;
709 // convert crops to pixel
710 if(rAttr
.IsCropped())
712 if (aMapGraph
.GetMapUnit() == MapUnit::MapPixel
)
714 // crops are in 1/100th mm -> to MapUnit::MapPixel
715 aCropLeftTop
= Application::GetDefaultDevice()->LogicToPixel(
716 Size(rAttr
.GetLeftCrop(), rAttr
.GetTopCrop()),
718 aCropRightBottom
= Application::GetDefaultDevice()->LogicToPixel(
719 Size(rAttr
.GetRightCrop(), rAttr
.GetBottomCrop()),
724 // crops are in GraphicObject units -> to MapUnit::MapPixel
725 aCropLeftTop
= Application::GetDefaultDevice()->LogicToPixel(
726 Size(rAttr
.GetLeftCrop(), rAttr
.GetTopCrop()),
728 aCropRightBottom
= Application::GetDefaultDevice()->LogicToPixel(
729 Size(rAttr
.GetRightCrop(), rAttr
.GetBottomCrop()),
733 // convert from prefmapmode to pixel
735 Application::GetDefaultDevice()->LogicToPixel(
740 && (aSrcSizePixel
.Width() != aBitmapEx
.GetSizePixel().Width() || aSrcSizePixel
.Height() != aBitmapEx
.GetSizePixel().Height())
741 && aSrcSizePixel
.Width())
743 // the size in pixels calculated from Graphic's internal MapMode (aTransGraphic.GetPrefMapMode())
744 // and its internal size (aTransGraphic.GetPrefSize()) is different from its real pixel size.
745 // This can be interpreted as this values to be set wrong, but needs to be corrected since e.g.
746 // existing cropping is calculated based on this logic values already.
747 // aBitmapEx.Scale(aSrcSizePixel);
749 // another possibility is to adapt the values created so far with a factor; this
750 // will keep the original Bitmap untouched and thus quality will not change
751 // caution: convert to double first, else pretty big errors may occur
752 const double fFactorX(static_cast<double>(aBitmapEx
.GetSizePixel().Width()) / aSrcSizePixel
.Width());
753 const double fFactorY(static_cast<double>(aBitmapEx
.GetSizePixel().Height()) / aSrcSizePixel
.Height());
755 aCropLeftTop
.setWidth( basegfx::fround(aCropLeftTop
.Width() * fFactorX
) );
756 aCropLeftTop
.setHeight( basegfx::fround(aCropLeftTop
.Height() * fFactorY
) );
757 aCropRightBottom
.setWidth( basegfx::fround(aCropRightBottom
.Width() * fFactorX
) );
758 aCropRightBottom
.setHeight( basegfx::fround(aCropRightBottom
.Height() * fFactorY
) );
760 aSrcSizePixel
= aBitmapEx
.GetSizePixel();
763 // setup crop rectangle in pixel
764 aCropRect
= tools::Rectangle( aCropLeftTop
.Width(), aCropLeftTop
.Height(),
765 aSrcSizePixel
.Width() - aCropRightBottom
.Width(),
766 aSrcSizePixel
.Height() - aCropRightBottom
.Height() );
769 // #105641# Also crop animations
770 if( aTransGraphic
.IsAnimated() )
772 Animation
aAnim( aTransGraphic
.GetAnimation() );
774 for( size_t nFrame
=0; nFrame
<aAnim
.Count(); ++nFrame
)
776 AnimationBitmap
aAnimationBitmap( aAnim
.Get( nFrame
) );
778 if( !aCropRect
.IsInside( tools::Rectangle(aAnimationBitmap
.maPositionPixel
, aAnimationBitmap
.maSizePixel
) ) )
780 // setup actual cropping (relative to frame position)
781 tools::Rectangle
aCropRectRel( aCropRect
);
782 aCropRectRel
.Move( -aAnimationBitmap
.maPositionPixel
.X(),
783 -aAnimationBitmap
.maPositionPixel
.Y() );
785 // cropping affects this frame, apply it then
786 // do _not_ apply enlargement, this is done below
787 ImplTransformBitmap( aAnimationBitmap
.maBitmapEx
, rAttr
, Size(), Size(),
788 aCropRectRel
, rDestSize
, false );
790 aAnim
.Replace( aAnimationBitmap
, nFrame
);
792 // else: bitmap completely within crop area,
793 // i.e. nothing is cropped away
796 // now, apply enlargement (if any) through global animation size
797 if( aCropLeftTop
.Width() < 0 ||
798 aCropLeftTop
.Height() < 0 ||
799 aCropRightBottom
.Width() < 0 ||
800 aCropRightBottom
.Height() < 0 )
802 Size
aNewSize( aAnim
.GetDisplaySizePixel() );
803 aNewSize
.AdjustWidth(aCropRightBottom
.Width() < 0 ? -aCropRightBottom
.Width() : 0 );
804 aNewSize
.AdjustWidth(aCropLeftTop
.Width() < 0 ? -aCropLeftTop
.Width() : 0 );
805 aNewSize
.AdjustHeight(aCropRightBottom
.Height() < 0 ? -aCropRightBottom
.Height() : 0 );
806 aNewSize
.AdjustHeight(aCropLeftTop
.Height() < 0 ? -aCropLeftTop
.Height() : 0 );
807 aAnim
.SetDisplaySizePixel( aNewSize
);
810 // if topleft has changed, we must move all frames to the
811 // right and bottom, resp.
812 if( aCropLeftTop
.Width() < 0 ||
813 aCropLeftTop
.Height() < 0 )
815 Point
aPosOffset( aCropLeftTop
.Width() < 0 ? -aCropLeftTop
.Width() : 0,
816 aCropLeftTop
.Height() < 0 ? -aCropLeftTop
.Height() : 0 );
818 for( size_t nFrame
=0; nFrame
<aAnim
.Count(); ++nFrame
)
820 AnimationBitmap
aAnimationBitmap( aAnim
.Get( nFrame
) );
822 aAnimationBitmap
.maPositionPixel
+= aPosOffset
;
824 aAnim
.Replace( aAnimationBitmap
, nFrame
);
828 aTransGraphic
= aAnim
;
832 ImplTransformBitmap( aBitmapEx
, rAttr
, aCropLeftTop
, aCropRightBottom
,
833 aCropRect
, rDestSize
, true );
835 aTransGraphic
= aBitmapEx
;
838 aTransGraphic
.SetPrefSize( rDestSize
);
839 aTransGraphic
.SetPrefMapMode( rDestMap
);
842 GraphicObject
aGrfObj( aTransGraphic
);
843 aTransGraphic
= aGrfObj
.GetTransformedGraphic( &rAttr
);
845 return aTransGraphic
;
848 Graphic
GraphicObject::GetTransformedGraphic( const GraphicAttr
* pAttr
) const
853 GraphicAttr
aAttr( pAttr
? *pAttr
: GetAttr() );
855 if (maGraphic
.IsSupportedGraphic())
857 if( aAttr
.IsSpecialDrawMode() || aAttr
.IsAdjusted() || aAttr
.IsMirrored() || aAttr
.IsRotated() || aAttr
.IsTransparent() )
859 if( GetType() == GraphicType::Bitmap
)
863 Animation
aAnimation( maGraphic
.GetAnimation() );
864 lclImplAdjust( aAnimation
, aAttr
, GraphicAdjustmentFlags::ALL
);
865 aAnimation
.SetLoopCount(maGraphic
.GetAnimationLoopCount());
866 aGraphic
= aAnimation
;
870 BitmapEx
aBmpEx( maGraphic
.GetBitmapEx() );
871 lclImplAdjust( aBmpEx
, aAttr
, GraphicAdjustmentFlags::ALL
);
877 GDIMetaFile
aMtf( maGraphic
.GetGDIMetaFile() );
878 lclImplAdjust( aMtf
, aAttr
, GraphicAdjustmentFlags::ALL
);
884 if( ( GetType() == GraphicType::Bitmap
) && IsAnimated() )
886 Animation
aAnimation( maGraphic
.GetAnimation() );
887 aAnimation
.SetLoopCount(maGraphic
.GetAnimationLoopCount());
888 aGraphic
= aAnimation
;
891 aGraphic
= maGraphic
;
898 bool GraphicObject::isGraphicObjectUniqueIdURL(OUString
const & rURL
)
900 const OUString
aPrefix("vnd.sun.star.GraphicObject:");
901 return rURL
.startsWith(aPrefix
);
904 // calculate scalings between real image size and logic object size. This
905 // is necessary since the crop values are relative to original bitmap size
906 basegfx::B2DVector
GraphicObject::calculateCropScaling(
912 double fBottomCrop
) const
914 const MapMode
aMapMode100thmm(MapUnit::Map100thMM
);
915 Size
aBitmapSize(GetPrefSize());
916 double fFactorX(1.0);
917 double fFactorY(1.0);
919 if(MapUnit::MapPixel
== GetPrefMapMode().GetMapUnit())
921 aBitmapSize
= Application::GetDefaultDevice()->PixelToLogic(aBitmapSize
, aMapMode100thmm
);
925 aBitmapSize
= OutputDevice::LogicToLogic(aBitmapSize
, GetPrefMapMode(), aMapMode100thmm
);
928 const double fDivX(aBitmapSize
.Width() - fLeftCrop
- fRightCrop
);
929 const double fDivY(aBitmapSize
.Height() - fTopCrop
- fBottomCrop
);
931 if(!basegfx::fTools::equalZero(fDivX
))
933 fFactorX
= fabs(fWidth
) / fDivX
;
936 if(!basegfx::fTools::equalZero(fDivY
))
938 fFactorY
= fabs(fHeight
) / fDivY
;
941 return basegfx::B2DVector(fFactorX
,fFactorY
);
945 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */