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 .
26 #define UINT64 USE_WIN_UINT64
27 #define INT64 USE_WIN_INT64
28 #define UINT32 USE_WIN_UINT32
29 #define INT32 USE_WIN_INT32
31 #include <tools/presys.h>
33 #pragma warning(push, 1)
39 #include <tools/postsys.h>
47 #include <com/sun/star/uno/Exception.hpp>
48 #include <com/sun/star/datatransfer/XTransferable.hpp>
49 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
50 #include <com/sun/star/graphic/GraphicProvider.hpp>
51 #include <com/sun/star/graphic/XGraphicProvider.hpp>
52 #include <com/sun/star/graphic/XGraphic.hpp>
53 #include <com/sun/star/io/XStream.hpp>
56 #include <osl/thread.h>
57 #include <vcl/gdimtf.hxx>
58 #include <vcl/graph.hxx>
59 #include <vcl/cvtgrf.hxx>
60 #include <vcl/outdev.hxx>
61 #include <vcl/virdev.hxx>
62 #include <vcl/bitmapex.hxx>
64 #include <tools/stream.hxx>
65 #include <tools/helpers.hxx>
66 #include <unotools/tempfile.hxx>
67 #include <unotools/ucbstreamhelper.hxx>
68 #include <unotools/streamwrap.hxx>
69 #include <comphelper/processfactory.hxx>
72 #include "sfx2/sfxresid.hxx"
73 #include "graphhelp.hxx"
76 using namespace ::com::sun::star
;
78 #define THUMBNAIL_RESOLUTION 256
80 //---------------------------------------------------------------
82 SvMemoryStream
* GraphicHelper::getFormatStrFromGDI_Impl( const GDIMetaFile
* pGDIMeta
, sal_uInt32 nFormat
)
84 SvMemoryStream
* pResult
= NULL
;
87 SvMemoryStream
* pStream
= new SvMemoryStream( 65535, 65535 );
90 Graphic
aGraph( *pGDIMeta
);
91 if ( GraphicConverter::Export( *pStream
, aGraph
, nFormat
) == 0 )
101 //---------------------------------------------------------------
103 void* GraphicHelper::getEnhMetaFileFromGDI_Impl( const GDIMetaFile
* pGDIMeta
)
105 (void)pGDIMeta
; // unused
106 void* pResult
= NULL
;
111 String aStr
= OUString(".emf");
112 ::utl::TempFile
aTempFile( OUString(),
117 OUString aMetaFile
= aTempFile
.GetFileName();
118 OUString aMetaURL
= aTempFile
.GetURL();
119 OString aWinFile
= OUStringToOString( aMetaFile
, osl_getThreadTextEncoding() );
121 SvStream
* pStream
= ::utl::UcbStreamHelper::CreateStream( aMetaURL
, STREAM_STD_READWRITE
);
124 Graphic
aGraph( *pGDIMeta
);
125 sal_Bool bFailed
= (sal_Bool
)GraphicConverter::Export( *pStream
, aGraph
, CVT_EMF
);
130 pResult
= GetEnhMetaFileA( aWinFile
.getStr() );
138 //---------------------------------------------------------------
140 void* GraphicHelper::getWinMetaFileFromGDI_Impl( const GDIMetaFile
* pGDIMeta
, const Size
& aMetaSize
)
142 (void)pGDIMeta
; // unused
143 (void)aMetaSize
; // unused
144 void* pResult
= NULL
;
149 SvMemoryStream
* pStream
= new SvMemoryStream( 65535, 65535 );
152 Graphic
aGraph( *pGDIMeta
);
153 sal_Bool bFailed
= (sal_Bool
)GraphicConverter::Export( *pStream
, aGraph
, CVT_WMF
);
157 sal_Int32 nLength
= pStream
->Seek( STREAM_SEEK_TO_END
);
160 HMETAFILE hMeta
= SetMetaFileBitsEx( nLength
- 22,
161 ( reinterpret_cast< const sal_uChar
*>( pStream
->GetData() ) ) + 22 );
165 HGLOBAL hMemory
= GlobalAlloc( GMEM_DDESHARE
| GMEM_MOVEABLE
, sizeof( METAFILEPICT
) );
169 METAFILEPICT
* pMF
= (METAFILEPICT
*)GlobalLock( hMemory
);
172 pMF
->mm
= MM_ANISOTROPIC
;
174 MapMode aMetaMode
= pGDIMeta
->GetPrefMapMode();
175 MapMode
aWinMode( MAP_100TH_MM
);
177 if ( aWinMode
== pGDIMeta
->GetPrefMapMode() )
179 pMF
->xExt
= aMetaSize
.Width();
180 pMF
->yExt
= aMetaSize
.Height();
184 Size aWinSize
= OutputDevice::LogicToLogic( Size( aMetaSize
.Width(), aMetaSize
.Height() ),
185 pGDIMeta
->GetPrefMapMode(),
187 pMF
->xExt
= aWinSize
.Width();
188 pMF
->yExt
= aWinSize
.Height();
191 GlobalUnlock( hMemory
);
192 pResult
= (void*)hMemory
;
195 DeleteMetaFile( hMeta
);
210 //---------------------------------------------------------------
212 sal_Bool
GraphicHelper::supportsMetaFileHandle_Impl()
221 //---------------------------------------------------------------
223 sal_Bool
GraphicHelper::mergeBitmaps_Impl( const BitmapEx
& rBmpEx
, const BitmapEx
& rOverlay
,
224 const Rectangle
& rOverlayRect
, BitmapEx
& rReturn
)
226 // the implementation is provided by KA
229 Rectangle
aBmpRect( aNullPt
, rBmpEx
.GetSizePixel() );
232 if( !rReturn
.IsEmpty() )
235 if( !rBmpEx
.IsEmpty() && aVDev
.SetOutputSizePixel( aBmpRect
.GetSize() ) )
237 Rectangle
aOverlayRect( rOverlayRect
);
239 aOverlayRect
.Intersection( aBmpRect
);
241 if( rOverlay
.IsEmpty() || rOverlayRect
.IsEmpty() )
245 aVDev
.DrawBitmap( aNullPt
, aVDev
.GetOutputSizePixel(), rBmpEx
.GetBitmap() );
246 aVDev
.DrawBitmapEx( aOverlayRect
.TopLeft(), aOverlayRect
.GetSize(), rOverlay
);
248 Bitmap
aBmp( aVDev
.GetBitmap( aNullPt
, aVDev
.GetOutputSizePixel() ) );
249 aBmp
.Convert( BMP_CONVERSION_24BIT
);
251 if( !rBmpEx
.IsTransparent() )
255 aVDev
.DrawBitmap( aNullPt
, aVDev
.GetOutputSizePixel(), rBmpEx
.GetMask() );
256 Bitmap
aOverlayMergeBmp( aVDev
.GetBitmap( aOverlayRect
.TopLeft(), aOverlayRect
.GetSize() ) );
258 if( rOverlay
.IsTransparent() )
259 aVDev
.DrawBitmap( aOverlayRect
.TopLeft(), aOverlayRect
.GetSize(), rOverlay
.GetMask() );
262 aVDev
.SetLineColor( COL_BLACK
);
263 aVDev
.SetFillColor( COL_BLACK
);
264 aVDev
.DrawRect( aOverlayRect
);
267 aOverlayMergeBmp
.CombineSimple( aVDev
.GetBitmap( aOverlayRect
.TopLeft(), aOverlayRect
.GetSize() ), BMP_COMBINE_AND
);
268 aVDev
.DrawBitmap( aOverlayRect
.TopLeft(), aOverlayRect
.GetSize(), aOverlayMergeBmp
);
269 rReturn
= BitmapEx( aBmp
, aVDev
.GetBitmap( aNullPt
, aVDev
.GetOutputSizePixel() ) );
274 return !rReturn
.IsEmpty();
278 //---------------------------------------------------------------
280 sal_Bool
GraphicHelper::createThumb_Impl( const GDIMetaFile
& rMtf
,
281 sal_uInt32 nMaximumExtent
,
283 const BitmapEx
* pOverlay
,
284 const Rectangle
* pOverlayRect
)
286 // the implementation is provided by KA
288 // initialization seems to be complicated but is used to avoid rounding errors
291 const Point
aTLPix( aVDev
.LogicToPixel( aNullPt
, rMtf
.GetPrefMapMode() ) );
292 const Point
aBRPix( aVDev
.LogicToPixel( Point( rMtf
.GetPrefSize().Width() - 1, rMtf
.GetPrefSize().Height() - 1 ), rMtf
.GetPrefMapMode() ) );
293 Size
aDrawSize( aVDev
.LogicToPixel( rMtf
.GetPrefSize(), rMtf
.GetPrefMapMode() ) );
294 Size
aSizePix( labs( aBRPix
.X() - aTLPix
.X() ) + 1, labs( aBRPix
.Y() - aTLPix
.Y() ) + 1 );
296 if ( !rBmpEx
.IsEmpty() )
299 // determine size that has the same aspect ratio as image size and
300 // fits into the rectangle determined by nMaximumExtent
301 if ( aSizePix
.Width() && aSizePix
.Height() &&
302 ( sal::static_int_cast
<sal_uInt32
>(aSizePix
.Width()) > nMaximumExtent
||
303 sal::static_int_cast
<sal_uInt32
>(aSizePix
.Height()) > nMaximumExtent
) )
305 const Size
aOldSizePix( aSizePix
);
306 double fWH
= static_cast< double >( aSizePix
.Width() ) / aSizePix
.Height();
310 aSizePix
.Width() = FRound( nMaximumExtent
* fWH
);
311 aSizePix
.Height() = nMaximumExtent
;
315 aSizePix
.Width() = nMaximumExtent
;
316 aSizePix
.Height() = FRound( nMaximumExtent
/ fWH
);
319 aDrawSize
.Width() = FRound( ( static_cast< double >( aDrawSize
.Width() ) * aSizePix
.Width() ) / aOldSizePix
.Width() );
320 aDrawSize
.Height() = FRound( ( static_cast< double >( aDrawSize
.Height() ) * aSizePix
.Height() ) / aOldSizePix
.Height() );
325 Rectangle aOverlayRect
;
327 // calculate addigtional positions and sizes if an overlay image is used
330 aFullSize
= Size( nMaximumExtent
, nMaximumExtent
);
331 aOverlayRect
= Rectangle( aNullPt
, aFullSize
);
333 aOverlayRect
.Intersection( pOverlayRect
? *pOverlayRect
: Rectangle( aNullPt
, pOverlay
->GetSizePixel() ) );
335 if ( !aOverlayRect
.IsEmpty() )
336 aBackPosPix
= Point( ( nMaximumExtent
- aSizePix
.Width() ) >> 1, ( nMaximumExtent
- aSizePix
.Height() ) >> 1 );
342 aFullSize
= aSizePix
;
346 // draw image(s) into VDev and get resulting image
347 if ( aVDev
.SetOutputSizePixel( aFullSize
) )
349 // draw metafile into VDev
350 const_cast< GDIMetaFile
& >( rMtf
).WindStart();
351 const_cast< GDIMetaFile
& >( rMtf
).Play( &aVDev
, aBackPosPix
, aDrawSize
);
353 // draw overlay if necessary
355 aVDev
.DrawBitmapEx( aOverlayRect
.TopLeft(), aOverlayRect
.GetSize(), *pOverlay
);
358 Bitmap
aBmp( aVDev
.GetBitmap( aNullPt
, aVDev
.GetOutputSizePixel() ) );
360 // assure that we have a true color image
361 if ( aBmp
.GetBitCount() != 24 )
362 aBmp
.Convert( BMP_CONVERSION_24BIT
);
364 rBmpEx
= BitmapEx( aBmp
);
367 return !rBmpEx
.IsEmpty();
370 //---------------------------------------------------------------
372 sal_Bool
GraphicHelper::getThumbnailFormatFromGDI_Impl( GDIMetaFile
* pMetaFile
,
374 const uno::Reference
< io::XStream
>& xStream
)
376 sal_Bool bResult
= sal_False
;
377 SvStream
* pStream
= NULL
;
380 pStream
= ::utl::UcbStreamHelper::CreateStream( xStream
);
382 if ( pMetaFile
&& pStream
&& !pStream
->GetError() )
384 BitmapEx aResultBitmap
;
385 BitmapEx
* pSignatureBitmap
= NULL
;
388 pSignatureBitmap
= new BitmapEx( SfxResId( BMP_SIGNATURE
) );
390 bResult
= createThumb_Impl( *pMetaFile
,
391 THUMBNAIL_RESOLUTION
,
395 bResult
= ( !aResultBitmap
.IsEmpty()
396 && GraphicConverter::Export( *pStream
, aResultBitmap
, CVT_PNG
) == 0
397 && ( pStream
->Flush(), !pStream
->GetError() ) );
399 if ( pSignatureBitmap
)
400 delete pSignatureBitmap
;
408 //---------------------------------------------------------------
410 sal_Bool
GraphicHelper::getSignedThumbnailFormatFromBitmap_Impl( const BitmapEx
& aBitmap
,
411 const uno::Reference
< io::XStream
>& xStream
)
413 sal_Bool bResult
= sal_False
;
414 SvStream
* pStream
= NULL
;
417 pStream
= ::utl::UcbStreamHelper::CreateStream( xStream
);
419 if ( pStream
&& !pStream
->GetError() )
421 BitmapEx aResultBitmap
;
422 BitmapEx
aSignatureBitmap( SfxResId( BMP_SIGNATURE
) );
424 bResult
= mergeBitmaps_Impl( aBitmap
,
426 Rectangle( Point(), aBitmap
.GetSizePixel() ),
431 bResult
= ( !aResultBitmap
.IsEmpty()
432 && GraphicConverter::Export( *pStream
, aResultBitmap
, CVT_PNG
) == 0
433 && ( pStream
->Flush(), !pStream
->GetError() ) );
442 //---------------------------------------------------------------
444 sal_Bool
GraphicHelper::getThumbnailReplacement_Impl( sal_Int32 nResID
, const uno::Reference
< io::XStream
>& xStream
)
446 sal_Bool bResult
= sal_False
;
447 if ( nResID
&& xStream
.is() )
449 uno::Reference
< uno::XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
452 uno::Reference
< graphic::XGraphicProvider
> xGraphProvider(graphic::GraphicProvider::create(xContext
));
453 OUString
aURL("private:resource/sfx/bitmapex/");
454 aURL
+= OUString::valueOf( nResID
);
456 uno::Sequence
< beans::PropertyValue
> aMediaProps( 1 );
457 aMediaProps
[0].Name
= "URL";
458 aMediaProps
[0].Value
<<= aURL
;
460 uno::Reference
< graphic::XGraphic
> xGraphic
= xGraphProvider
->queryGraphic( aMediaProps
);
463 uno::Sequence
< beans::PropertyValue
> aStoreProps( 2 );
464 aStoreProps
[0].Name
= "OutputStream";
465 aStoreProps
[0].Value
<<= xStream
;
466 aStoreProps
[1].Name
= "MimeType";
467 aStoreProps
[1].Value
<<= OUString("image/png");
469 xGraphProvider
->storeGraphic( xGraphic
, aStoreProps
);
473 catch(const uno::Exception
&)
481 //---------------------------------------------------------------
483 sal_uInt16
GraphicHelper::getThumbnailReplacementIDByFactoryName_Impl( const OUString
& aFactoryShortName
, sal_Bool
/*bIsTemplate*/ )
485 sal_uInt16 nResult
= 0;
487 if ( aFactoryShortName
== "scalc" )
489 nResult
= BMP_128X128_CALC_DOC
;
491 else if ( aFactoryShortName
== "sdraw" )
493 nResult
= BMP_128X128_DRAW_DOC
;
495 else if ( aFactoryShortName
== "simpress" )
497 nResult
= BMP_128X128_IMPRESS_DOC
;
499 else if ( aFactoryShortName
== "smath" )
501 nResult
= BMP_128X128_MATH_DOC
;
503 else if ( aFactoryShortName
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "swriter" ) ) || aFactoryShortName
.startsWith("swriter/") )
505 nResult
= BMP_128X128_WRITER_DOC
;
511 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */