/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <sal/config.h>
#include <com/sun/star/frame/XModel.hpp>
#include <sfx2/objsh.hxx>
#include <comphelper/fileformat.h>
#include <comphelper/servicehelper.hxx>
#include <tools/vcompat.hxx>
#include <tools/helpers.hxx>
#include <vcl/virdev.hxx>
#include <svx/fmmodel.hxx>
#include <svx/fmview.hxx>
#include <svx/fmpage.hxx>
#include <svx/galmisc.hxx>
#include <galobj.hxx>
#include <vcl/dibtools.hxx>
#include <vcl/filter/SvmReader.hxx>
#include <vcl/filter/SvmWriter.hxx>
#include "gallerydrawmodel.hxx"
#include <bitmaps.hlst>
using namespace ::com::sun::star;
SgaObject::SgaObject()
: bIsValid ( false ),
bIsThumbBmp ( true )
{
}
SgaObject::SgaObject(const SgaObject& aObject)
: aThumbBmp(aObject.aThumbBmp)
, aThumbMtf(aObject.aThumbMtf)
, aURL(aObject.aURL)
, aTitle(aObject.aTitle)
, bIsValid(aObject.bIsValid)
, bIsThumbBmp(aObject.bIsThumbBmp)
{
}
BitmapEx SgaObject::createPreviewBitmapEx(const Size& rSizePixel) const
{
BitmapEx aRetval;
if(rSizePixel.Width() && rSizePixel.Height())
{
if(SgaObjKind::Sound == GetObjKind())
{
aRetval = BitmapEx(RID_SVXBMP_GALLERY_MEDIA);
}
else if(IsThumbBitmap())
{
aRetval = GetThumbBmp();
}
else
{
const Graphic aGraphic(GetThumbMtf());
aRetval = aGraphic.GetBitmapEx();
}
if(!aRetval.IsEmpty())
{
const Size aCurrentSizePixel(aRetval.GetSizePixel());
const double fScaleX(static_cast<double>(rSizePixel.Width()) / static_cast<double>(aCurrentSizePixel.Width()));
const double fScaleY(static_cast<double>(rSizePixel.Height()) / static_cast<double>(aCurrentSizePixel.Height()));
const double fScale(std::min(fScaleX, fScaleY));
// only scale when need to decrease, no need to make bigger as original. Also
// prevent scaling close to 1.0 which is not needed for pixel graphics
if(fScale < 1.0 && fabs(1.0 - fScale) > 0.005)
{
aRetval.Scale(fScale, fScale, BmpScaleFlag::BestQuality);
}
}
}
return aRetval;
}
bool SgaObject::CreateThumb( const Graphic& rGraphic )
{
bool bRet = false;
if( rGraphic.GetType() == GraphicType::Bitmap )
{
BitmapEx aBmpEx( rGraphic.GetBitmapEx() );
Size aBmpSize( aBmpEx.GetSizePixel() );
if( aBmpSize.Width() && aBmpSize.Height() )
{
if( aBmpEx.GetPrefMapMode().GetMapUnit() != MapUnit::MapPixel &&
aBmpEx.GetPrefSize().Width() > 0 &&
aBmpEx.GetPrefSize().Height() > 0 )
{
Size aLogSize( OutputDevice::LogicToLogic(aBmpEx.GetPrefSize(), aBmpEx.GetPrefMapMode(), MapMode(MapUnit::Map100thMM)) );
if( !aLogSize.IsEmpty() )
{
double fFactorLog = static_cast< double >( aLogSize.Width() ) / aLogSize.Height();
double fFactorPix = static_cast< double >( aBmpSize.Width() ) / aBmpSize.Height();
if( fFactorPix > fFactorLog )
aBmpSize.setWidth( basegfx::fround<tools::Long>( aBmpSize.Height() * fFactorLog ) );
else
aBmpSize.setHeight( basegfx::fround<tools::Long>( aBmpSize.Width() / fFactorLog ) );
aBmpEx.Scale(aBmpSize, BmpScaleFlag::BestQuality);
}
}
// take over BitmapEx
aThumbBmp = aBmpEx;
if( ( aBmpSize.Width() <= S_THUMB ) && ( aBmpSize.Height() <= S_THUMB ) )
{
aThumbBmp.Convert( BmpConversion::N8BitColors );
bRet = true;
}
else
{
const float fFactor = static_cast<float>(aBmpSize.Width()) / aBmpSize.Height();
const Size aNewSize( std::max( tools::Long(fFactor < 1. ? S_THUMB * fFactor : S_THUMB), tools::Long(8) ),
std::max( tools::Long(fFactor < 1. ? S_THUMB : S_THUMB / fFactor), tools::Long(8) ) );
if(aThumbBmp.Scale(
static_cast<double>(aNewSize.Width()) / aBmpSize.Width(),
static_cast<double>(aNewSize.Height()) / aBmpSize.Height(),
BmpScaleFlag::BestQuality ) )
{
aThumbBmp.Convert( BmpConversion::N8BitColors );
bRet = true;
}
}
}
}
else if( rGraphic.GetType() == GraphicType::GdiMetafile )
{
const Size aPrefSize( rGraphic.GetPrefSize() );
const double fFactor = static_cast<double>(aPrefSize.Width()) / static_cast<double>(aPrefSize.Height());
Size aSize( S_THUMB, S_THUMB );
if ( fFactor < 1.0 )
aSize.setWidth( static_cast<sal_Int32>( S_THUMB * fFactor ) );
else
aSize.setHeight( static_cast<sal_Int32>( S_THUMB / fFactor ) );
const GraphicConversionParameters aParameters(aSize, false, true, true /*TODO: extra ", true" post-#i121194#*/);
aThumbBmp = rGraphic.GetBitmapEx(aParameters);
if( !aThumbBmp.IsEmpty() )
{
aThumbBmp.Convert( BmpConversion::N8BitColors );
bRet = true;
}
}
return bRet;
}
void SgaObject::WriteData( SvStream& rOut, const OUString& rDestDir ) const
{
static const sal_uInt32 nInventor = COMPAT_FORMAT( 'S', 'G', 'A', '3' );
rOut.WriteUInt32( nInventor ).WriteUInt16( 0x0004 ).WriteUInt16( GetVersion() ).WriteUInt16( static_cast<sal_uInt16>(GetObjKind()) );
rOut.WriteBool( bIsThumbBmp );
if( bIsThumbBmp )
{
const SvStreamCompressFlags nOldCompressMode = rOut.GetCompressMode();
const sal_Int32 nOldVersion = rOut.GetVersion();
rOut.SetCompressMode( SvStreamCompressFlags::ZBITMAP );
rOut.SetVersion( SOFFICE_FILEFORMAT_50 );
WriteDIBBitmapEx(aThumbBmp, rOut);
rOut.SetVersion( nOldVersion );
rOut.SetCompressMode( nOldCompressMode );
}
else
{
if(!rOut.GetError())
{
SvmWriter aWriter(rOut);
aWriter.Write(aThumbMtf);
}
}
OUString aURLWithoutDestDir = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
aURLWithoutDestDir = aURLWithoutDestDir.replaceFirst(rDestDir, "");
write_uInt16_lenPrefixed_uInt8s_FromOUString(rOut, aURLWithoutDestDir, RTL_TEXTENCODING_UTF8);
}
void SgaObject::ReadData(SvStream& rIn, sal_uInt16& rReadVersion )
{
sal_uInt32 nTmp32;
sal_uInt16 nTmp16;
rIn.ReadUInt32( nTmp32 ).ReadUInt16( nTmp16 ).ReadUInt16( rReadVersion ).ReadUInt16( nTmp16 ).ReadCharAsBool( bIsThumbBmp );
if( bIsThumbBmp )
{
ReadDIBBitmapEx(aThumbBmp, rIn);
}
else
{
SvmReader aReader( rIn );
aReader.Read( aThumbMtf );
}
OUString aTmpStr = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIn, RTL_TEXTENCODING_UTF8);
aURL = INetURLObject(aTmpStr);
}
OUString const & SgaObject::GetTitle() const
{
return aTitle;
}
void SgaObject::SetTitle( const OUString& rTitle )
{
aTitle = rTitle;
}
SvStream& WriteSgaObject( SvStream& rOut, const SgaObject& rObj )
{
rObj.WriteData( rOut, u""_ustr );
return rOut;
}
SvStream& ReadSgaObject( SvStream& rIn, SgaObject& rObj )
{
sal_uInt16 nReadVersion;
rObj.ReadData( rIn, nReadVersion );
rObj.bIsValid = ( rIn.GetError() == ERRCODE_NONE );
return rIn;
}
SgaObjectBmp::SgaObjectBmp()
{
}
SgaObjectBmp::SgaObjectBmp( const INetURLObject& rURL )
{
Graphic aGraphic;
OUString aFilter;
if ( GalleryGraphicImportRet::IMPORT_NONE != GalleryGraphicImport( rURL, aGraphic, aFilter ) )
Init( aGraphic, rURL );
}
SgaObjectBmp::SgaObjectBmp( const Graphic& rGraphic, const INetURLObject& rURL )
{
if( FileExists( rURL ) )
Init( rGraphic, rURL );
}
void SgaObjectBmp::Init( const Graphic& rGraphic, const INetURLObject& rURL )
{
aURL = rURL;
bIsValid = CreateThumb( rGraphic );
}
void SgaObjectBmp::WriteData( SvStream& rOut, const OUString& rDestDir ) const
{
// Set version
SgaObject::WriteData( rOut, rDestDir );
char const aDummy[ 10 ] = { 0 };
rOut.WriteBytes(aDummy, 10);
write_uInt16_lenPrefixed_uInt8s_FromOString(rOut, ""); //dummy
write_uInt16_lenPrefixed_uInt8s_FromOUString(rOut, aTitle, RTL_TEXTENCODING_UTF8);
}
void SgaObjectBmp::ReadData( SvStream& rIn, sal_uInt16& rReadVersion )
{
SgaObject::ReadData( rIn, rReadVersion );
rIn.SeekRel( 10 ); // 16, 16, 32, 16
read_uInt16_lenPrefixed_uInt8s_ToOString(rIn); //dummy
if( rReadVersion >= 5 )
aTitle = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIn, RTL_TEXTENCODING_UTF8);
}
SgaObjectSound::SgaObjectSound() :
eSoundType( SOUND_STANDARD )
{
}
SgaObjectSound::SgaObjectSound( const INetURLObject& rURL ) :
eSoundType( SOUND_STANDARD )
{
if( FileExists( rURL ) )
{
aURL = rURL;
aThumbBmp = Bitmap(Size(1, 1), vcl::PixelFormat::N8_BPP);
bIsValid = true;
}
else
bIsValid = false;
}
SgaObjectSound::~SgaObjectSound()
{
}
BitmapEx SgaObjectSound::GetThumbBmp() const
{
OUString sId;
switch( eSoundType )
{
case SOUND_COMPUTER: sId = RID_SVXBMP_GALLERY_SOUND_1; break;
case SOUND_MISC: sId = RID_SVXBMP_GALLERY_SOUND_2; break;
case SOUND_MUSIC: sId = RID_SVXBMP_GALLERY_SOUND_3; break;
case SOUND_NATURE: sId = RID_SVXBMP_GALLERY_SOUND_4; break;
case SOUND_SPEECH: sId = RID_SVXBMP_GALLERY_SOUND_5; break;
case SOUND_TECHNIC: sId = RID_SVXBMP_GALLERY_SOUND_6; break;
case SOUND_ANIMAL: sId = RID_SVXBMP_GALLERY_SOUND_7; break;
// standard
default:
sId = RID_SVXBMP_GALLERY_MEDIA;
break;
}
const BitmapEx aBmpEx(sId);
return aBmpEx;
}
void SgaObjectSound::WriteData( SvStream& rOut, const OUString& rDestDir ) const
{
SgaObject::WriteData( rOut, rDestDir );
rOut.WriteUInt16( eSoundType );
write_uInt16_lenPrefixed_uInt8s_FromOUString(rOut, aTitle, RTL_TEXTENCODING_UTF8);
}
void SgaObjectSound::ReadData( SvStream& rIn, sal_uInt16& rReadVersion )
{
SgaObject::ReadData( rIn, rReadVersion );
if( rReadVersion >= 5 )
{
sal_uInt16 nTmp16;
rIn.ReadUInt16( nTmp16 ); eSoundType = static_cast<GalSoundType>(nTmp16);
if( rReadVersion >= 6 )
aTitle = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIn, RTL_TEXTENCODING_UTF8);
}
}
SgaObjectAnim::SgaObjectAnim()
{
}
SgaObjectAnim::SgaObjectAnim( const Graphic& rGraphic,
const INetURLObject& rURL )
{
aURL = rURL;
bIsValid = CreateThumb( rGraphic );
}
SgaObjectINet::SgaObjectINet()
{
}
SgaObjectINet::SgaObjectINet( const Graphic& rGraphic, const INetURLObject& rURL ) :
SgaObjectAnim ( rGraphic, rURL )
{
}
SgaObjectSvDraw::SgaObjectSvDraw()
{
}
SgaObjectSvDraw::SgaObjectSvDraw( const FmFormModel& rModel, const INetURLObject& rURL )
{
aURL = rURL;
bIsValid = CreateThumb( rModel );
}
SvxGalleryDrawModel::SvxGalleryDrawModel()
: mpFormModel( nullptr )
{
mxDoc = SfxObjectShell::CreateObjectByFactoryName( u"sdraw"_ustr );
if( !mxDoc.Is() )
return;
mxDoc->DoInitNew();
mpFormModel
= dynamic_cast<FmFormModel*>(comphelper::getFromUnoTunnel<SdrModel>(mxDoc->GetModel()));
if (mpFormModel)
{
mpFormModel->InsertPage(mpFormModel->AllocPage(false).get());
}
}
SvxGalleryDrawModel::~SvxGalleryDrawModel()
{
if( mxDoc.Is() )
mxDoc->DoClose();
}
SgaObjectSvDraw::SgaObjectSvDraw( SvStream& rIStm, const INetURLObject& rURL )
{
SvxGalleryDrawModel aModel;
if( aModel.GetModel() )
{
if( GallerySvDrawImport( rIStm, *aModel.GetModel() ) )
{
aURL = rURL;
bIsValid = CreateThumb( *aModel.GetModel() );
}
}
}
bool SgaObjectSvDraw::CreateThumb( const FmFormModel& rModel )
{
Graphic aGraphic;
ImageMap aImageMap;
bool bRet = false;
if ( CreateIMapGraphic( rModel, aGraphic, aImageMap ) )
{
bRet = SgaObject::CreateThumb( aGraphic );
}
else
{
const FmFormPage* pPage = static_cast< const FmFormPage* >(rModel.GetPage(0));
if(pPage)
{
const tools::Rectangle aObjRect(pPage->GetAllObjBoundRect());
if(aObjRect.GetWidth() && aObjRect.GetHeight())
{
ScopedVclPtrInstance< VirtualDevice > pVDev;
FmFormView aView(const_cast< FmFormModel& >(rModel), pVDev);
aView.ShowSdrPage(const_cast< FmFormPage* >(pPage));
aView.MarkAllObj();
aThumbBmp = aView.GetMarkedObjBitmapEx(true);
aGraphic = Graphic(aThumbBmp);
bRet = SgaObject::CreateThumb(aGraphic);
}
}
}
return bRet;
}
void SgaObjectSvDraw::WriteData( SvStream& rOut, const OUString& rDestDir ) const
{
SgaObject::WriteData( rOut, rDestDir );
write_uInt16_lenPrefixed_uInt8s_FromOUString(rOut, aTitle, RTL_TEXTENCODING_UTF8);
}
void SgaObjectSvDraw::ReadData( SvStream& rIn, sal_uInt16& rReadVersion )
{
SgaObject::ReadData( rIn, rReadVersion );
if( rReadVersion >= 5 )
aTitle = read_uInt16_lenPrefixed_uInt8s_ToOUString(rIn, RTL_TEXTENCODING_UTF8);
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V530 The return value of function 'read_uInt16_lenPrefixed_uInt8s_ToOString' is required to be utilized.