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