LibreOffice Module svx (master)  1
galobj.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <sal/config.h>
21 
22 #include <com/sun/star/frame/XModel.hpp>
23 #include <com/sun/star/lang/XUnoTunnel.hpp>
24 #include <sfx2/objsh.hxx>
25 #include <comphelper/fileformat.h>
26 #include <tools/vcompat.hxx>
27 #include <tools/helpers.hxx>
28 #include <vcl/virdev.hxx>
29 #include <svx/fmmodel.hxx>
30 #include <svx/fmview.hxx>
31 #include <svx/fmpage.hxx>
32 #include <svx/galmisc.hxx>
33 #include <galobj.hxx>
34 #include <vcl/dibtools.hxx>
35 #include <vcl/filter/SvmReader.hxx>
36 #include <vcl/filter/SvmWriter.hxx>
37 #include "gallerydrawmodel.hxx"
38 #include <bitmaps.hlst>
39 
40 using namespace ::com::sun::star;
41 
42 SgaObject::SgaObject()
43 : bIsValid ( false ),
44  bIsThumbBmp ( true )
45 {
46 }
47 
48 SgaObject::SgaObject(const SgaObject& aObject)
49  : aThumbBmp(aObject.aThumbBmp)
50  , aThumbMtf(aObject.aThumbMtf)
51  , aURL(aObject.aURL)
52  , aTitle(aObject.aTitle)
53  , bIsValid(aObject.bIsValid)
54  , bIsThumbBmp(aObject.bIsThumbBmp)
55 {
56 }
57 
58 BitmapEx SgaObject::createPreviewBitmapEx(const Size& rSizePixel) const
59 {
60  BitmapEx aRetval;
61 
62  if(rSizePixel.Width() && rSizePixel.Height())
63  {
64  if(SgaObjKind::Sound == GetObjKind())
65  {
66  aRetval = BitmapEx(RID_SVXBMP_GALLERY_MEDIA);
67  }
68  else if(IsThumbBitmap())
69  {
70  aRetval = GetThumbBmp();
71  }
72  else
73  {
74  const Graphic aGraphic(GetThumbMtf());
75 
76  aRetval = aGraphic.GetBitmapEx();
77  }
78 
79  if(!aRetval.IsEmpty())
80  {
81  const Size aCurrentSizePixel(aRetval.GetSizePixel());
82  const double fScaleX(static_cast<double>(rSizePixel.Width()) / static_cast<double>(aCurrentSizePixel.Width()));
83  const double fScaleY(static_cast<double>(rSizePixel.Height()) / static_cast<double>(aCurrentSizePixel.Height()));
84  const double fScale(std::min(fScaleX, fScaleY));
85 
86  // only scale when need to decrease, no need to make bigger as original. Also
87  // prevent scaling close to 1.0 which is not needed for pixel graphics
88  if(fScale < 1.0 && fabs(1.0 - fScale) > 0.005)
89  {
90  aRetval.Scale(fScale, fScale, BmpScaleFlag::BestQuality);
91  }
92  }
93  }
94 
95  return aRetval;
96 }
97 
98 bool SgaObject::CreateThumb( const Graphic& rGraphic )
99 {
100  bool bRet = false;
101 
102  if( rGraphic.GetType() == GraphicType::Bitmap )
103  {
104  BitmapEx aBmpEx( rGraphic.GetBitmapEx() );
105  Size aBmpSize( aBmpEx.GetSizePixel() );
106 
107  if( aBmpSize.Width() && aBmpSize.Height() )
108  {
109  if( aBmpEx.GetPrefMapMode().GetMapUnit() != MapUnit::MapPixel &&
110  aBmpEx.GetPrefSize().Width() > 0 &&
111  aBmpEx.GetPrefSize().Height() > 0 )
112  {
113  Size aLogSize( OutputDevice::LogicToLogic(aBmpEx.GetPrefSize(), aBmpEx.GetPrefMapMode(), MapMode(MapUnit::Map100thMM)) );
114 
115  if( !aLogSize.IsEmpty() )
116  {
117  double fFactorLog = static_cast< double >( aLogSize.Width() ) / aLogSize.Height();
118  double fFactorPix = static_cast< double >( aBmpSize.Width() ) / aBmpSize.Height();
119 
120  if( fFactorPix > fFactorLog )
121  aBmpSize.setWidth( FRound( aBmpSize.Height() * fFactorLog ) );
122  else
123  aBmpSize.setHeight( FRound( aBmpSize.Width() / fFactorLog ) );
124 
125  aBmpEx.Scale(aBmpSize, BmpScaleFlag::BestQuality);
126  }
127  }
128 
129  // take over BitmapEx
130  aThumbBmp = aBmpEx;
131 
132  if( ( aBmpSize.Width() <= S_THUMB ) && ( aBmpSize.Height() <= S_THUMB ) )
133  {
134  aThumbBmp.Convert( BmpConversion::N8BitColors );
135  bRet = true;
136  }
137  else
138  {
139  const float fFactor = static_cast<float>(aBmpSize.Width()) / aBmpSize.Height();
140  const Size aNewSize( std::max( tools::Long(fFactor < 1. ? S_THUMB * fFactor : S_THUMB), tools::Long(8) ),
141  std::max( tools::Long(fFactor < 1. ? S_THUMB : S_THUMB / fFactor), tools::Long(8) ) );
142  if(aThumbBmp.Scale(
143  static_cast<double>(aNewSize.Width()) / aBmpSize.Width(),
144  static_cast<double>(aNewSize.Height()) / aBmpSize.Height(),
145  BmpScaleFlag::BestQuality ) )
146  {
147  aThumbBmp.Convert( BmpConversion::N8BitColors );
148  bRet = true;
149  }
150  }
151  }
152  }
153  else if( rGraphic.GetType() == GraphicType::GdiMetafile )
154  {
155  const Size aPrefSize( rGraphic.GetPrefSize() );
156  const double fFactor = static_cast<double>(aPrefSize.Width()) / static_cast<double>(aPrefSize.Height());
157  Size aSize( S_THUMB, S_THUMB );
158  if ( fFactor < 1.0 )
159  aSize.setWidth( static_cast<sal_Int32>( S_THUMB * fFactor ) );
160  else
161  aSize.setHeight( static_cast<sal_Int32>( S_THUMB / fFactor ) );
162 
163  const GraphicConversionParameters aParameters(aSize, false, true, true /*TODO: extra ", true" post-#i121194#*/);
164  aThumbBmp = rGraphic.GetBitmapEx(aParameters);
165 
166  if( !aThumbBmp.IsEmpty() )
167  {
168  aThumbBmp.Convert( BmpConversion::N8BitColors );
169  bRet = true;
170  }
171  }
172 
173  return bRet;
174 }
175 
176 void SgaObject::WriteData( SvStream& rOut, const OUString& rDestDir ) const
177 {
178  static const sal_uInt32 nInventor = COMPAT_FORMAT( 'S', 'G', 'A', '3' );
179 
180  rOut.WriteUInt32( nInventor ).WriteUInt16( 0x0004 ).WriteUInt16( GetVersion() ).WriteUInt16( static_cast<sal_uInt16>(GetObjKind()) );
181  rOut.WriteBool( bIsThumbBmp );
182 
183  if( bIsThumbBmp )
184  {
185  const SvStreamCompressFlags nOldCompressMode = rOut.GetCompressMode();
186  const sal_Int32 nOldVersion = rOut.GetVersion();
187 
188  rOut.SetCompressMode( SvStreamCompressFlags::ZBITMAP );
189  rOut.SetVersion( SOFFICE_FILEFORMAT_50 );
190 
191  WriteDIBBitmapEx(aThumbBmp, rOut);
192 
193  rOut.SetVersion( nOldVersion );
194  rOut.SetCompressMode( nOldCompressMode );
195  }
196  else
197  {
198  if(!rOut.GetError())
199  {
200  SvmWriter aWriter(rOut);
201  aWriter.Write(aThumbMtf);
202  }
203  }
204 
205  OUString aURLWithoutDestDir = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
206  aURLWithoutDestDir = aURLWithoutDestDir.replaceFirst(rDestDir, "");
207  write_uInt16_lenPrefixed_uInt8s_FromOUString(rOut, aURLWithoutDestDir, RTL_TEXTENCODING_UTF8);
208 }
209 
210 void SgaObject::ReadData(SvStream& rIn, sal_uInt16& rReadVersion )
211 {
212  sal_uInt32 nTmp32;
213  sal_uInt16 nTmp16;
214 
215  rIn.ReadUInt32( nTmp32 ).ReadUInt16( nTmp16 ).ReadUInt16( rReadVersion ).ReadUInt16( nTmp16 ).ReadCharAsBool( bIsThumbBmp );
216 
217  if( bIsThumbBmp )
218  {
219  ReadDIBBitmapEx(aThumbBmp, rIn);
220  }
221  else
222  {
223  SvmReader aReader( rIn );
224  aReader.Read( aThumbMtf );
225  }
226 
227  OUString aTmpStr = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIn, RTL_TEXTENCODING_UTF8);
228  aURL = INetURLObject(aTmpStr);
229 }
230 
231 OUString const & SgaObject::GetTitle() const
232 {
233  return aTitle;
234 }
235 
236 void SgaObject::SetTitle( const OUString& rTitle )
237 {
238  aTitle = rTitle;
239 }
240 
241 SvStream& WriteSgaObject( SvStream& rOut, const SgaObject& rObj )
242 {
243  rObj.WriteData( rOut, "" );
244  return rOut;
245 }
246 
247 SvStream& ReadSgaObject( SvStream& rIn, SgaObject& rObj )
248 {
249  sal_uInt16 nReadVersion;
250 
251  rObj.ReadData( rIn, nReadVersion );
252  rObj.bIsValid = ( rIn.GetError() == ERRCODE_NONE );
253 
254  return rIn;
255 }
256 
258 {
259 }
260 
262 {
263  Graphic aGraphic;
264  OUString aFilter;
265 
266  if ( GalleryGraphicImportRet::IMPORT_NONE != GalleryGraphicImport( rURL, aGraphic, aFilter ) )
267  Init( aGraphic, rURL );
268 }
269 
270 SgaObjectBmp::SgaObjectBmp( const Graphic& rGraphic, const INetURLObject& rURL )
271 {
272  if( FileExists( rURL ) )
273  Init( rGraphic, rURL );
274 }
275 
276 void SgaObjectBmp::Init( const Graphic& rGraphic, const INetURLObject& rURL )
277 {
278  aURL = rURL;
279  bIsValid = CreateThumb( rGraphic );
280 }
281 
282 void SgaObjectBmp::WriteData( SvStream& rOut, const OUString& rDestDir ) const
283 {
284  // Set version
285  SgaObject::WriteData( rOut, rDestDir );
286  char const aDummy[ 10 ] = { 0 };
287  rOut.WriteBytes(aDummy, 10);
289  write_uInt16_lenPrefixed_uInt8s_FromOUString(rOut, aTitle, RTL_TEXTENCODING_UTF8);
290 }
291 
292 void SgaObjectBmp::ReadData( SvStream& rIn, sal_uInt16& rReadVersion )
293 {
294 
295  SgaObject::ReadData( rIn, rReadVersion );
296  rIn.SeekRel( 10 ); // 16, 16, 32, 16
298 
299  if( rReadVersion >= 5 )
300  aTitle = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIn, RTL_TEXTENCODING_UTF8);
301 }
302 
303 
305  eSoundType( SOUND_STANDARD )
306 {
307 }
308 
310  eSoundType( SOUND_STANDARD )
311 {
312 
313  if( FileExists( rURL ) )
314  {
315  aURL = rURL;
316  aThumbBmp = Bitmap(Size(1, 1), vcl::PixelFormat::N1_BPP);
317  bIsValid = true;
318  }
319  else
320  bIsValid = false;
321 }
322 
324 {
325 }
326 
328 {
329  OUString sId;
330 
331  switch( eSoundType )
332  {
333  case SOUND_COMPUTER: sId = RID_SVXBMP_GALLERY_SOUND_1; break;
334  case SOUND_MISC: sId = RID_SVXBMP_GALLERY_SOUND_2; break;
335  case SOUND_MUSIC: sId = RID_SVXBMP_GALLERY_SOUND_3; break;
336  case SOUND_NATURE: sId = RID_SVXBMP_GALLERY_SOUND_4; break;
337  case SOUND_SPEECH: sId = RID_SVXBMP_GALLERY_SOUND_5; break;
338  case SOUND_TECHNIC: sId = RID_SVXBMP_GALLERY_SOUND_6; break;
339  case SOUND_ANIMAL: sId = RID_SVXBMP_GALLERY_SOUND_7; break;
340 
341  // standard
342  default:
343  sId = RID_SVXBMP_GALLERY_MEDIA;
344  break;
345  }
346 
347  const BitmapEx aBmpEx(sId);
348 
349  return aBmpEx;
350 }
351 
352 void SgaObjectSound::WriteData( SvStream& rOut, const OUString& rDestDir ) const
353 {
354  SgaObject::WriteData( rOut, rDestDir );
355  rOut.WriteUInt16( eSoundType );
356  write_uInt16_lenPrefixed_uInt8s_FromOUString(rOut, aTitle, RTL_TEXTENCODING_UTF8);
357 }
358 
359 void SgaObjectSound::ReadData( SvStream& rIn, sal_uInt16& rReadVersion )
360 {
361  SgaObject::ReadData( rIn, rReadVersion );
362 
363  if( rReadVersion >= 5 )
364  {
365  sal_uInt16 nTmp16;
366 
367  rIn.ReadUInt16( nTmp16 ); eSoundType = static_cast<GalSoundType>(nTmp16);
368 
369  if( rReadVersion >= 6 )
370  aTitle = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIn, RTL_TEXTENCODING_UTF8);
371  }
372 }
373 
375 {
376 }
377 
379  const INetURLObject& rURL )
380 {
381  aURL = rURL;
382  bIsValid = CreateThumb( rGraphic );
383 }
384 
386 {
387 }
388 
389 SgaObjectINet::SgaObjectINet( const Graphic& rGraphic, const INetURLObject& rURL ) :
390  SgaObjectAnim ( rGraphic, rURL )
391 {
392 }
393 
395 {
396 }
397 
399 {
400  aURL = rURL;
401  bIsValid = CreateThumb( rModel );
402 }
403 
404 
406 : mpFormModel( nullptr )
407 {
409 
410  if( !mxDoc.Is() )
411  return;
412 
413  mxDoc->DoInitNew();
414 
415  uno::Reference< lang::XUnoTunnel > xTunnel( mxDoc->GetModel(), uno::UNO_QUERY );
416  if( xTunnel.is() )
417  {
418  mpFormModel = dynamic_cast< FmFormModel* >(
419  reinterpret_cast<SdrModel*>(xTunnel->getSomething(SdrModel::getUnoTunnelId())));
420  if( mpFormModel )
421  {
422  mpFormModel->InsertPage( mpFormModel->AllocPage( false ).get() );
423  }
424  }
425 }
426 
428 {
429  if( mxDoc.Is() )
430  mxDoc->DoClose();
431 
432 }
433 
435 {
436  SvxGalleryDrawModel aModel;
437 
438  if( aModel.GetModel() )
439  {
440  if( GallerySvDrawImport( rIStm, *aModel.GetModel() ) )
441  {
442  aURL = rURL;
443  bIsValid = CreateThumb( *aModel.GetModel() );
444  }
445  }
446 }
447 
449 {
450  Graphic aGraphic;
451  ImageMap aImageMap;
452  bool bRet = false;
453 
454  if ( CreateIMapGraphic( rModel, aGraphic, aImageMap ) )
455  {
456  bRet = SgaObject::CreateThumb( aGraphic );
457  }
458  else
459  {
460  const FmFormPage* pPage = static_cast< const FmFormPage* >(rModel.GetPage(0));
461 
462  if(pPage)
463  {
464  const tools::Rectangle aObjRect(pPage->GetAllObjBoundRect());
465 
466  if(aObjRect.GetWidth() && aObjRect.GetHeight())
467  {
469  FmFormView aView(const_cast< FmFormModel& >(rModel), pVDev);
470 
471  aView.ShowSdrPage(const_cast< FmFormPage* >(pPage));
472  aView.MarkAllObj();
473  aThumbBmp = aView.GetMarkedObjBitmapEx(true);
474  aGraphic = Graphic(aThumbBmp);
475  bRet = SgaObject::CreateThumb(aGraphic);
476  }
477  }
478  }
479 
480  return bRet;
481 }
482 
483 void SgaObjectSvDraw::WriteData( SvStream& rOut, const OUString& rDestDir ) const
484 {
485  SgaObject::WriteData( rOut, rDestDir );
486  write_uInt16_lenPrefixed_uInt8s_FromOUString(rOut, aTitle, RTL_TEXTENCODING_UTF8);
487 }
488 
489 void SgaObjectSvDraw::ReadData( SvStream& rIn, sal_uInt16& rReadVersion )
490 {
491  SgaObject::ReadData( rIn, rReadVersion );
492 
493  if( rReadVersion >= 5 )
494  aTitle = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIn, RTL_TEXTENCODING_UTF8);
495 }
496 
497 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SvStream & WriteBool(bool b)
virtual void ReadData(SvStream &rIn, sal_uInt16 &rReadVersion) override
Definition: galobj.cxx:359
virtual ~SgaObjectSound() override
Definition: galobj.cxx:323
URL aURL
virtual BitmapEx GetThumbBmp() const override
Definition: galobj.cxx:327
SvStream & WriteUInt16(sal_uInt16 nUInt16)
bool CreateIMapGraphic(const FmFormModel &rModel, Graphic &rGraphic, ImageMap &rImageMap)
Definition: galmisc.cxx:120
SvStream & ReadUInt16(sal_uInt16 &rUInt16)
SAL_WARN_UNUSED_RESULT Point LogicToLogic(const Point &rPtSource, const MapMode *pMapModeSource, const MapMode *pMapModeDest) const
SvStream & ReadSgaObject(SvStream &rIn, SgaObject &rObj)
Definition: galobj.cxx:247
const tools::Rectangle & GetAllObjBoundRect() const
Definition: svdpage.cxx:752
virtual void WriteData(SvStream &rOut, const OUString &rDestDir) const override
Definition: galobj.cxx:352
bool CreateThumb(const FmFormModel &rModel)
Definition: galobj.cxx:448
sal_Int32 GetVersion() const
bool Is() const
virtual void WriteData(SvStream &rOut, const OUString &rDestDir) const override
Definition: galobj.cxx:483
bool Scale(const Size &rNewSize, BmpScaleFlag nScaleFlag=BmpScaleFlag::Default)
long Long
SvStream & ReadCharAsBool(bool &rBool)
css::uno::Reference< css::frame::XModel3 > GetModel() const
virtual SdrPageView * ShowSdrPage(SdrPage *pPage) override
Definition: fmview.cxx:297
SvStream & WriteSgaObject(SvStream &rOut, const SgaObject &rObj)
Definition: galobj.cxx:241
FmFormModel * GetModel() const
FmFormModel * mpFormModel
SvStreamCompressFlags GetCompressMode() const
bool Convert(BmpConversion eConversion)
sal_uInt64 SeekRel(sal_Int64 nPos)
constexpr tools::Long Width() const
OString read_uInt16_lenPrefixed_uInt8s_ToOString(SvStream &rStrm)
ErrCode GetError() const
bool ReadDIBBitmapEx(BitmapEx &rTarget, SvStream &rIStm, bool bFileHeader, bool bMSOFormat)
std::size_t write_uInt16_lenPrefixed_uInt8s_FromOUString(SvStream &rStrm, std::u16string_view rStr, rtl_TextEncoding eEnc)
SvStream & WriteUInt32(sal_uInt32 nUInt32)
#define S_THUMB
Definition: galobj.hxx:29
static bool FileExists(const INetURLObject &rURL, std::u16string_view rExt)
virtual void ReadData(SvStream &rIn, sal_uInt16 &rReadVersion) override
Definition: galobj.cxx:489
SvStream & ReadUInt32(sal_uInt32 &rUInt32)
void MarkAllObj(SdrPageView *pPV=nullptr)
Definition: svdmrkv.cxx:2533
bool IsEmpty() const
virtual void InsertPage(SdrPage *pPage, sal_uInt16 nPos=0xFFFF) override
Definition: fmmodel.cxx:80
bool WriteDIBBitmapEx(const BitmapEx &rSource, SvStream &rOStm)
OUString read_uInt16_lenPrefixed_uInt8s_ToOUString(SvStream &rStrm, rtl_TextEncoding eEnc)
GalleryGraphicImportRet GalleryGraphicImport(const INetURLObject &rURL, Graphic &rGraphic, OUString &rFilterName)
Definition: galmisc.cxx:51
GraphicType GetType() const
tools::Long FRound(double fVal)
sal_uInt32 COMPAT_FORMAT(char char1, char char2, char char3, char char4)
static SfxObjectShell * CreateObjectByFactoryName(const OUString &rURL, SfxObjectCreateMode=SfxObjectCreateMode::STANDARD)
virtual void ReadData(SvStream &rIn, sal_uInt16 &rReadVersion) override
Definition: galobj.cxx:292
const SdrPage * GetPage(sal_uInt16 nPgNum) const
Definition: svdmodel.cxx:1795
std::size_t WriteBytes(const void *pData, std::size_t nSize)
SvStreamCompressFlags
BitmapEx GetBitmapEx(const GraphicConversionParameters &rParameters=GraphicConversionParameters()) const
void SetVersion(sal_Int32 n)
GalSoundType eSoundType
Definition: galobj.hxx:95
void Init(const Graphic &rGraphic, const INetURLObject &rURL)
Definition: galobj.cxx:276
bool GallerySvDrawImport(SvStream &rIStm, SdrModel &rModel)
Definition: galmisc.cxx:76
virtual rtl::Reference< SdrPage > AllocPage(bool bMasterPage) override
Definition: fmmodel.cxx:75
std::size_t write_uInt16_lenPrefixed_uInt8s_FromOString(SvStream &rStrm, std::string_view rStr)
GalSoundType
Definition: galobj.hxx:32
Size GetPrefSize() const
virtual void WriteData(SvStream &rOut, const OUString &rDestDir) const override
Definition: galobj.cxx:282
#define ERRCODE_NONE
constexpr tools::Long Height() const
bool DoInitNew(SfxMedium *pMedium=nullptr)
BitmapEx GetMarkedObjBitmapEx(bool bNoVDevIfOneBmpMarked=false, const sal_uInt32 nMaximumQuadraticPixels=500000, const std::optional< Size > &rTargetDPI=std::nullopt) const
Definition: svdxcgv.cxx:428
static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId()
Definition: svdmodel.cxx:1881
SfxObjectShellLock mxDoc
sal_uInt16 GetVersion(sal_uInt16)
Definition: legacyitem.cxx:29
void SetCompressMode(SvStreamCompressFlags nNewMode)
const Size & GetSizePixel() const
OUString sId