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_svtools.hxx"
30 
31 #include <rtl/uuid.h>
32 #include <vos/mutex.hxx>
33 #include <vcl/svapp.hxx>
34 #include <vcl/image.hxx>
35 #include <vcl/metaact.hxx>
36 #include <vcl/msgbox.hxx>
37 #include <vcl/imagerepository.hxx>
38 #include <tools/rcid.h>
39 #include <tools/resid.hxx>
40 #include <tools/resmgr.hxx>
41 #include <unotools/ucbstreamhelper.hxx>
42 #include <svtools/filter.hxx>
43 #include <svl/solar.hrc>
44 #include <vcl/salbtype.hxx>
45 #include <vcl/virdev.hxx>
46 #include <com/sun/star/io/XStream.hpp>
47 #include <com/sun/star/text/GraphicCrop.hpp>
48 
49 #include "descriptor.hxx"
50 #include "graphic.hxx"
51 #include <svtools/grfmgr.hxx>
52 #include "provider.hxx"
53 
54 using namespace com::sun::star;
55 
56 namespace unographic {
57 
58 #define UNO_NAME_GRAPHOBJ_URLPREFIX                             "vnd.sun.star.GraphicObject:"
59 
60 // -------------------
61 // - GraphicProvider -
62 // -------------------
63 
64 uno::Reference< uno::XInterface > SAL_CALL GraphicProvider_CreateInstance( const uno::Reference< lang::XMultiServiceFactory >& )
65 {
66 	return SAL_STATIC_CAST( ::cppu::OWeakObject*, new GraphicProvider );
67 }
68 
69 GraphicProvider::GraphicProvider()
70 {
71 }
72 
73 // ------------------------------------------------------------------------------
74 
75 GraphicProvider::~GraphicProvider()
76 {
77 }
78 
79 // ------------------------------------------------------------------------------
80 
81 ::rtl::OUString GraphicProvider::getImplementationName_Static()
82 	throw()
83 {
84 	return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.graphic.GraphicProvider" ) );
85 }
86 
87 // ------------------------------------------------------------------------------
88 
89 uno::Sequence< ::rtl::OUString > GraphicProvider::getSupportedServiceNames_Static()
90 	throw()
91 {
92 	uno::Sequence< ::rtl::OUString > aSeq( 1 );
93 
94 	aSeq.getArray()[ 0 ] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.graphic.GraphicProvider" ) );
95 
96 	return aSeq;
97 }
98 
99 // ------------------------------------------------------------------------------
100 
101 ::rtl::OUString SAL_CALL GraphicProvider::getImplementationName()
102 	throw( uno::RuntimeException )
103 {
104 	return getImplementationName_Static();
105 }
106 
107 // ------------------------------------------------------------------------------
108 
109 sal_Bool SAL_CALL GraphicProvider::supportsService( const ::rtl::OUString& ServiceName )
110 	throw( uno::RuntimeException )
111 {
112     uno::Sequence< ::rtl::OUString >	aSNL( getSupportedServiceNames() );
113     const ::rtl::OUString*				pArray = aSNL.getConstArray();
114 
115     for( int i = 0; i < aSNL.getLength(); i++ )
116         if( pArray[i] == ServiceName )
117             return true;
118 
119     return false;
120 }
121 
122 // ------------------------------------------------------------------------------
123 
124 uno::Sequence< ::rtl::OUString > SAL_CALL GraphicProvider::getSupportedServiceNames()
125 	throw( uno::RuntimeException )
126 {
127 	return getSupportedServiceNames_Static();
128 }
129 
130 // ------------------------------------------------------------------------------
131 
132 uno::Sequence< uno::Type > SAL_CALL GraphicProvider::getTypes()
133 	throw(uno::RuntimeException)
134 {
135 	uno::Sequence< uno::Type >	aTypes( 3 );
136 	uno::Type* 					pTypes = aTypes.getArray();
137 
138 	*pTypes++ = ::getCppuType((const uno::Reference< lang::XServiceInfo>*)0);
139 	*pTypes++ = ::getCppuType((const uno::Reference< lang::XTypeProvider>*)0);
140 	*pTypes++ = ::getCppuType((const uno::Reference< graphic::XGraphicProvider>*)0);
141 
142 	return aTypes;
143 }
144 
145 // ------------------------------------------------------------------------------
146 
147 uno::Sequence< sal_Int8 > SAL_CALL GraphicProvider::getImplementationId()
148 	throw(uno::RuntimeException)
149 {
150 	vos::OGuard 						aGuard( Application::GetSolarMutex() );
151 	static uno::Sequence< sal_Int8 >	aId;
152 
153 	if( aId.getLength() == 0 )
154 	{
155 		aId.realloc( 16 );
156 		rtl_createUuid( reinterpret_cast< sal_uInt8* >( aId.getArray() ), 0, sal_True );
157 	}
158 
159 	return aId;
160 }
161 
162 // ------------------------------------------------------------------------------
163 
164 uno::Reference< ::graphic::XGraphic > GraphicProvider::implLoadGraphicObject( const ::rtl::OUString& rResourceURL ) const
165 {
166 	uno::Reference< ::graphic::XGraphic > 	xRet;
167 	if( rResourceURL.compareToAscii( UNO_NAME_GRAPHOBJ_URLPREFIX, RTL_CONSTASCII_LENGTH( UNO_NAME_GRAPHOBJ_URLPREFIX ) ) == 0 )
168 	{
169 		// graphic manager url
170 		String aTmpStr( rResourceURL.copy( sizeof( UNO_NAME_GRAPHOBJ_URLPREFIX ) - 1 ) );
171 		ByteString aUniqueID( aTmpStr, RTL_TEXTENCODING_UTF8 );
172 		GraphicObject aGrafObj( aUniqueID );
173 		// I don't call aGrafObj.GetXGraphic because it will call us back
174 		// into implLoadMemory ( with "private:memorygraphic" test )
175 		::unographic::Graphic* pUnoGraphic = new ::unographic::Graphic;
176 		pUnoGraphic->init( aGrafObj.GetGraphic() );
177 		xRet = pUnoGraphic;
178 	}
179 	return xRet;
180 }
181 
182 uno::Reference< ::graphic::XGraphic > GraphicProvider::implLoadMemory( const ::rtl::OUString& rResourceURL ) const
183 {
184 	uno::Reference< ::graphic::XGraphic > 	xRet;
185 	sal_Int32								nIndex = 0;
186 
187 	if( ( 0 == rResourceURL.getToken( 0, '/', nIndex ).compareToAscii( "private:memorygraphic" ) ) )
188 	{
189 		sal_Int64 nGraphicAddress = rResourceURL.getToken( 0, '/', nIndex ).toInt64();
190 
191 		if( nGraphicAddress )
192 		{
193 			::unographic::Graphic* pUnoGraphic = new ::unographic::Graphic;
194 
195 			pUnoGraphic->init( *reinterpret_cast< ::Graphic* >( nGraphicAddress ) );
196 			xRet = pUnoGraphic;
197 		}
198 	}
199 
200 	return xRet;
201 }
202 
203 // ------------------------------------------------------------------------------
204 
205 uno::Reference< ::graphic::XGraphic > GraphicProvider::implLoadRepositoryImage( const ::rtl::OUString& rResourceURL ) const
206 {
207 	uno::Reference< ::graphic::XGraphic > 	xRet;
208 	sal_Int32								nIndex = 0;
209 
210     if( ( 0 == rResourceURL.getToken( 0, '/', nIndex ).compareToAscii( "private:graphicrepository" ) ) )
211     {
212 		String sPathName( rResourceURL.copy( nIndex ) );
213         BitmapEx aBitmap;
214         if ( ::vcl::ImageRepository::loadImage( sPathName, aBitmap, false ) )
215         {
216             Image aImage( aBitmap );
217             xRet = aImage.GetXGraphic();
218         }
219     }
220     return xRet;
221 }
222 
223 
224 // ------------------------------------------------------------------------------
225 
226 uno::Reference< ::graphic::XGraphic > GraphicProvider::implLoadStandardImage( const ::rtl::OUString& rResourceURL ) const
227 {
228 	uno::Reference< ::graphic::XGraphic > 	xRet;
229 	sal_Int32								nIndex = 0;
230 
231     if( ( 0 == rResourceURL.getToken( 0, '/', nIndex ).compareToAscii( "private:standardimage" ) ) )
232     {
233 		rtl::OUString sImageName( rResourceURL.copy( nIndex ) );
234         if ( sImageName.equalsAscii( "info" ) )
235 		{
236 			xRet = InfoBox::GetStandardImage().GetXGraphic();
237 		}
238 		else if ( sImageName.equalsAscii( "warning" ) )
239 		{
240 			xRet = WarningBox::GetStandardImage().GetXGraphic();
241 		}
242 		else if ( sImageName.equalsAscii( "error" ) )
243 		{
244 			xRet = ErrorBox::GetStandardImage().GetXGraphic();
245 		}
246 		else if ( sImageName.equalsAscii( "query" ) )
247 		{
248 			xRet = QueryBox::GetStandardImage().GetXGraphic();
249 		}
250     }
251     return xRet;
252 }
253 
254 // ------------------------------------------------------------------------------
255 
256 uno::Reference< ::graphic::XGraphic > GraphicProvider::implLoadBitmap( const uno::Reference< awt::XBitmap >& xBtm ) const
257 {
258     uno::Reference< ::graphic::XGraphic > xRet;
259     uno::Sequence< sal_Int8 > aBmpSeq( xBtm->getDIB() );
260     uno::Sequence< sal_Int8 > aMaskSeq( xBtm->getMaskDIB() );
261     SvMemoryStream aBmpStream( aBmpSeq.getArray(), aBmpSeq.getLength(), STREAM_READ );
262     Bitmap aBmp;
263     aBmpStream >> aBmp;
264 
265     BitmapEx aBmpEx;
266 
267     if( aMaskSeq.getLength() )
268     {
269         SvMemoryStream aMaskStream( aMaskSeq.getArray(), aMaskSeq.getLength(), STREAM_READ );
270         Bitmap aMask;
271         aMaskStream >> aMask;
272         aBmpEx = BitmapEx( aBmp, aMask );
273     }
274     else
275         aBmpEx = BitmapEx( aBmp );
276 
277     if( !aBmpEx.IsEmpty() )
278     {
279         ::unographic::Graphic* pUnoGraphic = new ::unographic::Graphic;
280 
281         pUnoGraphic->init( aBmpEx );
282         xRet = pUnoGraphic;
283     }
284     return xRet;
285 }
286 
287 // ------------------------------------------------------------------------------
288 
289 uno::Reference< ::graphic::XGraphic > GraphicProvider::implLoadResource( const ::rtl::OUString& rResourceURL ) const
290 {
291 	uno::Reference< ::graphic::XGraphic > 	xRet;
292 	sal_Int32								nIndex = 0;
293 
294 	if( ( 0 == rResourceURL.getToken( 0, '/', nIndex ).compareToAscii( "private:resource" ) ) )
295 	{
296 		ByteString aResMgrName( String( rResourceURL.getToken( 0, '/', nIndex ) ), RTL_TEXTENCODING_ASCII_US );
297 
298 		ResMgr* pResMgr = ResMgr::CreateResMgr( aResMgrName.GetBuffer(), Application::GetSettings().GetUILocale() );
299 
300 		if( pResMgr )
301 		{
302 			const ::rtl::OUString	aResourceType( rResourceURL.getToken( 0, '/', nIndex ) );
303 			const ResId				aResId( rResourceURL.getToken( 0, '/', nIndex ).toInt32(), *pResMgr );
304 
305 			if( aResourceType.getLength() )
306 			{
307 				BitmapEx aBmpEx;
308 
309 				if( ( 0 == aResourceType.compareToAscii( "bitmap" ) ) ||
310 					( 0 == aResourceType.compareToAscii( "bitmapex" ) ) )
311 				{
312 					aResId.SetRT( RSC_BITMAP );
313 
314 					if( pResMgr->IsAvailable( aResId ) )
315 					{
316 						aBmpEx = BitmapEx( aResId );
317 					}
318 				}
319 				else if( 0 == aResourceType.compareToAscii( "image" ) )
320 				{
321 					aResId.SetRT( RSC_IMAGE );
322 
323 					if( pResMgr->IsAvailable( aResId ) )
324 					{
325 						const Image aImage( aResId );
326 						aBmpEx = aImage.GetBitmapEx();
327 					}
328 				}
329 				else if( 0 == aResourceType.compareToAscii( "imagelist" ) )
330 				{
331 					aResId.SetRT( RSC_IMAGELIST );
332 
333 					if( pResMgr->IsAvailable( aResId ) )
334 					{
335 						const ImageList aImageList( aResId );
336 						sal_Int32		nImageId = ( nIndex > -1 ) ? rResourceURL.getToken( 0, '/', nIndex ).toInt32() : 0;
337 
338 						if( 0 < nImageId )
339 						{
340 							const Image aImage( aImageList.GetImage( sal::static_int_cast< sal_uInt16 >(nImageId) ) );
341 							aBmpEx = aImage.GetBitmapEx();
342 						}
343 						else
344 						{
345 							aBmpEx = aImageList.GetAsHorizontalStrip();
346 						}
347 					}
348 				}
349 
350 				if( !aBmpEx.IsEmpty() )
351 				{
352 					::unographic::Graphic* pUnoGraphic = new ::unographic::Graphic;
353 
354 					pUnoGraphic->init( aBmpEx );
355 					xRet = pUnoGraphic;
356 				}
357 			}
358 
359 			delete pResMgr;
360 		}
361 	}
362 
363 	return xRet;
364 }
365 
366 // ------------------------------------------------------------------------------
367 
368 uno::Reference< beans::XPropertySet > SAL_CALL GraphicProvider::queryGraphicDescriptor( const uno::Sequence< beans::PropertyValue >& rMediaProperties )
369 	throw ( io::IOException, lang::IllegalArgumentException, lang::WrappedTargetException, uno::RuntimeException)
370 {
371 	uno::Reference< beans::XPropertySet > xRet;
372 
373 	::rtl::OUString aURL;
374 	uno::Reference< io::XInputStream > xIStm;
375     uno::Reference< awt::XBitmap >xBtm;
376 
377 	for( sal_Int32 i = 0; ( i < rMediaProperties.getLength() ) && !xRet.is(); ++i )
378 	{
379 		const ::rtl::OUString	aName( rMediaProperties[ i ].Name );
380 		const uno::Any 			aValue( rMediaProperties[ i ].Value );
381 
382 		if( COMPARE_EQUAL == aName.compareToAscii( "URL" ) )
383 		{
384 			aValue >>= aURL;
385 		}
386 		else if( COMPARE_EQUAL == aName.compareToAscii( "InputStream" ) )
387 		{
388 			aValue >>= xIStm;
389 		}
390         else if( COMPARE_EQUAL == aName.compareToAscii( "Bitmap" ) )
391         {
392             aValue >>= xBtm;
393         }
394 	}
395 
396 	if( xIStm.is() )
397 	{
398 		GraphicDescriptor* pDescriptor = new GraphicDescriptor;
399 		pDescriptor->init( xIStm, aURL );
400 		xRet = pDescriptor;
401 	}
402 	else if( aURL.getLength() )
403 	{
404 		uno::Reference< ::graphic::XGraphic > xGraphic( implLoadMemory( aURL ) );
405 		if( !xGraphic.is() )
406 			xGraphic = implLoadResource( aURL );
407 		if( !xGraphic.is() )
408 			xGraphic = implLoadGraphicObject( aURL );
409 
410         if ( !xGraphic.is() )
411             xGraphic = implLoadRepositoryImage( aURL );
412 
413 		if ( !xGraphic.is() )
414             xGraphic = implLoadStandardImage( aURL );
415 
416 		if( xGraphic.is() )
417 		{
418 			xRet = uno::Reference< beans::XPropertySet >( xGraphic, uno::UNO_QUERY );
419 		}
420 		else
421 		{
422 			GraphicDescriptor* pDescriptor = new GraphicDescriptor;
423 			pDescriptor->init( aURL );
424 			xRet = pDescriptor;
425 		}
426 	}
427     else if( xBtm.is() )
428     {
429         uno::Reference< ::graphic::XGraphic > xGraphic( implLoadBitmap( xBtm ) );
430 		if( xGraphic.is() )
431 			xRet = uno::Reference< beans::XPropertySet >( xGraphic, uno::UNO_QUERY );
432     }
433 
434 	return xRet;
435 }
436 
437 // ------------------------------------------------------------------------------
438 
439 uno::Reference< ::graphic::XGraphic > SAL_CALL GraphicProvider::queryGraphic( const uno::Sequence< ::beans::PropertyValue >& rMediaProperties )
440 	throw ( io::IOException, lang::IllegalArgumentException, lang::WrappedTargetException, uno::RuntimeException)
441 {
442 	uno::Reference< ::graphic::XGraphic >	xRet;
443 	String									aPath;
444 	SvStream* 								pIStm = NULL;
445 
446 	uno::Reference< io::XInputStream > xIStm;
447     uno::Reference< awt::XBitmap >xBtm;
448 
449 	for( sal_Int32 i = 0; ( i < rMediaProperties.getLength() ) && !pIStm && !xRet.is(); ++i )
450 	{
451 		const ::rtl::OUString	aName( rMediaProperties[ i ].Name );
452 		const uno::Any 			aValue( rMediaProperties[ i ].Value );
453 
454 		if( COMPARE_EQUAL == aName.compareToAscii( "URL" ) )
455 		{
456 			::rtl::OUString aURL;
457 			aValue >>= aURL;
458 			aPath = aURL;
459 		}
460 		else if( COMPARE_EQUAL == aName.compareToAscii( "InputStream" ) )
461 		{
462 			aValue >>= xIStm;
463 		}
464         else if( COMPARE_EQUAL == aName.compareToAscii( "Bitmap" ) )
465         {
466             aValue >>= xBtm;
467         }
468 	}
469 
470 	if( xIStm.is() )
471 	{
472 		pIStm = ::utl::UcbStreamHelper::CreateStream( xIStm );
473 	}
474 	else if( aPath.Len() )
475 	{
476 		xRet = implLoadMemory( aPath );
477 
478 		if( !xRet.is() )
479 			xRet = implLoadGraphicObject( aPath );
480 
481 		if( !xRet.is() )
482 			xRet = implLoadResource( aPath );
483 
484         if ( !xRet.is() )
485             xRet = implLoadRepositoryImage( aPath );
486 
487 		if ( !xRet.is() )
488             xRet = implLoadStandardImage( aPath );
489 
490 		if( !xRet.is() )
491 			pIStm = ::utl::UcbStreamHelper::CreateStream( aPath, STREAM_READ );
492 	}
493     else if( xBtm.is() )
494     {
495         xRet = implLoadBitmap( xBtm );
496     }
497 
498 	if( pIStm )
499 	{
500 		::GraphicFilter* pFilter = ::GraphicFilter::GetGraphicFilter();
501 
502 		if( pFilter )
503 		{
504 			::Graphic aVCLGraphic;
505 
506 			if( ( pFilter->ImportGraphic( aVCLGraphic, aPath, *pIStm ) == GRFILTER_OK ) &&
507 				( aVCLGraphic.GetType() != GRAPHIC_NONE ) )
508 			{
509 				::unographic::Graphic* pUnoGraphic = new ::unographic::Graphic;
510 
511 				pUnoGraphic->init( aVCLGraphic );
512 				xRet = pUnoGraphic;
513 			}
514 		}
515 
516 		delete pIStm;
517 	}
518 
519 	return xRet;
520 }
521 
522 void ImplCalculateCropRect( ::Graphic& rGraphic, const text::GraphicCrop& rGraphicCropLogic, Rectangle& rGraphicCropPixel )
523 {
524 	if ( rGraphicCropLogic.Left || rGraphicCropLogic.Top || rGraphicCropLogic.Right || rGraphicCropLogic.Bottom )
525 	{
526 		Size aSourceSizePixel( rGraphic.GetSizePixel() );
527 		if ( aSourceSizePixel.Width() && aSourceSizePixel.Height() )
528 		{
529 			if ( rGraphicCropLogic.Left || rGraphicCropLogic.Top || rGraphicCropLogic.Right || rGraphicCropLogic.Bottom )
530 			{
531 				Size aSize100thMM( 0, 0 );
532 				if( rGraphic.GetPrefMapMode().GetMapUnit() != MAP_PIXEL )
533 				{
534 					aSize100thMM = OutputDevice::LogicToLogic( rGraphic.GetPrefSize(), rGraphic.GetPrefMapMode(), MAP_100TH_MM );
535 				}
536 				else
537 				{
538 					aSize100thMM = Application::GetDefaultDevice()->PixelToLogic( rGraphic.GetPrefSize(), MAP_100TH_MM );
539 				}
540 				if ( aSize100thMM.Width() && aSize100thMM.Height() )
541 				{
542 					double fSourceSizePixelWidth = static_cast<double>(aSourceSizePixel.Width());
543 					double fSourceSizePixelHeight= static_cast<double>(aSourceSizePixel.Height());
544 					rGraphicCropPixel.Left() = static_cast< sal_Int32 >((fSourceSizePixelWidth * rGraphicCropLogic.Left ) / aSize100thMM.Width());
545 					rGraphicCropPixel.Top() = static_cast< sal_Int32 >((fSourceSizePixelHeight * rGraphicCropLogic.Top ) / aSize100thMM.Height());
546 					rGraphicCropPixel.Right() = static_cast< sal_Int32 >(( fSourceSizePixelWidth * ( aSize100thMM.Width() - rGraphicCropLogic.Right ) ) / aSize100thMM.Width() );
547 					rGraphicCropPixel.Bottom() = static_cast< sal_Int32 >(( fSourceSizePixelHeight * ( aSize100thMM.Height() - rGraphicCropLogic.Bottom ) ) / aSize100thMM.Height() );
548 				}
549 			}
550 		}
551 	}
552 }
553 
554 void ImplApplyBitmapScaling( ::Graphic& rGraphic, sal_Int32 nPixelWidth, sal_Int32 nPixelHeight )
555 {
556 	if ( nPixelWidth && nPixelHeight )
557 	{
558 		BitmapEx aBmpEx( rGraphic.GetBitmapEx() );
559 		MapMode aPrefMapMode( aBmpEx.GetPrefMapMode() );
560 		Size	aPrefSize( aBmpEx.GetPrefSize() );
561 		aBmpEx.Scale( Size( nPixelWidth, nPixelHeight ) );
562 		aBmpEx.SetPrefMapMode( aPrefMapMode );
563 		aBmpEx.SetPrefSize( aPrefSize );
564 		rGraphic = aBmpEx;
565 	}
566 }
567 
568 void ImplApplyBitmapResolution( ::Graphic& rGraphic, sal_Int32 nImageResolution, const Size& rVisiblePixelSize, const awt::Size& rLogicalSize )
569 {
570 	if ( nImageResolution && rLogicalSize.Width && rLogicalSize.Height )
571 	{
572 		const double fImageResolution = static_cast<double>( nImageResolution );
573 		const double fSourceDPIX = ( static_cast<double>(rVisiblePixelSize.Width()) * 2540.0 ) / static_cast<double>(rLogicalSize.Width);
574 		const double fSourceDPIY = ( static_cast<double>(rVisiblePixelSize.Height()) * 2540.0 ) / static_cast<double>(rLogicalSize.Height);
575 		const sal_Int32 nSourcePixelWidth( rGraphic.GetSizePixel().Width() );
576 		const sal_Int32 nSourcePixelHeight( rGraphic.GetSizePixel().Height() );
577 		const double fSourcePixelWidth = static_cast<double>( nSourcePixelWidth );
578 		const double fSourcePixelHeight= static_cast<double>( nSourcePixelHeight );
579 
580 		sal_Int32 nDestPixelWidth = nSourcePixelWidth;
581 		sal_Int32 nDestPixelHeight = nSourcePixelHeight;
582 
583 		// check, if the bitmap DPI exceeds the maximum DPI
584 		if( fSourceDPIX > fImageResolution )
585 		{
586 			nDestPixelWidth = static_cast<sal_Int32>(( fSourcePixelWidth * fImageResolution ) / fSourceDPIX);
587 			if ( !nDestPixelWidth || ( nDestPixelWidth > nSourcePixelWidth ) )
588 				nDestPixelWidth = nSourcePixelWidth;
589 		}
590 		if ( fSourceDPIY > fImageResolution )
591 		{
592 			nDestPixelHeight= static_cast<sal_Int32>(( fSourcePixelHeight* fImageResolution ) / fSourceDPIY);
593 			if ( !nDestPixelHeight || ( nDestPixelHeight > nSourcePixelHeight ) )
594 				nDestPixelHeight = nSourcePixelHeight;
595 		}
596 		if ( ( nDestPixelWidth != nSourcePixelWidth ) || ( nDestPixelHeight != nSourcePixelHeight ) )
597 			ImplApplyBitmapScaling( rGraphic, nDestPixelWidth, nDestPixelHeight );
598 	}
599 }
600 
601 void ImplApplyFilterData( ::Graphic& rGraphic, uno::Sequence< beans::PropertyValue >& rFilterData )
602 {
603 	/* this method applies following attributes to the graphic, in the first step the
604 	   cropping area (logical size in 100thmm) is applied, in the second step the resolution
605 	   is applied, in the third step the graphic is scaled to the corresponding pixelsize.
606 	   if a parameter value is zero or not available the corresponding step will be skipped */
607 
608 	sal_Int32 nPixelWidth = 0;
609 	sal_Int32 nPixelHeight= 0;
610 	sal_Int32 nImageResolution = 0;
611 	awt::Size aLogicalSize( 0, 0 );
612 	text::GraphicCrop aCropLogic( 0, 0, 0, 0 );
613 	sal_Bool bRemoveCropArea = sal_True;
614 
615 	for( sal_Int32 i = 0; i < rFilterData.getLength(); ++i )
616 	{
617 		const ::rtl::OUString	aName(  rFilterData[ i ].Name );
618 		const uno::Any 			aValue( rFilterData[ i ].Value );
619 
620 		if( COMPARE_EQUAL == aName.compareToAscii( "PixelWidth" ) )
621 			aValue >>= nPixelWidth;
622 		else if( COMPARE_EQUAL == aName.compareToAscii( "PixelHeight" ) )
623 			aValue >>= nPixelHeight;
624 		else if( COMPARE_EQUAL == aName.compareToAscii( "LogicalSize" ) )
625 			aValue >>= aLogicalSize;
626 		else if (COMPARE_EQUAL == aName.compareToAscii( "GraphicCropLogic" ) )
627 			aValue >>= aCropLogic;
628 		else if (COMPARE_EQUAL == aName.compareToAscii( "RemoveCropArea" ) )
629 			aValue >>= bRemoveCropArea;
630 		else if (COMPARE_EQUAL == aName.compareToAscii( "ImageResolution" ) )
631 			aValue >>= nImageResolution;
632 	}
633 	if ( rGraphic.GetType() == GRAPHIC_BITMAP )
634 	{
635 		Rectangle aCropPixel( Point( 0, 0 ), rGraphic.GetSizePixel() );
636 		ImplCalculateCropRect( rGraphic, aCropLogic, aCropPixel );
637 		if ( bRemoveCropArea )
638 		{
639 			BitmapEx aBmpEx( rGraphic.GetBitmapEx() );
640 			aBmpEx.Crop( aCropPixel );
641 			rGraphic = aBmpEx;
642 		}
643 		Size aVisiblePixelSize( bRemoveCropArea ? rGraphic.GetSizePixel() : aCropPixel.GetSize() );
644 		ImplApplyBitmapResolution( rGraphic, nImageResolution, aVisiblePixelSize, aLogicalSize );
645 		ImplApplyBitmapScaling( rGraphic, nPixelWidth, nPixelHeight );
646 	}
647 	else if ( ( rGraphic.GetType() == GRAPHIC_GDIMETAFILE ) && nImageResolution )
648 	{
649 		VirtualDevice aDummyVDev;
650 		GDIMetaFile aMtf( rGraphic.GetGDIMetaFile() );
651 		Size aMtfSize( aDummyVDev.LogicToLogic( aMtf.GetPrefSize(), aMtf.GetPrefMapMode(), MAP_100TH_MM ) );
652 		if ( aMtfSize.Width() && aMtfSize.Height() )
653 		{
654 			MapMode aNewMapMode( MAP_100TH_MM );
655 			aNewMapMode.SetScaleX( static_cast< double >( aLogicalSize.Width ) / static_cast< double >( aMtfSize.Width() ) );
656 			aNewMapMode.SetScaleY( static_cast< double >( aLogicalSize.Height ) / static_cast< double >( aMtfSize.Height() ) );
657 			aDummyVDev.EnableOutput( sal_False );
658 			aDummyVDev.SetMapMode( aNewMapMode );
659 
660 			for( sal_uInt32 i = 0, nObjCount = aMtf.GetActionCount(); i < nObjCount; i++ )
661 			{
662 				MetaAction* pAction = aMtf.GetAction( i );
663 				switch( pAction->GetType() )
664 				{
665 					// only optimizing common bitmap actions:
666 					case( META_MAPMODE_ACTION ):
667 					{
668 						const_cast< MetaAction* >( pAction )->Execute( &aDummyVDev );
669 						break;
670 					}
671 					case( META_PUSH_ACTION ):
672 					{
673 						const MetaPushAction* pA = (const MetaPushAction*)pAction;
674 						aDummyVDev.Push( pA->GetFlags() );
675 						break;
676 					}
677 					case( META_POP_ACTION ):
678 					{
679 						aDummyVDev.Pop();
680 						break;
681 					}
682 					case( META_BMPSCALE_ACTION ):
683 					case( META_BMPEXSCALE_ACTION ):
684 					{
685 						BitmapEx aBmpEx;
686 						Point aPos;
687 						Size aSize;
688 						if ( pAction->GetType() == META_BMPSCALE_ACTION )
689 						{
690 							MetaBmpScaleAction* pScaleAction = dynamic_cast< MetaBmpScaleAction* >( pAction );
691 							aBmpEx = pScaleAction->GetBitmap();
692 							aPos = pScaleAction->GetPoint();
693 							aSize = pScaleAction->GetSize();
694 						}
695 						else
696 						{
697 							MetaBmpExScaleAction* pScaleAction = dynamic_cast< MetaBmpExScaleAction* >( pAction );
698 							aBmpEx = pScaleAction->GetBitmapEx();
699 							aPos = pScaleAction->GetPoint();
700 							aSize = pScaleAction->GetSize();
701 						}
702 						::Graphic aGraphic( aBmpEx );
703 						const Size aSize100thmm( aDummyVDev.LogicToPixel( aSize ) );
704 						Size aSize100thmm2( aDummyVDev.PixelToLogic( aSize100thmm, MAP_100TH_MM ) );
705 
706 						ImplApplyBitmapResolution( aGraphic, nImageResolution,
707 							aGraphic.GetSizePixel(), awt::Size( aSize100thmm2.Width(), aSize100thmm2.Height() ) );
708 
709 						MetaAction* pNewAction;
710 						if ( pAction->GetType() == META_BMPSCALE_ACTION )
711 							pNewAction = new MetaBmpScaleAction ( aPos, aSize, aGraphic.GetBitmap() );
712 						else
713 							pNewAction = new MetaBmpExScaleAction( aPos, aSize, aGraphic.GetBitmapEx() );
714 
715 						aMtf.ReplaceAction( pNewAction, i );
716 						pAction->Delete();
717 						break;
718 					}
719 					default:
720 					case( META_BMP_ACTION ):
721 					case( META_BMPSCALEPART_ACTION ):
722 					case( META_BMPEX_ACTION ):
723 					case( META_BMPEXSCALEPART_ACTION ):
724 					case( META_MASK_ACTION ):
725 					case( META_MASKSCALE_ACTION ):
726 					break;
727 				}
728 			}
729 			rGraphic = aMtf;
730 		}
731 	}
732 }
733 
734 // ------------------------------------------------------------------------------
735 
736 void SAL_CALL GraphicProvider::storeGraphic( const uno::Reference< ::graphic::XGraphic >& rxGraphic, const uno::Sequence< beans::PropertyValue >& rMediaProperties )
737 	throw ( io::IOException, lang::IllegalArgumentException, lang::WrappedTargetException, uno::RuntimeException)
738 {
739 	SvStream* 	pOStm = NULL;
740 	String		aPath;
741 	sal_Int32 	i;
742 
743 	for( i = 0; ( i < rMediaProperties.getLength() ) && !pOStm; ++i )
744 	{
745 		const ::rtl::OUString	aName( rMediaProperties[ i ].Name );
746 		const uno::Any 			aValue( rMediaProperties[ i ].Value );
747 
748 		if( COMPARE_EQUAL == aName.compareToAscii( "URL" ) )
749 		{
750 			::rtl::OUString aURL;
751 
752 			aValue >>= aURL;
753 			pOStm = ::utl::UcbStreamHelper::CreateStream( aURL, STREAM_WRITE | STREAM_TRUNC );
754 			aPath = aURL;
755 		}
756 		else if( COMPARE_EQUAL == aName.compareToAscii( "OutputStream" ) )
757 		{
758 			uno::Reference< io::XStream > xOStm;
759 
760 			aValue >>= xOStm;
761 
762 			if( xOStm.is() )
763 				pOStm = ::utl::UcbStreamHelper::CreateStream( xOStm );
764 		}
765 	}
766 
767 	if( pOStm )
768 	{
769 		uno::Sequence< beans::PropertyValue >	aFilterDataSeq;
770 		const char*								pFilterShortName = NULL;
771 
772 		for( i = 0; i < rMediaProperties.getLength(); ++i )
773 		{
774 			const ::rtl::OUString	aName( rMediaProperties[ i ].Name );
775 			const uno::Any 			aValue( rMediaProperties[ i ].Value );
776 
777 			if( COMPARE_EQUAL == aName.compareToAscii( "FilterData" ) )
778 			{
779 				aValue >>= aFilterDataSeq;
780 			}
781 			else if( COMPARE_EQUAL == aName.compareToAscii( "MimeType" ) )
782 			{
783 				::rtl::OUString aMimeType;
784 
785 				aValue >>= aMimeType;
786 
787 				if( COMPARE_EQUAL == aMimeType.compareToAscii( MIMETYPE_BMP ) )
788 					pFilterShortName = "bmp";
789 				else if( COMPARE_EQUAL == aMimeType.compareToAscii( MIMETYPE_EPS ) )
790 					pFilterShortName = "eps";
791 				else if( COMPARE_EQUAL == aMimeType.compareToAscii( MIMETYPE_GIF ) )
792 					pFilterShortName = "gif";
793 				else if( COMPARE_EQUAL == aMimeType.compareToAscii( MIMETYPE_JPG ) )
794 					pFilterShortName = "jpg";
795 				else if( COMPARE_EQUAL == aMimeType.compareToAscii( MIMETYPE_MET ) )
796 					pFilterShortName = "met";
797 				else if( COMPARE_EQUAL == aMimeType.compareToAscii( MIMETYPE_PNG ) )
798 					pFilterShortName = "png";
799 				else if( COMPARE_EQUAL == aMimeType.compareToAscii( MIMETYPE_PCT ) )
800 					pFilterShortName = "pct";
801 				else if( COMPARE_EQUAL == aMimeType.compareToAscii( MIMETYPE_PBM ) )
802 					pFilterShortName = "pbm";
803 				else if( COMPARE_EQUAL == aMimeType.compareToAscii( MIMETYPE_PGM ) )
804 					pFilterShortName = "pgm";
805 				else if( COMPARE_EQUAL == aMimeType.compareToAscii( MIMETYPE_PPM ) )
806 					pFilterShortName = "ppm";
807 				else if( COMPARE_EQUAL == aMimeType.compareToAscii( MIMETYPE_RAS ) )
808 					pFilterShortName = "ras";
809 				else if( COMPARE_EQUAL == aMimeType.compareToAscii( MIMETYPE_SVM ) )
810 					pFilterShortName = "svm";
811 				else if( COMPARE_EQUAL == aMimeType.compareToAscii( MIMETYPE_TIF ) )
812 					pFilterShortName = "tif";
813 				else if( COMPARE_EQUAL == aMimeType.compareToAscii( MIMETYPE_EMF ) )
814 					pFilterShortName = "emf";
815 				else if( COMPARE_EQUAL == aMimeType.compareToAscii( MIMETYPE_WMF ) )
816 					pFilterShortName = "wmf";
817 				else if( COMPARE_EQUAL == aMimeType.compareToAscii( MIMETYPE_XPM ) )
818 					pFilterShortName = "xpm";
819 				else if( COMPARE_EQUAL == aMimeType.compareToAscii( MIMETYPE_SVG ) )
820 					pFilterShortName = "svg";
821 				else if( COMPARE_EQUAL == aMimeType.compareToAscii( MIMETYPE_VCLGRAPHIC ) )
822 					pFilterShortName = MIMETYPE_VCLGRAPHIC;
823 			}
824 		}
825 
826 		if( pFilterShortName )
827 		{
828 			::GraphicFilter* pFilter = ::GraphicFilter::GetGraphicFilter();
829 
830 			if( pFilter )
831 			{
832 				const uno::Reference< XInterface > 	xIFace( rxGraphic, uno::UNO_QUERY );
833 				const ::Graphic* 					pGraphic = ::unographic::Graphic::getImplementation( xIFace );
834 
835 				if( pGraphic && ( pGraphic->GetType() != GRAPHIC_NONE ) )
836 				{
837 					::Graphic aGraphic( *pGraphic );
838 					ImplApplyFilterData( aGraphic, aFilterDataSeq );
839 
840 					/* sj: using a temporary memory stream, because some graphic filters are seeking behind
841 					   stream end (which leads to an invalid argument exception then). */
842 					SvMemoryStream aMemStrm;
843 					aMemStrm.SetVersion( SOFFICE_FILEFORMAT_CURRENT );
844 					if( 0 == strcmp( pFilterShortName, MIMETYPE_VCLGRAPHIC ) )
845 						aMemStrm << aGraphic;
846 					else
847 					{
848 						pFilter->ExportGraphic( aGraphic, aPath, aMemStrm,
849 												pFilter->GetExportFormatNumberForShortName( ::rtl::OUString::createFromAscii( pFilterShortName ) ),
850 													( aFilterDataSeq.getLength() ? &aFilterDataSeq : NULL ) );
851 					}
852 					aMemStrm.Seek( STREAM_SEEK_TO_END );
853 					pOStm->Write( aMemStrm.GetData(), aMemStrm.Tell() );
854 				}
855 			}
856 		}
857 		delete pOStm;
858 	}
859 }
860 
861 }
862