LibreOffice Module svx (master) 1
compressgraphicdialog.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 "dlgunit.hxx"
21#include <utility>
22#include <vcl/fieldvalues.hxx>
23#include <vcl/graph.hxx>
24#include <vcl/graphicfilter.hxx>
25#include <vcl/virdev.hxx>
26#include <vcl/svapp.hxx>
27#include <vcl/settings.hxx>
28#include <vcl/weld.hxx>
29#include <svx/strings.hrc>
30#include <svx/svdograf.hxx>
31#include <svx/sdgcpitm.hxx>
32#include <svx/dialmgr.hxx>
33#include <svx/graphichelper.hxx>
35#include <sfx2/dispatch.hxx>
36#include <sfx2/module.hxx>
39#include <com/sun/star/uno/Sequence.hxx>
40#include <tools/stream.hxx>
42
43// tdf#146929 - remember user settings within the current session
44// memp is filled in dtor and restored after initialization
45namespace
46{
47 struct memParam {
48 bool ReduceResolutionCB = false;
49 int MFNewWidth = 1;
50 int MFNewHeight = 1;
51 bool LosslessRB = true;
52 bool JpegCompRB = false;
53 int CompressionMF = 6;
54 int QualityMF = 80;
55 int InterpolationCombo = 3;
56 };
57 memParam memp;
58}
59
60using namespace com::sun::star::uno;
61using namespace com::sun::star::beans;
62
64 GenericDialogController( pParent, "svx/ui/compressgraphicdialog.ui", "CompressGraphicDialog" ),
65 m_xGraphicObj ( pGraphicObj ),
66 m_aGraphic ( pGraphicObj->GetGraphicObject().GetGraphic() ),
67 m_aViewSize100mm ( pGraphicObj->GetLogicRect().GetSize() ),
68 m_rBindings ( rBindings ),
69 m_dResolution ( 300 )
70{
71 const SdrGrafCropItem& rCrop = m_xGraphicObj->GetMergedItem(SDRATTR_GRAFCROP);
72 m_aCropRectangle = tools::Rectangle(rCrop.GetLeft(), rCrop.GetTop(), rCrop.GetRight(), rCrop.GetBottom());
73
74 Initialize();
76}
77
78CompressGraphicsDialog::CompressGraphicsDialog( weld::Window* pParent, Graphic aGraphic, Size rViewSize100mm, tools::Rectangle const & rCropRectangle, SfxBindings& rBindings ) :
79 GenericDialogController( pParent, "svx/ui/compressgraphicdialog.ui", "CompressGraphicDialog" ),
80 m_xGraphicObj ( nullptr ),
81 m_aGraphic (std::move( aGraphic )),
82 m_aViewSize100mm ( rViewSize100mm ),
83 m_aCropRectangle ( rCropRectangle ),
84 m_rBindings ( rBindings ),
85 m_dResolution ( 300 )
86{
87 Initialize();
89}
90
92{
93}
94
96{
97 m_xReduceResolutionCB->set_active( memp.ReduceResolutionCB );
98 if (memp.ReduceResolutionCB && (memp.MFNewWidth > 1))
99 m_xMFNewWidth->set_value( memp.MFNewWidth );
100 if (memp.ReduceResolutionCB && (memp.MFNewHeight > 1))
101 m_xMFNewHeight->set_value( memp.MFNewHeight );
102
103 m_xLosslessRB->set_active( memp.LosslessRB );
104 m_xJpegCompRB->set_active( memp.JpegCompRB );
105 m_xCompressionMF->set_value( memp.CompressionMF );
106 m_xCompressionSlider->set_value( memp.CompressionMF );
107 m_xQualityMF->set_value( memp.QualityMF );
108 m_xQualitySlider->set_value( memp.QualityMF );
109
110 m_xInterpolationCombo->set_active( memp.InterpolationCombo );
111}
112
114{
115 m_xLabelGraphicType = m_xBuilder->weld_label("label-graphic-type");
116 m_xFixedText2 = m_xBuilder->weld_label("label-original-size");
117 m_xFixedText3 = m_xBuilder->weld_label("label-view-size");
118 m_xFixedText5 = m_xBuilder->weld_label("label-image-capacity");
119 m_xFixedText6 = m_xBuilder->weld_label("label-new-capacity");
120 m_xJpegCompRB = m_xBuilder->weld_radio_button("radio-jpeg");
121 m_xCompressionMF = m_xBuilder->weld_spin_button("spin-compression");
122 m_xCompressionSlider = m_xBuilder->weld_scale("scale-compression");
123 m_xLosslessRB = m_xBuilder->weld_radio_button("radio-lossless");
124 m_xQualityMF = m_xBuilder->weld_spin_button("spin-quality");
125 m_xQualitySlider = m_xBuilder->weld_scale("scale-quality");
126 m_xReduceResolutionCB = m_xBuilder->weld_check_button("checkbox-reduce-resolution");
127 m_xMFNewWidth = m_xBuilder->weld_spin_button("spin-new-width");
128 m_xMFNewHeight = m_xBuilder->weld_spin_button("spin-new-height");
129 m_xResolutionLB = m_xBuilder->weld_combo_box("combo-resolution");
130 m_xBtnCalculate = m_xBuilder->weld_button("calculate");
131 m_xInterpolationCombo = m_xBuilder->weld_combo_box("interpolation-method-combo");
132 m_xBtnOkay = m_xBuilder->weld_button("ok");
133
134 m_xInterpolationCombo->set_active_text("Lanczos");
135
136 m_xInterpolationCombo->connect_changed(LINK(this, CompressGraphicsDialog, NewInterpolationModifiedHdl));
137
138 m_xMFNewWidth->connect_changed( LINK( this, CompressGraphicsDialog, NewWidthModifiedHdl ));
139 m_xMFNewHeight->connect_changed( LINK( this, CompressGraphicsDialog, NewHeightModifiedHdl ));
140
141 m_xResolutionLB->connect_changed( LINK( this, CompressGraphicsDialog, ResolutionModifiedHdl ));
142 m_xBtnCalculate->connect_clicked( LINK( this, CompressGraphicsDialog, CalculateClickHdl ) );
143
144 m_xLosslessRB->connect_toggled( LINK( this, CompressGraphicsDialog, ToggleCompressionRB ) );
145 m_xJpegCompRB->connect_toggled( LINK( this, CompressGraphicsDialog, ToggleCompressionRB ) );
146
147 m_xReduceResolutionCB->connect_toggled( LINK( this, CompressGraphicsDialog, ToggleReduceResolutionRB ) );
148
149 m_xQualitySlider->connect_value_changed( LINK( this, CompressGraphicsDialog, SlideHdl ));
150 m_xCompressionSlider->connect_value_changed( LINK( this, CompressGraphicsDialog, SlideHdl ));
151 m_xQualityMF->connect_changed( LINK( this, CompressGraphicsDialog, NewQualityModifiedHdl ));
152 m_xCompressionMF->connect_changed( LINK( this, CompressGraphicsDialog, NewCompressionModifiedHdl ));
153
154 m_xJpegCompRB->set_active(true);
155 m_xReduceResolutionCB->set_active(true);
156
157 m_xBtnOkay->connect_clicked( LINK( this, CompressGraphicsDialog, OkayClickHdl ) );
161 Update();
162}
163
165{
166 auto pGfxLink = m_aGraphic.GetSharedGfxLink();
167
168 m_xLabelGraphicType->set_label(GraphicHelper::GetImageType(m_aGraphic));
169
170 const FieldUnit eFieldUnit = m_rBindings.GetDispatcher()->GetModule()->GetFieldUnit();
172 sal_Unicode cSeparator = rLocaleWrapper.getNumDecimalSep()[0];
173
175 pDummyVDev->EnableOutput( false );
176 pDummyVDev->SetMapMode( m_aGraphic.GetPrefMapMode() );
177
178 Size aPixelSize = m_aGraphic.GetSizePixel();
179 Size aOriginalSize100mm(pDummyVDev->PixelToLogic(m_aGraphic.GetSizePixel(), MapMode(MapUnit::Map100thMM)));
180
181 OUString aBitmapSizeString = SvxResId(STR_IMAGE_ORIGINAL_SIZE);
182 OUString aWidthString = GetUnitString( aOriginalSize100mm.Width(), eFieldUnit, cSeparator );
183 OUString aHeightString = GetUnitString( aOriginalSize100mm.Height(), eFieldUnit, cSeparator );
184 aBitmapSizeString = aBitmapSizeString.replaceAll("$(WIDTH)", aWidthString);
185 aBitmapSizeString = aBitmapSizeString.replaceAll("$(HEIGHT)", aHeightString);
186 aBitmapSizeString = aBitmapSizeString.replaceAll("$(WIDTH_IN_PX)", OUString::number(aPixelSize.Width()));
187 aBitmapSizeString = aBitmapSizeString.replaceAll("$(HEIGHT_IN_PX)", OUString::number(aPixelSize.Height()));
188 m_xFixedText2->set_label(aBitmapSizeString);
189
190 int aValX = static_cast<int>(aPixelSize.Width() / GetViewWidthInch());
191
192 OUString aViewSizeString = SvxResId(STR_IMAGE_VIEW_SIZE);
193
194 aWidthString = GetUnitString( m_aViewSize100mm.Width(), eFieldUnit, cSeparator );
195 aHeightString = GetUnitString( m_aViewSize100mm.Height(), eFieldUnit, cSeparator );
196 aViewSizeString = aViewSizeString.replaceAll("$(WIDTH)", aWidthString);
197 aViewSizeString = aViewSizeString.replaceAll("$(HEIGHT)", aHeightString);
198 aViewSizeString = aViewSizeString.replaceAll("$(DPI)", OUString::number(aValX));
199 m_xFixedText3->set_label(aViewSizeString);
200
201 m_aNativeSize = pGfxLink ? pGfxLink->GetDataSize() : 0;
202
203 OUString aNativeSizeString = SvxResId(STR_IMAGE_CAPACITY);
204 aNativeSizeString = aNativeSizeString.replaceAll("$(CAPACITY)", OUString::number( m_aNativeSize / 1024 ));
205 m_xFixedText5->set_label(aNativeSizeString);
206
207 m_xFixedText6->set_label("??");
208}
209
211{
212 int nPixelX = static_cast<sal_Int32>( GetViewWidthInch() * m_dResolution );
213 m_xMFNewWidth->set_value(nPixelX);
214}
215
217{
218 int nPixelY = static_cast<sal_Int32>( GetViewHeightInch() * m_dResolution );
219 m_xMFNewHeight->set_value(nPixelY);
220}
221
223{
224 m_xResolutionLB->set_entry_text( OUString::number( static_cast<sal_Int32>(m_dResolution) ) );
225}
226
228{
229 return static_cast<double>(vcl::ConvertValue(m_aViewSize100mm.Width(), 2, MapUnit::Map100thMM, FieldUnit::INCH)) / 100.0;
230}
231
233{
234 return static_cast<double>(vcl::ConvertValue(m_aViewSize100mm.Height(), 2, MapUnit::Map100thMM, FieldUnit::INCH)) / 100.0;
235}
236
238{
239 OUString aSelectionText = m_xInterpolationCombo->get_active_text();
240
241 if( aSelectionText == "Lanczos" ) {
242 return BmpScaleFlag::Lanczos;
243 } else if( aSelectionText == "Bilinear" ) {
244 return BmpScaleFlag::BiLinear;
245 } else if( aSelectionText == "Bicubic" ) {
246 return BmpScaleFlag::BiCubic;
247 } else if ( aSelectionText == "None" ) {
248 return BmpScaleFlag::Fast;
249 }
250 return BmpScaleFlag::BestQuality;
251}
252
254{
255 BitmapEx aBitmap = m_aGraphic.GetBitmapEx();
256 if ( m_xReduceResolutionCB->get_active() )
257 {
258 tools::Long nPixelX = static_cast<tools::Long>( GetViewWidthInch() * m_dResolution );
259 tools::Long nPixelY = static_cast<tools::Long>( GetViewHeightInch() * m_dResolution );
260
261 aBitmap.Scale( Size( nPixelX, nPixelY ), GetSelectedInterpolationType() );
262 }
263 Graphic aScaledGraphic( aBitmap );
265
266 Sequence< PropertyValue > aFilterData{
267 comphelper::makePropertyValue("Interlaced", sal_Int32(0)),
268 comphelper::makePropertyValue("Compression", static_cast<sal_Int32>(m_xCompressionMF->get_value())),
269 comphelper::makePropertyValue("Quality", static_cast<sal_Int32>(m_xQualityMF->get_value()))
270 };
271
272 OUString aGraphicFormatName = m_xLosslessRB->get_active() ? OUString( "png" ) : OUString( "jpg" );
273
274 sal_uInt16 nFilterFormat = rFilter.GetExportFormatNumberForShortName( aGraphicFormatName );
275 rFilter.ExportGraphic( aScaledGraphic, u"none", aStream, nFilterFormat, &aFilterData );
276}
277
279{
280 memp.ReduceResolutionCB = m_xReduceResolutionCB->get_active();
281 memp.MFNewWidth = m_xMFNewWidth->get_value();
282 memp.MFNewHeight = m_xMFNewHeight->get_value();
283 memp.LosslessRB = m_xLosslessRB->get_active();
284 memp.JpegCompRB = m_xJpegCompRB->get_active();
285 memp.CompressionMF = m_xCompressionMF->get_value();
286 memp.QualityMF = m_xQualityMF->get_value();
287 memp.InterpolationCombo = m_xInterpolationCombo->get_active();
289}
290
292{
293 m_dResolution = m_xMFNewWidth->get_value() / GetViewWidthInch();
294
295 UpdateNewHeightMF();
296 UpdateResolutionLB();
297 Update();
298}
299
300IMPL_LINK( CompressGraphicsDialog, SlideHdl, weld::Scale&, rScale, void )
301{
302 if (&rScale == m_xQualitySlider.get())
303 m_xQualityMF->set_value(m_xQualitySlider->get_value());
304 else
305 m_xCompressionMF->set_value(m_xCompressionSlider->get_value());
306 Update();
307}
308
309IMPL_LINK_NOARG( CompressGraphicsDialog, NewInterpolationModifiedHdl, weld::ComboBox&, void )
310{
311 Update();
312}
313
314IMPL_LINK_NOARG( CompressGraphicsDialog, NewQualityModifiedHdl, weld::Entry&, void )
315{
316 m_xQualitySlider->set_value(m_xQualityMF->get_value());
317 Update();
318}
319
320IMPL_LINK_NOARG( CompressGraphicsDialog, NewCompressionModifiedHdl, weld::Entry&, void )
321{
322 m_xCompressionSlider->set_value(m_xCompressionMF->get_value());
323 Update();
324}
325
326IMPL_LINK_NOARG( CompressGraphicsDialog, NewHeightModifiedHdl, weld::Entry&, void )
327{
328 m_dResolution = m_xMFNewHeight->get_value() / GetViewHeightInch();
329
330 UpdateNewWidthMF();
331 UpdateResolutionLB();
332 Update();
333}
334
336{
337 m_dResolution = static_cast<double>(m_xResolutionLB->get_active_text().toInt32());
338
339 UpdateNewWidthMF();
340 UpdateNewHeightMF();
341 Update();
342}
343
345{
346 bool choice = m_xLosslessRB->get_active();
347 m_xCompressionMF->set_sensitive(choice);
348 m_xCompressionSlider->set_sensitive(choice);
349 m_xQualityMF->set_sensitive(!choice);
350 m_xQualitySlider->set_sensitive(!choice);
351 Update();
352}
353
354IMPL_LINK_NOARG( CompressGraphicsDialog, ToggleReduceResolutionRB, weld::Toggleable&, void )
355{
356 bool choice = m_xReduceResolutionCB->get_active();
357 m_xMFNewWidth->set_sensitive(choice);
358 m_xMFNewHeight->set_sensitive(choice);
359 m_xResolutionLB->set_sensitive(choice);
360 m_xInterpolationCombo->set_sensitive(choice);
361 Update();
362}
363
365{
366 sal_Int32 aSize = 0;
367
368 if ( m_dResolution > 0.0 )
369 {
370 SvMemoryStream aMemStream;
372 Compress( aMemStream );
373 aSize = aMemStream.TellEnd();
374 }
375
376 if ( aSize > 0 )
377 {
378 OUString aSizeAsString = OUString::number(aSize / 1024);
379
380 OUString aReductionSizeAsString = OUString::number( m_aNativeSize > 0 ? (m_aNativeSize - aSize) * 100 / m_aNativeSize : 0 );
381
382 OUString aNewSizeString = SvxResId(STR_IMAGE_CAPACITY_WITH_REDUCTION);
383 aNewSizeString = aNewSizeString.replaceAll("$(CAPACITY)", aSizeAsString);
384 aNewSizeString = aNewSizeString.replaceAll("$(REDUCTION)", aReductionSizeAsString);
385 m_xFixedText6->set_label(aNewSizeString);
386 }
387}
388
390{
391 if ( m_xReduceResolutionCB->get_active() )
392 {
393 tools::Long nPixelX = static_cast<tools::Long>( GetViewWidthInch() * m_dResolution );
394 tools::Long nPixelY = static_cast<tools::Long>( GetViewHeightInch() * m_dResolution );
396 double aScaleX = nPixelX / static_cast<double>(aSize.Width());
397 double aScaleY = nPixelY / static_cast<double>(aSize.Height());
398
399 return tools::Rectangle(
400 m_aCropRectangle.Left() * aScaleX,
401 m_aCropRectangle.Top() * aScaleY,
402 m_aCropRectangle.Right() * aScaleX,
403 m_aCropRectangle.Bottom()* aScaleY);
404 }
405 else
406 {
407 return m_aCropRectangle;
408 }
409}
410
412{
413 if ( m_dResolution > 0.0 )
414 {
415 SvMemoryStream aMemStream;
417 Compress( aMemStream );
418 aMemStream.Seek( STREAM_SEEK_TO_BEGIN );
419 Graphic aResultGraphic;
421 rFilter.ImportGraphic( aResultGraphic, u"import", aMemStream );
422
423 return aResultGraphic;
424 }
425 return Graphic();
426}
427
429{
430 if ( m_dResolution > 0.0 )
431 {
433
434 if ( m_xReduceResolutionCB->get_active() )
435 {
436 tools::Rectangle aScaledCropedRectangle = GetScaledCropRectangle();
437 SdrGrafCropItem aNewCrop(
438 aScaledCropedRectangle.Left(),
439 aScaledCropedRectangle.Top(),
440 aScaledCropedRectangle.Right(),
441 aScaledCropedRectangle.Bottom());
442
443 pNewObject->SetMergedItem(aNewCrop);
444 }
445 pNewObject->SetGraphic( GetCompressedGraphic() );
446
447 return pNewObject;
448 }
449 return nullptr;
450}
451
452/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static const AllSettings & GetSettings()
bool Scale(const Size &rNewSize, BmpScaleFlag nScaleFlag=BmpScaleFlag::Default)
const Size & GetSizePixel() const
std::unique_ptr< weld::Button > m_xBtnCalculate
std::unique_ptr< weld::Button > m_xBtnOkay
std::unique_ptr< weld::Scale > m_xCompressionSlider
std::unique_ptr< weld::ComboBox > m_xResolutionLB
std::unique_ptr< weld::Label > m_xFixedText5
tools::Rectangle GetScaledCropRectangle() const
std::unique_ptr< weld::Label > m_xFixedText6
std::unique_ptr< weld::SpinButton > m_xQualityMF
std::unique_ptr< weld::SpinButton > m_xMFNewHeight
void Compress(SvStream &aStream)
std::unique_ptr< weld::RadioButton > m_xJpegCompRB
std::unique_ptr< weld::SpinButton > m_xCompressionMF
std::unique_ptr< weld::ComboBox > m_xInterpolationCombo
std::unique_ptr< weld::CheckButton > m_xReduceResolutionCB
BmpScaleFlag GetSelectedInterpolationType() const
std::unique_ptr< weld::Label > m_xLabelGraphicType
rtl::Reference< SdrGrafObj > GetCompressedSdrGrafObj()
CompressGraphicsDialog(weld::Window *pParent, SdrGrafObj *pGraphicObj, SfxBindings &rBindings)
virtual ~CompressGraphicsDialog() override
std::unique_ptr< weld::Scale > m_xQualitySlider
std::unique_ptr< weld::Label > m_xFixedText3
std::unique_ptr< weld::RadioButton > m_xLosslessRB
std::unique_ptr< weld::SpinButton > m_xMFNewWidth
std::unique_ptr< weld::Label > m_xFixedText2
sal_uInt16 GetExportFormatNumberForShortName(std::u16string_view rShortName)
static GraphicFilter & GetGraphicFilter()
ErrCode ExportGraphic(const Graphic &rGraphic, const INetURLObject &rPath, sal_uInt16 nFormat, const css::uno::Sequence< css::beans::PropertyValue > *pFilterData=nullptr)
ErrCode ImportGraphic(Graphic &rGraphic, const INetURLObject &rPath, sal_uInt16 nFormat=GRFILTER_FORMAT_DONTKNOW, sal_uInt16 *pDeterminedFormat=nullptr, GraphicFilterImportFlags nImportFlags=GraphicFilterImportFlags::NONE)
const std::shared_ptr< GfxLink > & GetSharedGfxLink() const
BitmapEx GetBitmapEx(const GraphicConversionParameters &rParameters=GraphicConversionParameters()) const
MapMode GetPrefMapMode() const
Size GetSizePixel(const OutputDevice *pRefDevice=nullptr) const
const OUString & getNumDecimalSep() const
This class represents an embedded or linked bitmap graphic object.
Definition: svdograf.hxx:68
const SfxPoolItem & GetMergedItem(const sal_uInt16 nWhich) const
Definition: svdobj.cxx:2012
static rtl::Reference< T > Clone(T const &rObj, SdrModel &rTargetModel)
Definition: svdobj.hxx:449
SdrModel & getSdrModelFromSdrObject() const
Definition: svdobj.cxx:289
SfxDispatcher * GetDispatcher() const
SfxModule * GetModule() const
FieldUnit GetFieldUnit() const
constexpr tools::Long Height() const
constexpr tools::Long Width() const
virtual sal_uInt64 TellEnd() override
void SetVersion(sal_Int32 n)
sal_uInt64 Seek(sal_uInt64 nPos)
constexpr tools::Long Top() const
constexpr tools::Long Right() const
constexpr tools::Long Left() const
constexpr tools::Long Bottom() const
void response(int nResponse)
std::unique_ptr< weld::Builder > m_xBuilder
IMPL_LINK_NOARG(CompressGraphicsDialog, OkayClickHdl, weld::Button &, void)
IMPL_LINK(CompressGraphicsDialog, SlideHdl, weld::Scale &, rScale, void)
OUString SvxResId(TranslateId aId)
Definition: dialmgr.cxx:24
OUString GetUnitString(tools::Long nVal_100, FieldUnit eFieldUnit, sal_Unicode cSep)
Definition: dlgunit.hxx:27
float u
#define SOFFICE_FILEFORMAT_CURRENT
FieldUnit
BmpScaleFlag
css::beans::PropertyValue makePropertyValue(const OUString &rName, T &&rValue)
const LocaleDataWrapper & GetLocaleDataWrapper(LanguageType nLang)
long Long
sal_Int64 ConvertValue(sal_Int64 nValue, sal_Int64 mnBaseValue, sal_uInt16 nDecDigits, FieldUnit eInUnit, FieldUnit eOutUnit)
#define STREAM_SEEK_TO_BEGIN
constexpr TypedWhichId< SdrGrafCropItem > SDRATTR_GRAFCROP(SDRATTR_GRAF_FIRST+9)
sal_uInt16 sal_Unicode
RET_OK