Files
core/svx/source/dialog/compressgraphicdialog.cxx
asif196 e6afe9d1bc tdf#145160 Set default choice in Image Compression dialog per last format
Currently the compression format selected by default in the compressed
dialog box for an image depends on the option last selected by the user
to compress an image except when it is opened for the first time after
opening libreoffice in which case the `PNG Compression` option is
selected. This happens regardless of the image format. This patch sets
the default option based on the format of the image each time the dialog
box is opened. If it is a JPG, then `JPEG Quality` will be chosen otherwise
the 'PNG Compression' will be chosen.

Change-Id: Ib8eb84b6b1e226f5bf6e98aa1e0477ffced9be73
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/180758
Reviewed-by: Sahil Gautam <sahil.gautam.extern@allotropia.de>
Tested-by: Jenkins
2025-06-03 14:21:21 +02:00

455 lines
17 KiB
C++

/* -*- 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 "dlgunit.hxx"
#include <utility>
#include <vcl/fieldvalues.hxx>
#include <vcl/graph.hxx>
#include <vcl/graphicfilter.hxx>
#include <vcl/virdev.hxx>
#include <vcl/svapp.hxx>
#include <vcl/settings.hxx>
#include <vcl/weld.hxx>
#include <svx/strings.hrc>
#include <svx/svdograf.hxx>
#include <svx/sdgcpitm.hxx>
#include <svx/dialmgr.hxx>
#include <svx/graphichelper.hxx>
#include <svx/compressgraphicdialog.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/module.hxx>
#include <comphelper/fileformat.h>
#include <comphelper/propertyvalue.hxx>
#include <com/sun/star/uno/Sequence.hxx>
#include <tools/stream.hxx>
#include <unotools/localedatawrapper.hxx>
// tdf#146929 - remember user settings within the current session
// memp is filled in dtor and restored after initialization
namespace
{
struct memParam {
bool ReduceResolutionCB = true;
int MFNewWidth = 1;
int MFNewHeight = 1;
int InterpolationCombo = 3;
};
memParam memp;
}
using namespace com::sun::star::uno;
using namespace com::sun::star::beans;
CompressGraphicsDialog::CompressGraphicsDialog( weld::Window* pParent, SdrGrafObj* pGraphicObj, SfxBindings& rBindings ) :
GenericDialogController( pParent, u"svx/ui/compressgraphicdialog.ui"_ustr, u"CompressGraphicDialog"_ustr ),
m_xGraphicObj ( pGraphicObj ),
m_aGraphic ( pGraphicObj->GetGraphicObject().GetGraphic() ),
m_aViewSize100mm ( pGraphicObj->GetLogicRect().GetSize() ),
m_rBindings ( rBindings ),
m_dResolution ( 300 )
{
const SdrGrafCropItem& rCrop = m_xGraphicObj->GetMergedItem(SDRATTR_GRAFCROP);
m_aCropRectangle = tools::Rectangle(rCrop.GetLeft(), rCrop.GetTop(), rCrop.GetRight(), rCrop.GetBottom());
Initialize();
recallParameter();
}
CompressGraphicsDialog::CompressGraphicsDialog( weld::Window* pParent, Graphic aGraphic, Size rViewSize100mm, tools::Rectangle const & rCropRectangle, SfxBindings& rBindings ) :
GenericDialogController( pParent, u"svx/ui/compressgraphicdialog.ui"_ustr, u"CompressGraphicDialog"_ustr ),
m_xGraphicObj ( nullptr ),
m_aGraphic (std::move( aGraphic )),
m_aViewSize100mm ( rViewSize100mm ),
m_aCropRectangle ( rCropRectangle ),
m_rBindings ( rBindings ),
m_dResolution ( 300 )
{
Initialize();
recallParameter();
}
CompressGraphicsDialog::~CompressGraphicsDialog()
{
}
void CompressGraphicsDialog::recallParameter()
{
m_xReduceResolutionCB->set_active( memp.ReduceResolutionCB );
if (memp.ReduceResolutionCB && (memp.MFNewWidth > 1))
m_xMFNewWidth->set_value( memp.MFNewWidth );
if (memp.ReduceResolutionCB && (memp.MFNewHeight > 1))
m_xMFNewHeight->set_value( memp.MFNewHeight );
m_xInterpolationCombo->set_active( memp.InterpolationCombo );
UpdateSensitivity(m_xReduceResolutionCB->get_active());
}
void CompressGraphicsDialog::Initialize()
{
m_xLabelGraphicType = m_xBuilder->weld_label(u"label-graphic-type"_ustr);
m_xFixedText2 = m_xBuilder->weld_label(u"label-original-size"_ustr);
m_xFixedText3 = m_xBuilder->weld_label(u"label-view-size"_ustr);
m_xFixedText5 = m_xBuilder->weld_label(u"label-image-capacity"_ustr);
m_xFixedText6 = m_xBuilder->weld_label(u"label-new-capacity"_ustr);
m_xJpegCompRB = m_xBuilder->weld_radio_button(u"radio-jpeg"_ustr);
m_xCompressionMF = m_xBuilder->weld_spin_button(u"spin-compression"_ustr);
m_xCompressionSlider = m_xBuilder->weld_scale(u"scale-compression"_ustr);
m_xLosslessRB = m_xBuilder->weld_radio_button(u"radio-lossless"_ustr);
m_xQualityMF = m_xBuilder->weld_spin_button(u"spin-quality"_ustr);
m_xQualitySlider = m_xBuilder->weld_scale(u"scale-quality"_ustr);
m_xReduceResolutionCB = m_xBuilder->weld_check_button(u"checkbox-change-resolution"_ustr);
m_xMFNewWidth = m_xBuilder->weld_spin_button(u"spin-new-width"_ustr);
m_xMFNewHeight = m_xBuilder->weld_spin_button(u"spin-new-height"_ustr);
m_xResolutionLB = m_xBuilder->weld_combo_box(u"combo-resolution"_ustr);
m_xBtnCalculate = m_xBuilder->weld_button(u"calculate"_ustr);
m_xInterpolationCombo = m_xBuilder->weld_combo_box(u"interpolation-method-combo"_ustr);
m_xBtnOkay = m_xBuilder->weld_button(u"ok"_ustr);
m_xInterpolationCombo->set_active_text(u"Lanczos"_ustr);
m_xInterpolationCombo->connect_changed(LINK(this, CompressGraphicsDialog, NewInterpolationModifiedHdl));
m_xMFNewWidth->connect_value_changed( LINK( this, CompressGraphicsDialog, NewWidthModifiedHdl ));
m_xMFNewHeight->connect_value_changed( LINK( this, CompressGraphicsDialog, NewHeightModifiedHdl ));
m_xResolutionLB->connect_changed( LINK( this, CompressGraphicsDialog, ResolutionModifiedHdl ));
m_xBtnCalculate->connect_clicked( LINK( this, CompressGraphicsDialog, CalculateClickHdl ) );
m_xLosslessRB->connect_toggled( LINK( this, CompressGraphicsDialog, ToggleCompressionRB ) );
m_xJpegCompRB->connect_toggled( LINK( this, CompressGraphicsDialog, ToggleCompressionRB ) );
m_xReduceResolutionCB->connect_toggled( LINK( this, CompressGraphicsDialog, ToggleReduceResolutionRB ) );
m_xQualitySlider->connect_value_changed( LINK( this, CompressGraphicsDialog, SlideHdl ));
m_xCompressionSlider->connect_value_changed( LINK( this, CompressGraphicsDialog, SlideHdl ));
m_xQualityMF->connect_value_changed( LINK( this, CompressGraphicsDialog, NewQualityModifiedHdl ));
m_xCompressionMF->connect_value_changed( LINK( this, CompressGraphicsDialog, NewCompressionModifiedHdl ));
const auto& pGfxLink = m_aGraphic.GetSharedGfxLink();
bool bDefaultChoice = (pGfxLink) ? (pGfxLink->GetType() == GfxLinkType::NativeJpg) : false;
m_xJpegCompRB->set_active(bDefaultChoice);
m_xQualitySlider->set_sensitive(bDefaultChoice);
m_xQualityMF->set_sensitive(bDefaultChoice);
m_xReduceResolutionCB->set_active(true);
m_xBtnOkay->connect_clicked( LINK( this, CompressGraphicsDialog, OkayClickHdl ) );
UpdateNewWidthMF();
UpdateNewHeightMF();
UpdateResolutionLB();
Update();
}
void CompressGraphicsDialog::Update()
{
auto pGfxLink = m_aGraphic.GetSharedGfxLink();
m_xLabelGraphicType->set_label(GraphicHelper::GetImageType(m_aGraphic));
const FieldUnit eFieldUnit = m_rBindings.GetDispatcher()->GetModule()->GetFieldUnit();
const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() );
sal_Unicode cSeparator = rLocaleWrapper.getNumDecimalSep()[0];
ScopedVclPtrInstance<VirtualDevice> pDummyVDev;
pDummyVDev->EnableOutput( false );
pDummyVDev->SetMapMode( m_aGraphic.GetPrefMapMode() );
Size aPixelSize = m_aGraphic.GetSizePixel();
Size aOriginalSize100mm(pDummyVDev->PixelToLogic(m_aGraphic.GetSizePixel(), MapMode(MapUnit::Map100thMM)));
OUString aBitmapSizeString = SvxResId(STR_IMAGE_ORIGINAL_SIZE);
OUString aWidthString = GetUnitString( aOriginalSize100mm.Width(), eFieldUnit, cSeparator );
OUString aHeightString = GetUnitString( aOriginalSize100mm.Height(), eFieldUnit, cSeparator );
aBitmapSizeString = aBitmapSizeString.replaceAll("$(WIDTH)", aWidthString);
aBitmapSizeString = aBitmapSizeString.replaceAll("$(HEIGHT)", aHeightString);
aBitmapSizeString = aBitmapSizeString.replaceAll("$(WIDTH_IN_PX)", OUString::number(aPixelSize.Width()));
aBitmapSizeString = aBitmapSizeString.replaceAll("$(HEIGHT_IN_PX)", OUString::number(aPixelSize.Height()));
m_xFixedText2->set_label(aBitmapSizeString);
int aValX = static_cast<int>(aPixelSize.Width() / GetViewWidthInch());
OUString aViewSizeString = SvxResId(STR_IMAGE_VIEW_SIZE);
aWidthString = GetUnitString( m_aViewSize100mm.Width(), eFieldUnit, cSeparator );
aHeightString = GetUnitString( m_aViewSize100mm.Height(), eFieldUnit, cSeparator );
aViewSizeString = aViewSizeString.replaceAll("$(WIDTH)", aWidthString);
aViewSizeString = aViewSizeString.replaceAll("$(HEIGHT)", aHeightString);
aViewSizeString = aViewSizeString.replaceAll("$(DPI)", OUString::number(aValX));
m_xFixedText3->set_label(aViewSizeString);
m_aNativeSize = pGfxLink ? pGfxLink->GetDataSize() : 0;
OUString aNativeSizeString = SvxResId(STR_IMAGE_CAPACITY);
aNativeSizeString = aNativeSizeString.replaceAll("$(CAPACITY)", OUString::number( m_aNativeSize / 1024 ));
m_xFixedText5->set_label(aNativeSizeString);
m_xFixedText6->set_label(u"??"_ustr);
}
void CompressGraphicsDialog::UpdateSensitivity(const bool bSensitive)
{
m_xMFNewWidth->set_sensitive(bSensitive);
m_xMFNewHeight->set_sensitive(bSensitive);
m_xResolutionLB->set_sensitive(bSensitive);
m_xInterpolationCombo->set_sensitive(bSensitive);
}
void CompressGraphicsDialog::UpdateNewWidthMF()
{
int nPixelX = static_cast<sal_Int32>( GetViewWidthInch() * m_dResolution );
m_xMFNewWidth->set_value(nPixelX);
}
void CompressGraphicsDialog::UpdateNewHeightMF()
{
int nPixelY = static_cast<sal_Int32>( GetViewHeightInch() * m_dResolution );
m_xMFNewHeight->set_value(nPixelY);
}
void CompressGraphicsDialog::UpdateResolutionLB()
{
m_xResolutionLB->set_entry_text( OUString::number( static_cast<sal_Int32>(m_dResolution) ) );
}
double CompressGraphicsDialog::GetViewWidthInch() const
{
return static_cast<double>(vcl::ConvertValue(m_aViewSize100mm.Width(), 2, MapUnit::Map100thMM, FieldUnit::INCH)) / 100.0;
}
double CompressGraphicsDialog::GetViewHeightInch() const
{
return static_cast<double>(vcl::ConvertValue(m_aViewSize100mm.Height(), 2, MapUnit::Map100thMM, FieldUnit::INCH)) / 100.0;
}
BmpScaleFlag CompressGraphicsDialog::GetSelectedInterpolationType() const
{
OUString aSelectionText = m_xInterpolationCombo->get_active_text();
if( aSelectionText == "Lanczos" ) {
return BmpScaleFlag::Lanczos;
} else if( aSelectionText == "Bilinear" ) {
return BmpScaleFlag::BiLinear;
} else if( aSelectionText == "Bicubic" ) {
return BmpScaleFlag::BiCubic;
} else if ( aSelectionText == "None" ) {
return BmpScaleFlag::Fast;
}
return BmpScaleFlag::BestQuality;
}
void CompressGraphicsDialog::Compress(SvStream& aStream)
{
BitmapEx aBitmap = m_aGraphic.GetBitmapEx();
if ( m_xReduceResolutionCB->get_active() )
{
tools::Long nPixelX = static_cast<tools::Long>( GetViewWidthInch() * m_dResolution );
tools::Long nPixelY = static_cast<tools::Long>( GetViewHeightInch() * m_dResolution );
aBitmap.Scale( Size( nPixelX, nPixelY ), GetSelectedInterpolationType() );
}
Graphic aScaledGraphic( aBitmap );
GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
Sequence< PropertyValue > aFilterData{
comphelper::makePropertyValue(u"Interlaced"_ustr, sal_Int32(0)),
comphelper::makePropertyValue(u"Compression"_ustr, static_cast<sal_Int32>(m_xCompressionMF->get_value())),
comphelper::makePropertyValue(u"Quality"_ustr, static_cast<sal_Int32>(m_xQualityMF->get_value()))
};
OUString aGraphicFormatName = m_xLosslessRB->get_active() ? u"png"_ustr : u"jpg"_ustr;
sal_uInt16 nFilterFormat = rFilter.GetExportFormatNumberForShortName( aGraphicFormatName );
rFilter.ExportGraphic( aScaledGraphic, u"none", aStream, nFilterFormat, &aFilterData );
}
IMPL_LINK_NOARG( CompressGraphicsDialog, OkayClickHdl, weld::Button&, void )
{
memp.ReduceResolutionCB = m_xReduceResolutionCB->get_active();
memp.MFNewWidth = m_xMFNewWidth->get_value();
memp.MFNewHeight = m_xMFNewHeight->get_value();
memp.InterpolationCombo = m_xInterpolationCombo->get_active();
CompressGraphicsDialog::response(RET_OK);
}
IMPL_LINK_NOARG( CompressGraphicsDialog, NewWidthModifiedHdl, weld::SpinButton&, void )
{
m_dResolution = m_xMFNewWidth->get_value() / GetViewWidthInch();
UpdateNewHeightMF();
UpdateResolutionLB();
Update();
}
IMPL_LINK( CompressGraphicsDialog, SlideHdl, weld::Scale&, rScale, void )
{
if (&rScale == m_xQualitySlider.get())
m_xQualityMF->set_value(m_xQualitySlider->get_value());
else
m_xCompressionMF->set_value(m_xCompressionSlider->get_value());
Update();
}
IMPL_LINK_NOARG( CompressGraphicsDialog, NewInterpolationModifiedHdl, weld::ComboBox&, void )
{
Update();
}
IMPL_LINK_NOARG( CompressGraphicsDialog, NewQualityModifiedHdl, weld::SpinButton&, void )
{
m_xQualitySlider->set_value(m_xQualityMF->get_value());
Update();
}
IMPL_LINK_NOARG( CompressGraphicsDialog, NewCompressionModifiedHdl, weld::SpinButton&, void )
{
m_xCompressionSlider->set_value(m_xCompressionMF->get_value());
Update();
}
IMPL_LINK_NOARG( CompressGraphicsDialog, NewHeightModifiedHdl, weld::SpinButton&, void )
{
m_dResolution = m_xMFNewHeight->get_value() / GetViewHeightInch();
UpdateNewWidthMF();
UpdateResolutionLB();
Update();
}
IMPL_LINK_NOARG( CompressGraphicsDialog, ResolutionModifiedHdl, weld::ComboBox&, void )
{
m_dResolution = static_cast<double>(m_xResolutionLB->get_active_text().toInt32());
UpdateNewWidthMF();
UpdateNewHeightMF();
Update();
}
IMPL_LINK_NOARG( CompressGraphicsDialog, ToggleCompressionRB, weld::Toggleable&, void )
{
bool choice = m_xLosslessRB->get_active();
m_xCompressionMF->set_sensitive(choice);
m_xCompressionSlider->set_sensitive(choice);
m_xQualityMF->set_sensitive(!choice);
m_xQualitySlider->set_sensitive(!choice);
Update();
}
IMPL_LINK_NOARG( CompressGraphicsDialog, ToggleReduceResolutionRB, weld::Toggleable&, void )
{
UpdateSensitivity(m_xReduceResolutionCB->get_active());
Update();
}
IMPL_LINK_NOARG( CompressGraphicsDialog, CalculateClickHdl, weld::Button&, void )
{
sal_Int32 aSize = 0;
if ( m_dResolution > 0.0 )
{
SvMemoryStream aMemStream;
aMemStream.SetVersion( SOFFICE_FILEFORMAT_CURRENT );
Compress( aMemStream );
aSize = aMemStream.TellEnd();
}
if ( aSize > 0 )
{
OUString aSizeAsString = OUString::number(aSize / 1024);
OUString aReductionSizeAsString;
if (m_aNativeSize > 0 )
aReductionSizeAsString = OUString::number( static_cast<sal_Int32>((m_aNativeSize - aSize) * 100.0 / m_aNativeSize) );
else
aReductionSizeAsString = "0";
OUString aNewSizeString = SvxResId(STR_IMAGE_CAPACITY_WITH_REDUCTION);
aNewSizeString = aNewSizeString.replaceAll("$(CAPACITY)", aSizeAsString);
aNewSizeString = aNewSizeString.replaceAll("$(REDUCTION)", aReductionSizeAsString);
m_xFixedText6->set_label(aNewSizeString);
}
}
tools::Rectangle CompressGraphicsDialog::GetScaledCropRectangle() const
{
if ( m_xReduceResolutionCB->get_active() )
{
tools::Long nPixelX = static_cast<tools::Long>( GetViewWidthInch() * m_dResolution );
tools::Long nPixelY = static_cast<tools::Long>( GetViewHeightInch() * m_dResolution );
Size aSize = m_aGraphic.GetBitmapEx().GetSizePixel();
double aScaleX = nPixelX / static_cast<double>(aSize.Width());
double aScaleY = nPixelY / static_cast<double>(aSize.Height());
return tools::Rectangle(
m_aCropRectangle.Left() * aScaleX,
m_aCropRectangle.Top() * aScaleY,
m_aCropRectangle.Right() * aScaleX,
m_aCropRectangle.Bottom()* aScaleY);
}
else
{
return m_aCropRectangle;
}
}
Graphic CompressGraphicsDialog::GetCompressedGraphic()
{
if ( m_dResolution > 0.0 )
{
SvMemoryStream aMemStream;
aMemStream.SetVersion( SOFFICE_FILEFORMAT_CURRENT );
Compress( aMemStream );
aMemStream.Seek( STREAM_SEEK_TO_BEGIN );
Graphic aResultGraphic;
GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
rFilter.ImportGraphic( aResultGraphic, u"import", aMemStream );
return aResultGraphic;
}
return Graphic();
}
rtl::Reference<SdrGrafObj> CompressGraphicsDialog::GetCompressedSdrGrafObj()
{
if ( m_dResolution > 0.0 )
{
rtl::Reference<SdrGrafObj> pNewObject = SdrObject::Clone(*m_xGraphicObj, m_xGraphicObj->getSdrModelFromSdrObject());
if ( m_xReduceResolutionCB->get_active() )
{
tools::Rectangle aScaledCropedRectangle = GetScaledCropRectangle();
SdrGrafCropItem aNewCrop(
aScaledCropedRectangle.Left(),
aScaledCropedRectangle.Top(),
aScaledCropedRectangle.Right(),
aScaledCropedRectangle.Bottom());
pNewObject->SetMergedItem(aNewCrop);
}
pNewObject->SetGraphic( GetCompressedGraphic() );
return pNewObject;
}
return nullptr;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */