xref: /trunk/main/sfx2/source/doc/graphhelp.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sfx2.hxx"
30 
31 #ifdef WNT
32 
33 #undef WB_LEFT
34 #undef WB_RIGHT
35 
36 #define UINT64 USE_WIN_UINT64
37 #define INT64 USE_WIN_INT64
38 #define UINT32 USE_WIN_UINT32
39 #define INT32 USE_WIN_INT32
40 
41 #include <tools/presys.h>
42 #if defined _MSC_VER
43 #pragma warning(push, 1)
44 #endif
45 #include <windows.h>
46 #if defined _MSC_VER
47 #pragma warning(pop)
48 #endif
49 #include <tools/postsys.h>
50 
51 #undef UINT64
52 #undef INT64
53 #undef UINT32
54 #undef INT32
55 
56 #endif
57 #include <com/sun/star/uno/Exception.hpp>
58 #include <com/sun/star/datatransfer/XTransferable.hpp>
59 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
60 #include <com/sun/star/graphic/XGraphicProvider.hpp>
61 #include <com/sun/star/graphic/XGraphic.hpp>
62 #include <com/sun/star/io/XStream.hpp>
63 
64 
65 #include <osl/thread.h>
66 #include <vcl/gdimtf.hxx>
67 #include <vcl/graph.hxx>
68 #include <vcl/cvtgrf.hxx>
69 #include <vcl/outdev.hxx>
70 #include <vcl/virdev.hxx>
71 #include <vcl/bitmapex.hxx>
72 #include <vcl/salbtype.hxx>
73 
74 #include <tools/stream.hxx>
75 #include <unotools/tempfile.hxx>
76 #include <unotools/ucbstreamhelper.hxx>
77 #include <unotools/streamwrap.hxx>
78 #include <comphelper/processfactory.hxx>
79 
80 
81 #include "sfx2/sfxresid.hxx"
82 #include "graphhelp.hxx"
83 #include "doc.hrc"
84 
85 using namespace ::com::sun::star;
86 
87 #define THUMBNAIL_RESOLUTION 256
88 
89 //---------------------------------------------------------------
90 // static
91 SvMemoryStream* GraphicHelper::getFormatStrFromGDI_Impl( const GDIMetaFile* pGDIMeta, sal_uInt32 nFormat )
92 {
93 	SvMemoryStream* pResult = NULL;
94 	if ( pGDIMeta )
95 	{
96 		SvMemoryStream* pStream = new SvMemoryStream( 65535, 65535 );
97 		if ( pStream )
98 		{
99 			Graphic aGraph( *pGDIMeta );
100 			if ( GraphicConverter::Export( *pStream, aGraph, nFormat ) == 0 )
101 				pResult = pStream;
102 			else
103 				delete pStream;
104 		}
105 	}
106 
107 	return pResult;
108 }
109 
110 //---------------------------------------------------------------
111 // static
112 void* GraphicHelper::getEnhMetaFileFromGDI_Impl( const GDIMetaFile* pGDIMeta )
113 {
114     (void)pGDIMeta;  // unused
115 	void* pResult = NULL;
116 
117 #ifdef WNT
118 	if ( pGDIMeta )
119 	{
120 		String aStr = ::rtl::OUString::createFromAscii( ".emf" );
121 		::utl::TempFile aTempFile( ::rtl::OUString(),
122 								   &aStr,
123 								   NULL,
124 								   sal_False );
125 
126 		::rtl::OUString aMetaFile = aTempFile.GetFileName();
127 		::rtl::OUString aMetaURL = aTempFile.GetURL();
128 		::rtl::OString aWinFile = ::rtl::OUStringToOString( aMetaFile, osl_getThreadTextEncoding() );
129 
130 		SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( aMetaURL, STREAM_STD_READWRITE );
131 		if ( pStream )
132 		{
133 			Graphic aGraph( *pGDIMeta );
134 			sal_Bool bFailed = (sal_Bool)GraphicConverter::Export( *pStream, aGraph, CVT_EMF );
135 			pStream->Flush();
136 			delete pStream;
137 
138 			if ( !bFailed )
139 				pResult = GetEnhMetaFileA( aWinFile.getStr() );
140 		}
141 	}
142 #endif
143 
144 	return pResult;
145 }
146 
147 //---------------------------------------------------------------
148 // static
149 void* GraphicHelper::getWinMetaFileFromGDI_Impl( const GDIMetaFile* pGDIMeta, const Size& aMetaSize )
150 {
151     (void)pGDIMeta;  // unused
152     (void)aMetaSize; // unused
153     void* pResult = NULL;
154 
155 #ifdef WNT
156 	if ( pGDIMeta )
157 	{
158 		SvMemoryStream* pStream = new SvMemoryStream( 65535, 65535 );
159 		if ( pStream )
160 		{
161 			Graphic aGraph( *pGDIMeta );
162 			sal_Bool bFailed = (sal_Bool)GraphicConverter::Export( *pStream, aGraph, CVT_WMF );
163 			pStream->Flush();
164 			if ( !bFailed )
165 			{
166 				sal_Int32 nLength = pStream->Seek( STREAM_SEEK_TO_END );
167 				if ( nLength > 22 )
168 				{
169 					HMETAFILE hMeta = SetMetaFileBitsEx( nLength - 22,
170 									( reinterpret_cast< const sal_uChar*>( pStream->GetData() ) ) + 22 );
171 
172 					if ( hMeta )
173 					{
174 						HGLOBAL hMemory = GlobalAlloc( GMEM_DDESHARE | GMEM_MOVEABLE, sizeof( METAFILEPICT ) );
175 
176 						if ( hMemory )
177 						{
178    							METAFILEPICT* pMF = (METAFILEPICT*)GlobalLock( hMemory );
179 
180    							pMF->hMF = hMeta;
181    							pMF->mm = MM_ANISOTROPIC;
182 
183 							MapMode aMetaMode = pGDIMeta->GetPrefMapMode();
184 							MapMode aWinMode( MAP_100TH_MM );
185 
186 							if ( aWinMode == pGDIMeta->GetPrefMapMode() )
187 							{
188 								pMF->xExt = aMetaSize.Width();
189 								pMF->yExt = aMetaSize.Height();
190 							}
191 							else
192 							{
193 								Size aWinSize = OutputDevice::LogicToLogic( Size( aMetaSize.Width(), aMetaSize.Height() ),
194 																			pGDIMeta->GetPrefMapMode(),
195 																			aWinMode );
196 								pMF->xExt = aWinSize.Width();
197 								pMF->yExt = aWinSize.Height();
198 							}
199 
200 							GlobalUnlock( hMemory );
201 							pResult = (void*)hMemory;
202 						}
203 						else
204    							DeleteMetaFile( hMeta );
205 					}
206 				}
207 			}
208 
209 			delete pStream;
210 		}
211 	}
212 
213 #endif
214 
215 
216 	return pResult;
217 }
218 
219 //---------------------------------------------------------------
220 // static
221 sal_Bool GraphicHelper::supportsMetaFileHandle_Impl()
222 {
223 #ifdef WNT
224 	return sal_True;
225 #else
226 	return sal_False;
227 #endif
228 }
229 
230 //---------------------------------------------------------------
231 // static
232 sal_Bool GraphicHelper::mergeBitmaps_Impl( const BitmapEx& rBmpEx, const BitmapEx& rOverlay,
233 				   const Rectangle& rOverlayRect, BitmapEx& rReturn )
234 {
235 	// the implementation is provided by KA
236 
237 	Point			aNullPt;
238 	Rectangle		aBmpRect( aNullPt, rBmpEx.GetSizePixel() );
239 	VirtualDevice	aVDev;
240 
241 	if( !rReturn.IsEmpty() )
242 		rReturn.SetEmpty();
243 
244 	if( !rBmpEx.IsEmpty() && aVDev.SetOutputSizePixel( aBmpRect.GetSize() ) )
245 	{
246 		Rectangle aOverlayRect( rOverlayRect );
247 
248 		aOverlayRect.Intersection( aBmpRect );
249 
250 		if( rOverlay.IsEmpty() || rOverlayRect.IsEmpty() )
251 			rReturn = rBmpEx;
252 		else
253 		{
254 			aVDev.DrawBitmap( aNullPt, aVDev.GetOutputSizePixel(), rBmpEx.GetBitmap() );
255 			aVDev.DrawBitmapEx( aOverlayRect.TopLeft(), aOverlayRect.GetSize(), rOverlay );
256 
257 			Bitmap aBmp( aVDev.GetBitmap( aNullPt, aVDev.GetOutputSizePixel() ) );
258 			aBmp.Convert( BMP_CONVERSION_24BIT );
259 
260 			if( !rBmpEx.IsTransparent() )
261 				rReturn = aBmp;
262 			else
263 			{
264 				aVDev.DrawBitmap( aNullPt, aVDev.GetOutputSizePixel(), rBmpEx.GetMask() );
265 				Bitmap aOverlayMergeBmp( aVDev.GetBitmap( aOverlayRect.TopLeft(), aOverlayRect.GetSize() ) );
266 
267 				if( rOverlay.IsTransparent() )
268 					aVDev.DrawBitmap( aOverlayRect.TopLeft(), aOverlayRect.GetSize(), rOverlay.GetMask() );
269 				else
270 				{
271 					aVDev.SetLineColor( COL_BLACK );
272 					aVDev.SetFillColor( COL_BLACK );
273 					aVDev.DrawRect( aOverlayRect);
274 				}
275 
276 				aOverlayMergeBmp.CombineSimple( aVDev.GetBitmap( aOverlayRect.TopLeft(), aOverlayRect.GetSize() ), BMP_COMBINE_AND );
277 				aVDev.DrawBitmap( aOverlayRect.TopLeft(), aOverlayRect.GetSize(), aOverlayMergeBmp );
278 				rReturn = BitmapEx( aBmp, aVDev.GetBitmap( aNullPt, aVDev.GetOutputSizePixel() ) );
279 			}
280 		}
281 	}
282 
283 	return !rReturn.IsEmpty();
284 }
285 
286 
287 //---------------------------------------------------------------
288 // static
289 sal_Bool GraphicHelper::createThumb_Impl( const GDIMetaFile& rMtf,
290 				       sal_uInt32 nMaximumExtent,
291 				       BitmapEx& rBmpEx,
292 				       const BitmapEx* pOverlay,
293 				       const Rectangle* pOverlayRect )
294 {
295 	// the implementation is provided by KA
296 
297 	// initialization seems to be complicated but is used to avoid rounding errors
298 	VirtualDevice	aVDev;
299 	const Point     aNullPt;
300 	const Point     aTLPix( aVDev.LogicToPixel( aNullPt, rMtf.GetPrefMapMode() ) );
301 	const Point     aBRPix( aVDev.LogicToPixel( Point( rMtf.GetPrefSize().Width() - 1, rMtf.GetPrefSize().Height() - 1 ), rMtf.GetPrefMapMode() ) );
302 	Size            aDrawSize( aVDev.LogicToPixel( rMtf.GetPrefSize(), rMtf.GetPrefMapMode() ) );
303 	Size			aSizePix( labs( aBRPix.X() - aTLPix.X() ) + 1, labs( aBRPix.Y() - aTLPix.Y() ) + 1 );
304 	Point			aPosPix;
305 
306 	if ( !rBmpEx.IsEmpty() )
307 		rBmpEx.SetEmpty();
308 
309 	// determine size that has the same aspect ratio as image size and
310 	// fits into the rectangle determined by nMaximumExtent
311 	if ( aSizePix.Width() && aSizePix.Height() &&
312             ( sal::static_int_cast<sal_uInt32>(aSizePix.Width()) > nMaximumExtent ||
313               sal::static_int_cast<sal_uInt32>(aSizePix.Height()) > nMaximumExtent ) )
314 	{
315 		const Size  aOldSizePix( aSizePix );
316 		double      fWH = static_cast< double >( aSizePix.Width() ) / aSizePix.Height();
317 
318 		if ( fWH <= 1.0 )
319 		{
320 			aSizePix.Width() = FRound( nMaximumExtent * fWH );
321 			aSizePix.Height() = nMaximumExtent;
322 		}
323 		else
324 		{
325 			aSizePix.Width() = nMaximumExtent;
326 			aSizePix.Height() = FRound(  nMaximumExtent / fWH );
327 		}
328 
329 		aDrawSize.Width() = FRound( ( static_cast< double >( aDrawSize.Width() ) * aSizePix.Width() ) / aOldSizePix.Width() );
330 		aDrawSize.Height() = FRound( ( static_cast< double >( aDrawSize.Height() ) * aSizePix.Height() ) / aOldSizePix.Height() );
331 	}
332 
333 	Size 		aFullSize;
334 	Point		aBackPosPix;
335 	Rectangle 	aOverlayRect;
336 
337 	// calculate addigtional positions and sizes if an overlay image is used
338 	if (  pOverlay )
339 	{
340 		aFullSize = Size( nMaximumExtent, nMaximumExtent );
341 		aOverlayRect = Rectangle( aNullPt, aFullSize  );
342 
343 		aOverlayRect.Intersection( pOverlayRect ? *pOverlayRect : Rectangle( aNullPt, pOverlay->GetSizePixel() ) );
344 
345 		if ( !aOverlayRect.IsEmpty() )
346 			aBackPosPix = Point( ( nMaximumExtent - aSizePix.Width() ) >> 1, ( nMaximumExtent - aSizePix.Height() ) >> 1 );
347 		else
348 			pOverlay = NULL;
349 	}
350 	else
351 	{
352 		aFullSize = aSizePix;
353 		pOverlay = NULL;
354 	}
355 
356 	// draw image(s) into VDev and get resulting image
357 	if ( aVDev.SetOutputSizePixel( aFullSize ) )
358 	{
359 		// draw metafile into VDev
360 		const_cast< GDIMetaFile& >( rMtf ).WindStart();
361 		const_cast< GDIMetaFile& >( rMtf ).Play( &aVDev, aBackPosPix, aDrawSize );
362 
363 		// draw overlay if neccessary
364 		if ( pOverlay )
365 			aVDev.DrawBitmapEx( aOverlayRect.TopLeft(), aOverlayRect.GetSize(), *pOverlay );
366 
367 		// get paint bitmap
368 		Bitmap aBmp( aVDev.GetBitmap( aNullPt, aVDev.GetOutputSizePixel() ) );
369 
370 		// assure that we have a true color image
371 		if ( aBmp.GetBitCount() != 24 )
372 			aBmp.Convert( BMP_CONVERSION_24BIT );
373 
374 		rBmpEx = BitmapEx( aBmp );
375 	}
376 
377 	return !rBmpEx.IsEmpty();
378 }
379 
380 //---------------------------------------------------------------
381 // static
382 sal_Bool GraphicHelper::getThumbnailFormatFromGDI_Impl( GDIMetaFile* pMetaFile,
383 														sal_Bool bSigned,
384 														const uno::Reference< io::XStream >& xStream )
385 {
386 	sal_Bool bResult = sal_False;
387 	SvStream* pStream = NULL;
388 
389 	if ( xStream.is() )
390 		pStream = ::utl::UcbStreamHelper::CreateStream( xStream );
391 
392 	if ( pMetaFile && pStream && !pStream->GetError() )
393 	{
394 		BitmapEx aResultBitmap;
395 		BitmapEx* pSignatureBitmap = NULL;
396 
397 		if ( bSigned )
398 			pSignatureBitmap = new BitmapEx( SfxResId( BMP_SIGNATURE ) );
399 
400 		bResult = createThumb_Impl( *pMetaFile,
401 			       				    THUMBNAIL_RESOLUTION,
402 			       				    aResultBitmap,
403 								    pSignatureBitmap );
404 		if ( bResult )
405 			bResult = ( !aResultBitmap.IsEmpty()
406 						&& GraphicConverter::Export( *pStream, aResultBitmap, CVT_PNG ) == 0
407 						&& ( pStream->Flush(), !pStream->GetError() ) );
408 
409 		if ( pSignatureBitmap )
410 			delete pSignatureBitmap;
411 
412 		delete pStream;
413 	}
414 
415 	return bResult;
416 }
417 
418 //---------------------------------------------------------------
419 // static
420 sal_Bool GraphicHelper::getSignedThumbnailFormatFromBitmap_Impl( const BitmapEx& aBitmap,
421 																 const uno::Reference< io::XStream >& xStream )
422 {
423 	sal_Bool bResult = sal_False;
424 	SvStream* pStream = NULL;
425 
426 	if ( xStream.is() )
427 		pStream = ::utl::UcbStreamHelper::CreateStream( xStream );
428 
429 	if ( pStream && !pStream->GetError() )
430 	{
431 		BitmapEx aResultBitmap;
432 		BitmapEx aSignatureBitmap( SfxResId( BMP_SIGNATURE ) );
433 
434 		bResult = mergeBitmaps_Impl( aBitmap,
435 									aSignatureBitmap,
436 									Rectangle( Point(), aBitmap.GetSizePixel() ),
437 									aResultBitmap );
438 
439 		if ( bResult )
440 		{
441 			bResult = ( !aResultBitmap.IsEmpty()
442 						&& GraphicConverter::Export( *pStream, aResultBitmap, CVT_PNG ) == 0
443 						&& ( pStream->Flush(), !pStream->GetError() ) );
444 		}
445 
446 		delete pStream;
447 	}
448 
449 	return bResult;
450 }
451 
452 //---------------------------------------------------------------
453 // static
454 sal_Bool GraphicHelper::getThumbnailReplacement_Impl( sal_Int32 nResID, const uno::Reference< io::XStream >& xStream )
455 {
456 	sal_Bool bResult = sal_False;
457 	if ( nResID && xStream.is() )
458 	{
459     	uno::Reference< lang::XMultiServiceFactory > xServiceManager = ::comphelper::getProcessServiceFactory();
460 		if ( xServiceManager.is() )
461 		{
462 			try
463 			{
464 				uno::Reference< graphic::XGraphicProvider > xGraphProvider(
465 					xServiceManager->createInstance(
466 						::rtl::OUString::createFromAscii( "com.sun.star.graphic.GraphicProvider" ) ),
467 					uno::UNO_QUERY );
468 				if ( xGraphProvider.is() )
469 				{
470 					::rtl::OUString aURL = ::rtl::OUString::createFromAscii( "private:resource/sfx/bitmapex/" );
471 					aURL += ::rtl::OUString::valueOf( nResID );
472 
473 					uno::Sequence< beans::PropertyValue > aMediaProps( 1 );
474 					aMediaProps[0].Name = ::rtl::OUString::createFromAscii( "URL" );
475 					aMediaProps[0].Value <<= aURL;
476 
477 					uno::Reference< graphic::XGraphic > xGraphic = xGraphProvider->queryGraphic( aMediaProps );
478 					if ( xGraphic.is() )
479 					{
480 						uno::Sequence< beans::PropertyValue > aStoreProps( 2 );
481 						aStoreProps[0].Name = ::rtl::OUString::createFromAscii( "OutputStream" );
482 						aStoreProps[0].Value <<= xStream;
483 						aStoreProps[1].Name = ::rtl::OUString::createFromAscii( "MimeType" );
484 						aStoreProps[1].Value <<= ::rtl::OUString::createFromAscii( "image/png" );
485 
486 						xGraphProvider->storeGraphic( xGraphic, aStoreProps );
487 						bResult = sal_True;
488 					}
489 				}
490 			}
491 			catch( uno::Exception& )
492 			{
493 			}
494 		}
495 	}
496 
497 	return bResult;
498 }
499 
500 //---------------------------------------------------------------
501 // static
502 sal_uInt16 GraphicHelper::getThumbnailReplacementIDByFactoryName_Impl( const ::rtl::OUString& aFactoryShortName, sal_Bool /*bIsTemplate*/ )
503 {
504 	sal_uInt16 nResult = 0;
505 
506 	if ( aFactoryShortName.equalsAscii( "scalc" ) )
507 	{
508 		nResult = BMP_128X128_CALC_DOC;
509 	}
510 	else if ( aFactoryShortName.equalsAscii( "sdraw" ) )
511 	{
512 		nResult = BMP_128X128_DRAW_DOC;
513 	}
514 	else if ( aFactoryShortName.equalsAscii( "simpress" ) )
515 	{
516 		nResult = BMP_128X128_IMPRESS_DOC;
517 	}
518 	else if ( aFactoryShortName.equalsAscii( "smath" ) )
519 	{
520 		nResult = BMP_128X128_MATH_DOC;
521 	}
522 	else if ( aFactoryShortName.equalsAscii( "swriter" ) || aFactoryShortName.compareToAscii( "swriter/", 8 ) == 0 )
523 	{
524 		nResult = BMP_128X128_WRITER_DOC;
525 	}
526 
527 	return nResult;
528 }
529 
530