1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: graph.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
33 #include <vcl/impgraph.hxx>
34 #include <vcl/outdev.hxx>
35 #include <vcl/svapp.hxx>
36 #include <vcl/graph.hxx>
37 #include <comphelper/processfactory.hxx>
38 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
39 #include <com/sun/star/graphic/XGraphicProvider.hpp>
40 #include <com/sun/star/lang/XUnoTunnel.hpp>
41 #include <com/sun/star/lang/XTypeProvider.hpp>
42 #include <com/sun/star/graphic/XGraphic.hpp>
44 // -----------------------
45 // - Compression defines -
46 // -----------------------
48 #define COMPRESS_OWN ('S'|('D'<<8UL))
49 #define COMPRESS_NONE ( 0UL )
52 #define BITFIELDS ( 3UL )
53 #define ZCOMPRESS ( COMPRESS_OWN | 0x01000000UL ) /* == 'SD01' (binary) */
55 using namespace ::com::sun::star
;
57 // -----------------------
58 // - Default-Drawmethode -
59 // -----------------------
61 static void ImplDrawDefault( OutputDevice
* pOutDev
, const UniString
* pText
,
62 Font
* pFont
, const Bitmap
* pBitmap
, const BitmapEx
* pBitmapEx
,
63 const Point
& rDestPt
, const Size
& rDestSize
)
65 USHORT nPixel
= (USHORT
) pOutDev
->PixelToLogic( Size( 1, 1 ) ).Width();
66 USHORT nPixelWidth
= nPixel
;
67 Point
aPoint( rDestPt
.X() + nPixelWidth
, rDestPt
.Y() + nPixelWidth
);
68 Size
aSize( rDestSize
.Width() - ( nPixelWidth
<< 1 ), rDestSize
.Height() - ( nPixelWidth
<< 1 ) );
69 BOOL bFilled
= ( pBitmap
!= NULL
|| pBitmapEx
!= NULL
|| pFont
!= NULL
);
70 Rectangle
aBorderRect( aPoint
, aSize
);
74 pOutDev
->SetFillColor();
76 // Auf dem Drucker ein schwarzes Rechteck und auf dem Bildschirm eins mit 3D-Effekt
77 if ( pOutDev
->GetOutDevType() == OUTDEV_PRINTER
)
78 pOutDev
->SetLineColor( COL_BLACK
);
81 aBorderRect
.Left() += nPixel
;
82 aBorderRect
.Top() += nPixel
;
84 pOutDev
->SetLineColor( COL_LIGHTGRAY
);
85 pOutDev
->DrawRect( aBorderRect
);
87 aBorderRect
.Left() -= nPixel
;
88 aBorderRect
.Top() -= nPixel
;
89 aBorderRect
.Right() -= nPixel
;
90 aBorderRect
.Bottom() -= nPixel
;
91 pOutDev
->SetLineColor( COL_GRAY
);
94 pOutDev
->DrawRect( aBorderRect
);
96 aPoint
.X() += nPixelWidth
+ 2*nPixel
;
97 aPoint
.Y() += nPixelWidth
+ 2*nPixel
;
98 aSize
.Width() -= 2*nPixelWidth
+ 4*nPixel
;
99 aSize
.Height() -= 2*nPixelWidth
+ 4*nPixel
;
101 if( aSize
.Width() > 0 && aSize
.Height() > 0
102 && ( ( pBitmap
&& !!*pBitmap
) || ( pBitmapEx
&& !!*pBitmapEx
) ) )
104 Size
aBitmapSize( pOutDev
->PixelToLogic( pBitmap
? pBitmap
->GetSizePixel() : pBitmapEx
->GetSizePixel() ) );
106 if( aSize
.Height() > aBitmapSize
.Height() && aSize
.Width() > aBitmapSize
.Width() )
109 pOutDev
->DrawBitmap( aPoint
, *pBitmap
);
111 pOutDev
->DrawBitmapEx( aPoint
, *pBitmapEx
);
112 aPoint
.X() += aBitmapSize
.Width() + 2*nPixel
;
113 aSize
.Width() -= aBitmapSize
.Width() + 2*nPixel
;
117 if ( aSize
.Width() > 0 && aSize
.Height() > 0 && pFont
&& pText
&& pText
->Len()
118 && !(!pOutDev
->IsOutputEnabled() /*&& pOutDev->GetConnectMetaFile() */) )
120 MapMode
aMapMode( MAP_POINT
);
121 Size aSz
= pOutDev
->LogicToLogic( Size( 0, 12 ), &aMapMode
, NULL
);
122 long nThreshold
= aSz
.Height() / 2;
123 long nStep
= nThreshold
/ 3;
126 nStep
= aSz
.Height() - nThreshold
;
128 for(;; aSz
.Height() -= nStep
)
130 pFont
->SetSize( aSz
);
131 pOutDev
->SetFont( *pFont
);
133 long nTextHeight
= pOutDev
->GetTextHeight();
134 long nTextWidth
= pOutDev
->GetTextWidth( *pText
);
137 // Die N"aherung ber"ucksichtigt keine Ungenauigkeiten durch
139 long nLines
= aSize
.Height() / nTextHeight
;
140 long nWidth
= aSize
.Width() * nLines
; // N"aherung!!!
142 if ( nTextWidth
<= nWidth
|| aSz
.Height() <= nThreshold
)
147 while( nStart
< pText
->Len() && pText
->GetChar( nStart
) == ' ' )
149 while( nStart
+nLen
< pText
->Len() && pText
->GetChar( nStart
+nLen
) != ' ' )
151 while( nStart
< pText
->Len() && nLines
-- )
156 while ( nStart
+nNext
< pText
->Len() && pText
->GetChar( nStart
+nNext
) == ' ' )
158 while ( nStart
+nNext
< pText
->Len() && pText
->GetChar( nStart
+nNext
) != ' ' )
160 nTextWidth
= pOutDev
->GetTextWidth( *pText
, nStart
, nNext
);
161 if ( nTextWidth
> aSize
.Width() )
165 while ( nStart
+nNext
< pText
->Len() );
168 nTextWidth
= pOutDev
->GetTextWidth( *pText
, nStart
, n
);
169 while( nTextWidth
> aSize
.Width() )
170 nTextWidth
= pOutDev
->GetTextWidth( *pText
, nStart
, --n
);
171 pOutDev
->DrawText( aPoint
, *pText
, nStart
, n
);
173 aPoint
.Y() += nTextHeight
;
174 nStart
= sal::static_int_cast
<USHORT
>(nStart
+ nLen
);
176 while( nStart
< pText
->Len() && pText
->GetChar( nStart
) == ' ' )
190 // Falls die Default-Graphik keinen Inhalt hat,
191 // malen wir ein rotes Kreuz
194 aBorderRect
.Left()++;
196 aBorderRect
.Right()--;
197 aBorderRect
.Bottom()--;
199 pOutDev
->SetLineColor( COL_LIGHTRED
);
200 pOutDev
->DrawLine( aBorderRect
.TopLeft(), aBorderRect
.BottomRight() );
201 pOutDev
->DrawLine( aBorderRect
.TopRight(), aBorderRect
.BottomLeft() );
211 TYPEINIT1_AUTOFACTORY( Graphic
, SvDataCopyStream
);
213 // ------------------------------------------------------------------------
217 mpImpGraphic
= new ImpGraphic
;
220 // ------------------------------------------------------------------------
222 Graphic::Graphic( const Graphic
& rGraphic
) :
225 if( rGraphic
.IsAnimated() )
226 mpImpGraphic
= new ImpGraphic( *rGraphic
.mpImpGraphic
);
229 mpImpGraphic
= rGraphic
.mpImpGraphic
;
230 mpImpGraphic
->mnRefCount
++;
234 // ------------------------------------------------------------------------
236 Graphic::Graphic( const Bitmap
& rBmp
)
238 mpImpGraphic
= new ImpGraphic( rBmp
);
241 // ------------------------------------------------------------------------
243 Graphic::Graphic( const BitmapEx
& rBmpEx
)
245 mpImpGraphic
= new ImpGraphic( rBmpEx
);
248 // ------------------------------------------------------------------------
250 Graphic::Graphic( const Animation
& rAnimation
)
252 mpImpGraphic
= new ImpGraphic( rAnimation
);
255 // ------------------------------------------------------------------------
257 Graphic::Graphic( const GDIMetaFile
& rMtf
)
259 mpImpGraphic
= new ImpGraphic( rMtf
);
262 // ------------------------------------------------------------------------
264 Graphic::Graphic( const ::com::sun::star::uno::Reference
< ::com::sun::star::graphic::XGraphic
>& rxGraphic
)
266 uno::Reference
< lang::XUnoTunnel
> xTunnel( rxGraphic
, uno::UNO_QUERY
);
267 uno::Reference
< lang::XTypeProvider
> xProv( rxGraphic
, uno::UNO_QUERY
);
268 const ::Graphic
* pGraphic
= ( ( xTunnel
.is() && xProv
.is() ) ?
269 reinterpret_cast< ::Graphic
* >( xTunnel
->getSomething( xProv
->getImplementationId() ) ) :
274 if( pGraphic
->IsAnimated() )
275 mpImpGraphic
= new ImpGraphic( *pGraphic
->mpImpGraphic
);
278 mpImpGraphic
= pGraphic
->mpImpGraphic
;
279 mpImpGraphic
->mnRefCount
++;
283 mpImpGraphic
= new ImpGraphic
;
286 // ------------------------------------------------------------------------
290 if( mpImpGraphic
->mnRefCount
== 1UL )
293 mpImpGraphic
->mnRefCount
--;
296 // ------------------------------------------------------------------------
298 void Graphic::ImplTestRefCount()
300 if( mpImpGraphic
->mnRefCount
> 1UL )
302 mpImpGraphic
->mnRefCount
--;
303 mpImpGraphic
= new ImpGraphic( *mpImpGraphic
);
307 // ------------------------------------------------------------------------
309 Graphic
& Graphic::operator=( const Graphic
& rGraphic
)
311 if( &rGraphic
!= this )
313 if( rGraphic
.IsAnimated() )
315 if( mpImpGraphic
->mnRefCount
== 1UL )
318 mpImpGraphic
->mnRefCount
--;
320 mpImpGraphic
= new ImpGraphic( *rGraphic
.mpImpGraphic
);
324 rGraphic
.mpImpGraphic
->mnRefCount
++;
326 if( mpImpGraphic
->mnRefCount
== 1UL )
329 mpImpGraphic
->mnRefCount
--;
331 mpImpGraphic
= rGraphic
.mpImpGraphic
;
338 // ------------------------------------------------------------------------
340 BOOL
Graphic::operator==( const Graphic
& rGraphic
) const
342 return( *mpImpGraphic
== *rGraphic
.mpImpGraphic
);
345 // ------------------------------------------------------------------------
347 BOOL
Graphic::operator!=( const Graphic
& rGraphic
) const
349 return( *mpImpGraphic
!= *rGraphic
.mpImpGraphic
);
352 // ------------------------------------------------------------------------
354 BOOL
Graphic::operator!() const
356 return( GRAPHIC_NONE
== mpImpGraphic
->ImplGetType() );
359 // ------------------------------------------------------------------------
361 void Graphic::Load( SvStream
& rIStm
)
366 // ------------------------------------------------------------------------
368 void Graphic::Save( SvStream
& rOStm
)
373 // ------------------------------------------------------------------------
375 void Graphic::Assign( const SvDataCopyStream
& rCopyStream
)
377 *this = (const Graphic
& ) rCopyStream
;
380 // ------------------------------------------------------------------------
382 void Graphic::Clear()
385 mpImpGraphic
->ImplClear();
388 // ------------------------------------------------------------------------
390 GraphicType
Graphic::GetType() const
392 return mpImpGraphic
->ImplGetType();
395 // ------------------------------------------------------------------------
397 void Graphic::SetDefaultType()
400 mpImpGraphic
->ImplSetDefaultType();
403 // ------------------------------------------------------------------------
405 BOOL
Graphic::IsSupportedGraphic() const
407 return mpImpGraphic
->ImplIsSupportedGraphic();
410 // ------------------------------------------------------------------------
412 BOOL
Graphic::IsTransparent() const
414 return mpImpGraphic
->ImplIsTransparent();
417 // ------------------------------------------------------------------------
419 BOOL
Graphic::IsAlpha() const
421 return mpImpGraphic
->ImplIsAlpha();
424 // ------------------------------------------------------------------------
426 BOOL
Graphic::IsAnimated() const
428 return mpImpGraphic
->ImplIsAnimated();
431 // ------------------------------------------------------------------------
433 Bitmap
Graphic::GetBitmap(const GraphicConversionParameters
& rParameters
) const
435 return mpImpGraphic
->ImplGetBitmap(rParameters
);
438 // ------------------------------------------------------------------------
440 BitmapEx
Graphic::GetBitmapEx(const GraphicConversionParameters
& rParameters
) const
442 return mpImpGraphic
->ImplGetBitmapEx(rParameters
);
445 // ------------------------------------------------------------------------
447 Animation
Graphic::GetAnimation() const
449 return mpImpGraphic
->ImplGetAnimation();
452 // ------------------------------------------------------------------------
454 const GDIMetaFile
& Graphic::GetGDIMetaFile() const
456 return mpImpGraphic
->ImplGetGDIMetaFile();
459 // ------------------------------------------------------------------------
461 uno::Reference
< graphic::XGraphic
> Graphic::GetXGraphic() const
463 uno::Reference
< graphic::XGraphic
> xRet
;
465 if( GetType() != GRAPHIC_NONE
)
467 uno::Reference
< lang::XMultiServiceFactory
> xMSF( ::comphelper::getProcessServiceFactory() );
471 uno::Reference
< graphic::XGraphicProvider
> xProv( xMSF
->createInstance(
472 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.graphic.GraphicProvider" ) ) ),
477 uno::Sequence
< beans::PropertyValue
> aLoadProps( 1 );
478 ::rtl::OUString
aURL( RTL_CONSTASCII_USTRINGPARAM( "private:memorygraphic/" ) );
480 aLoadProps
[ 0 ].Name
= ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "URL" ) );
481 aLoadProps
[ 0 ].Value
<<= ( aURL
+= ::rtl::OUString::valueOf( reinterpret_cast< sal_Int64
>( this ) ) );
483 xRet
= xProv
->queryGraphic( aLoadProps
);
491 // ------------------------------------------------------------------------
493 Size
Graphic::GetPrefSize() const
495 return mpImpGraphic
->ImplGetPrefSize();
498 // ------------------------------------------------------------------------
500 void Graphic::SetPrefSize( const Size
& rPrefSize
)
503 mpImpGraphic
->ImplSetPrefSize( rPrefSize
);
506 // ------------------------------------------------------------------------
508 MapMode
Graphic::GetPrefMapMode() const
510 return mpImpGraphic
->ImplGetPrefMapMode();
513 // ------------------------------------------------------------------------
515 void Graphic::SetPrefMapMode( const MapMode
& rPrefMapMode
)
518 mpImpGraphic
->ImplSetPrefMapMode( rPrefMapMode
);
521 // ------------------------------------------------------------------
523 Size
Graphic::GetSizePixel( const OutputDevice
* pRefDevice
) const
527 if( GRAPHIC_BITMAP
== mpImpGraphic
->ImplGetType() )
528 aRet
= mpImpGraphic
->ImplGetBitmapEx(GraphicConversionParameters()).GetSizePixel();
530 aRet
= ( pRefDevice
? pRefDevice
: Application::GetDefaultDevice() )->LogicToPixel( GetPrefSize(), GetPrefMapMode() );
535 // ------------------------------------------------------------------
537 ULONG
Graphic::GetSizeBytes() const
539 return mpImpGraphic
->ImplGetSizeBytes();
542 // ------------------------------------------------------------------------
544 void Graphic::Draw( OutputDevice
* pOutDev
, const Point
& rDestPt
) const
546 mpImpGraphic
->ImplDraw( pOutDev
, rDestPt
);
549 // ------------------------------------------------------------------------
551 void Graphic::Draw( OutputDevice
* pOutDev
,
552 const Point
& rDestPt
, const Size
& rDestSz
) const
554 if( GRAPHIC_DEFAULT
== mpImpGraphic
->ImplGetType() )
555 ImplDrawDefault( pOutDev
, NULL
, NULL
, NULL
, NULL
, rDestPt
, rDestSz
);
557 mpImpGraphic
->ImplDraw( pOutDev
, rDestPt
, rDestSz
);
560 // ------------------------------------------------------------------------
562 void Graphic::Draw( OutputDevice
* pOutDev
, const String
& rText
,
563 Font
& rFont
, const Bitmap
& rBitmap
,
564 const Point
& rDestPt
, const Size
& rDestSz
)
566 ImplDrawDefault( pOutDev
, &rText
, &rFont
, &rBitmap
, NULL
, rDestPt
, rDestSz
);
569 // ------------------------------------------------------------------------
571 void Graphic::DrawEx( OutputDevice
* pOutDev
, const String
& rText
,
572 Font
& rFont
, const BitmapEx
& rBitmap
,
573 const Point
& rDestPt
, const Size
& rDestSz
)
575 ImplDrawDefault( pOutDev
, &rText
, &rFont
, NULL
, &rBitmap
, rDestPt
, rDestSz
);
578 // ------------------------------------------------------------------------
580 void Graphic::StartAnimation( OutputDevice
* pOutDev
, const Point
& rDestPt
, long nExtraData
,
581 OutputDevice
* pFirstFrameOutDev
)
584 mpImpGraphic
->ImplStartAnimation( pOutDev
, rDestPt
, nExtraData
, pFirstFrameOutDev
);
587 // ------------------------------------------------------------------------
589 void Graphic::StartAnimation( OutputDevice
* pOutDev
, const Point
& rDestPt
,
590 const Size
& rDestSz
, long nExtraData
,
591 OutputDevice
* pFirstFrameOutDev
)
594 mpImpGraphic
->ImplStartAnimation( pOutDev
, rDestPt
, rDestSz
, nExtraData
, pFirstFrameOutDev
);
597 // ------------------------------------------------------------------------
599 void Graphic::StopAnimation( OutputDevice
* pOutDev
, long nExtraData
)
602 mpImpGraphic
->ImplStopAnimation( pOutDev
, nExtraData
);
605 // ------------------------------------------------------------------------
607 void Graphic::SetAnimationNotifyHdl( const Link
& rLink
)
609 mpImpGraphic
->ImplSetAnimationNotifyHdl( rLink
);
612 // ------------------------------------------------------------------------
614 Link
Graphic::GetAnimationNotifyHdl() const
616 return mpImpGraphic
->ImplGetAnimationNotifyHdl();
619 // ------------------------------------------------------------------------
621 ULONG
Graphic::GetAnimationLoopCount() const
623 return mpImpGraphic
->ImplGetAnimationLoopCount();
626 // ------------------------------------------------------------------------
628 void Graphic::ResetAnimationLoopCount()
630 mpImpGraphic
->ImplResetAnimationLoopCount();
633 // ------------------------------------------------------------------------
635 List
* Graphic::GetAnimationInfoList() const
637 return mpImpGraphic
->ImplGetAnimationInfoList();
640 // ------------------------------------------------------------------------
642 GraphicReader
* Graphic::GetContext()
644 return mpImpGraphic
->ImplGetContext();
647 // ------------------------------------------------------------------------
649 void Graphic::SetContext( GraphicReader
* pReader
)
651 mpImpGraphic
->ImplSetContext( pReader
);
654 // ------------------------------------------------------------------------
656 USHORT
Graphic::GetGraphicsCompressMode( SvStream
& rIStm
)
658 const ULONG nPos
= rIStm
.Tell();
659 const USHORT nOldFormat
= rIStm
.GetNumberFormatInt();
662 USHORT nCompressMode
= COMPRESSMODE_NONE
;
664 rIStm
.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN
);
668 // is it a swapped graphic with a bitmap?
669 rIStm
.SeekRel( (nTmp32
== (UINT32
) GRAPHIC_BITMAP
) ? 40 : -4 );
671 // try to read bitmap id
674 // check id of BitmapFileHeader
675 if( 0x4D42 == nTmp16
)
677 // seek to compress field of BitmapInfoHeader
681 // Compare with our own compressmode
682 if( ZCOMPRESS
== nTmp32
)
683 nCompressMode
= COMPRESSMODE_ZBITMAP
;
686 rIStm
.SetNumberFormatInt( nOldFormat
);
689 return nCompressMode
;
692 // ------------------------------------------------------------------------
694 void Graphic::SetDocFileName( const String
& rName
, ULONG nFilePos
)
696 mpImpGraphic
->ImplSetDocFileName( rName
, nFilePos
);
699 // ------------------------------------------------------------------------
701 const String
& Graphic::GetDocFileName() const
703 return mpImpGraphic
->ImplGetDocFileName();
706 // ------------------------------------------------------------------------
708 ULONG
Graphic::GetDocFilePos() const
710 return mpImpGraphic
->ImplGetDocFilePos();
713 // ------------------------------------------------------------------------
715 BOOL
Graphic::ReadEmbedded( SvStream
& rIStream
, BOOL bSwap
)
718 return mpImpGraphic
->ImplReadEmbedded( rIStream
, bSwap
);
721 // ------------------------------------------------------------------------
723 BOOL
Graphic::WriteEmbedded( SvStream
& rOStream
)
726 return mpImpGraphic
->ImplWriteEmbedded( rOStream
);
729 // ------------------------------------------------------------------------
731 BOOL
Graphic::SwapOut()
734 return mpImpGraphic
->ImplSwapOut();
737 // ------------------------------------------------------------------------
739 BOOL
Graphic::SwapOut( SvStream
* pOStream
)
742 return mpImpGraphic
->ImplSwapOut( pOStream
);
745 // ------------------------------------------------------------------------
747 BOOL
Graphic::SwapIn()
750 return mpImpGraphic
->ImplSwapIn();
753 // ------------------------------------------------------------------------
755 BOOL
Graphic::SwapIn( SvStream
* pStrm
)
758 return mpImpGraphic
->ImplSwapIn( pStrm
);
761 // ------------------------------------------------------------------------
763 BOOL
Graphic::IsSwapOut() const
765 return mpImpGraphic
->ImplIsSwapOut();
768 // ------------------------------------------------------------------------
770 void Graphic::SetLink( const GfxLink
& rGfxLink
)
773 mpImpGraphic
->ImplSetLink( rGfxLink
);
776 // ------------------------------------------------------------------------
778 GfxLink
Graphic::GetLink() const
780 return mpImpGraphic
->ImplGetLink();
783 // ------------------------------------------------------------------------
785 BOOL
Graphic::IsLink() const
787 return mpImpGraphic
->ImplIsLink();
790 // ------------------------------------------------------------------------
792 ULONG
Graphic::GetChecksum() const
794 return mpImpGraphic
->ImplGetChecksum();
797 // ------------------------------------------------------------------------
799 BOOL
Graphic::ExportNative( SvStream
& rOStream
) const
801 return mpImpGraphic
->ImplExportNative( rOStream
);
804 // ------------------------------------------------------------------------
806 SvStream
& operator>>( SvStream
& rIStream
, Graphic
& rGraphic
)
808 rGraphic
.ImplTestRefCount();
809 return rIStream
>> *rGraphic
.mpImpGraphic
;
812 // ------------------------------------------------------------------------
814 SvStream
& operator<<( SvStream
& rOStream
, const Graphic
& rGraphic
)
816 return rOStream
<< *rGraphic
.mpImpGraphic
;