1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <officecfg/Office/Common.hxx>
21 #include <vcl/vclenum.hxx>
22 #include <vcl/BitmapReadAccess.hxx>
23 #include <vcl/bitmap/BitmapSimpleColorQuantizationFilter.hxx>
24 #include <vcl/bitmap/Vectorizer.hxx>
25 #include <vcl/metaact.hxx>
26 #include <vcl/svapp.hxx>
28 #include <DrawDocShell.hxx>
29 #include <vectdlg.hxx>
31 #define VECTORIZE_MAX_EXTENT 512
33 SdVectorizeDlg::SdVectorizeDlg(weld::Window
* pParent
, const Bitmap
& rBmp
, ::sd::DrawDocShell
* pDocShell
)
34 : GenericDialogController(pParent
, u
"modules/sdraw/ui/vectorize.ui"_ustr
, u
"VectorizeDialog"_ustr
)
37 , m_aBmpWin(m_xDialog
.get())
38 , m_aMtfWin(m_xDialog
.get())
39 , m_xNmLayers(m_xBuilder
->weld_spin_button(u
"colors"_ustr
))
40 , m_xMtReduce(m_xBuilder
->weld_metric_spin_button(u
"points"_ustr
, FieldUnit::PIXEL
))
41 , m_xFtFillHoles(m_xBuilder
->weld_label(u
"tilesft"_ustr
))
42 , m_xMtFillHoles(m_xBuilder
->weld_metric_spin_button(u
"tiles"_ustr
, FieldUnit::PIXEL
))
43 , m_xCbFillHoles(m_xBuilder
->weld_check_button(u
"fillholes"_ustr
))
44 , m_xBmpWin(new weld::CustomWeld(*m_xBuilder
, u
"source"_ustr
, m_aBmpWin
))
45 , m_xMtfWin(new weld::CustomWeld(*m_xBuilder
, u
"vectorized"_ustr
, m_aMtfWin
))
46 , m_xPrgs(m_xBuilder
->weld_progress_bar(u
"progressbar"_ustr
))
47 , m_xBtnOK(m_xBuilder
->weld_button(u
"ok"_ustr
))
48 , m_xBtnPreview(m_xBuilder
->weld_button(u
"preview"_ustr
))
50 const int nWidth
= m_xFtFillHoles
->get_approximate_digit_width() * 32;
51 const int nHeight
= m_xFtFillHoles
->get_text_height() * 16;
52 m_xBmpWin
->set_size_request(nWidth
, nHeight
);
53 m_xMtfWin
->set_size_request(nWidth
, nHeight
);
55 m_xBtnPreview
->connect_clicked( LINK( this, SdVectorizeDlg
, ClickPreviewHdl
) );
56 m_xBtnOK
->connect_clicked( LINK( this, SdVectorizeDlg
, ClickOKHdl
) );
57 m_xNmLayers
->connect_value_changed( LINK( this, SdVectorizeDlg
, ModifyHdl
) );
58 m_xMtReduce
->connect_value_changed( LINK( this, SdVectorizeDlg
, MetricModifyHdl
) );
59 m_xMtFillHoles
->connect_value_changed( LINK( this, SdVectorizeDlg
, MetricModifyHdl
) );
60 m_xCbFillHoles
->connect_toggled( LINK( this, SdVectorizeDlg
, ToggleHdl
) );
66 SdVectorizeDlg::~SdVectorizeDlg()
70 ::tools::Rectangle
SdVectorizeDlg::GetRect( const Size
& rDispSize
, const Size
& rBmpSize
)
72 ::tools::Rectangle aRect
;
74 if( rBmpSize
.Width() && rBmpSize
.Height() && rDispSize
.Width() && rDispSize
.Height() )
76 Size
aBmpSize( rBmpSize
);
77 const double fGrfWH
= static_cast<double>(aBmpSize
.Width()) / aBmpSize
.Height();
78 const double fWinWH
= static_cast<double>(rDispSize
.Width()) / rDispSize
.Height();
82 aBmpSize
.setWidth( static_cast<tools::Long
>( rDispSize
.Height() * fGrfWH
) );
83 aBmpSize
.setHeight( rDispSize
.Height() );
87 aBmpSize
.setWidth( rDispSize
.Width() );
88 aBmpSize
.setHeight( static_cast<tools::Long
>( rDispSize
.Width() / fGrfWH
) );
91 const Point
aBmpPos( ( rDispSize
.Width() - aBmpSize
.Width() ) >> 1,
92 ( rDispSize
.Height() - aBmpSize
.Height() ) >> 1 );
94 aRect
= ::tools::Rectangle( aBmpPos
, aBmpSize
);
100 void SdVectorizeDlg::InitPreviewBmp()
102 const ::tools::Rectangle
aRect( GetRect( m_aBmpWin
.GetOutputSizePixel(), aBmp
.GetSizePixel() ) );
105 aPreviewBmp
.Scale( aRect
.GetSize() );
106 m_aBmpWin
.SetGraphic(BitmapEx(aPreviewBmp
));
109 Bitmap
SdVectorizeDlg::GetPreparedBitmap( Bitmap
const & rBmp
, Fraction
& rScale
)
112 const Size
aSizePix( aNew
.GetSizePixel() );
114 if( aSizePix
.Width() > VECTORIZE_MAX_EXTENT
|| aSizePix
.Height() > VECTORIZE_MAX_EXTENT
)
116 const ::tools::Rectangle
aRect( GetRect( Size( VECTORIZE_MAX_EXTENT
, VECTORIZE_MAX_EXTENT
), aSizePix
) );
117 rScale
= Fraction( aSizePix
.Width(), aRect
.GetWidth() );
118 aNew
.Scale( aRect
.GetSize() );
121 rScale
= Fraction( 1, 1 );
123 BitmapEx
aNewBmpEx(aNew
);
124 BitmapFilter::Filter(aNewBmpEx
, BitmapSimpleColorQuantizationFilter(m_xNmLayers
->get_value()));
125 aNew
= aNewBmpEx
.GetBitmap();
130 void SdVectorizeDlg::Calculate( Bitmap
const & rBmp
, GDIMetaFile
& rMtf
)
132 m_pDocSh
->SetWaitCursor( true );
133 m_xPrgs
->set_percentage(0);
136 BitmapEx
aBitmapEx(GetPreparedBitmap(rBmp
, aScale
));
138 if (!aBitmapEx
.IsEmpty())
140 const Link
<::tools::Long
,void> aPrgsHdl( LINK( this, SdVectorizeDlg
, ProgressHdl
) );
141 sal_uInt8 nReduce
= sal_uInt8(m_xMtReduce
->get_value(FieldUnit::NONE
));
142 vcl::Vectorizer
aVecotrizer(nReduce
);
143 aVecotrizer
.vectorize(aBitmapEx
, rMtf
);
144 aVecotrizer
.setProgressCallback(&aPrgsHdl
);
146 if (m_xCbFillHoles
->get_active())
149 BitmapScopedReadAccess
pRAcc(aBitmapEx
.GetBitmap());
153 const tools::Long nWidth
= pRAcc
->Width();
154 const tools::Long nHeight
= pRAcc
->Height();
155 const tools::Long nTileX
= m_xMtFillHoles
->get_value(FieldUnit::NONE
);
156 const tools::Long nTileY
= m_xMtFillHoles
->get_value(FieldUnit::NONE
);
157 assert(nTileX
&& "div-by-zero");
158 const tools::Long nCountX
= nWidth
/ nTileX
;
159 assert(nTileY
&& "div-by-zero");
160 const tools::Long nCountY
= nHeight
/ nTileY
;
161 const tools::Long nRestX
= nWidth
% nTileX
;
162 const tools::Long nRestY
= nHeight
% nTileY
;
164 MapMode
aMap( rMtf
.GetPrefMapMode() );
165 aNewMtf
.SetPrefSize( rMtf
.GetPrefSize() );
166 aNewMtf
.SetPrefMapMode( aMap
);
168 for( tools::Long nTY
= 0; nTY
< nCountY
; nTY
++ )
170 const tools::Long nY
= nTY
* nTileY
;
172 for( tools::Long nTX
= 0; nTX
< nCountX
; nTX
++ )
173 AddTile( pRAcc
.get(), aNewMtf
, nTX
* nTileX
, nTY
* nTileY
, nTileX
, nTileY
);
176 AddTile( pRAcc
.get(), aNewMtf
, nCountX
* nTileX
, nY
, nRestX
, nTileY
);
181 const tools::Long nY
= nCountY
* nTileY
;
183 for( tools::Long nTX
= 0; nTX
< nCountX
; nTX
++ )
184 AddTile( pRAcc
.get(), aNewMtf
, nTX
* nTileX
, nY
, nTileX
, nRestY
);
187 AddTile( pRAcc
.get(), aNewMtf
, nCountX
* nTileX
, nCountY
* nTileY
, nRestX
, nRestY
);
192 for( size_t n
= 0, nCount
= rMtf
.GetActionSize(); n
< nCount
; n
++ )
193 aNewMtf
.AddAction( rMtf
.GetAction( n
)->Clone() );
195 aMap
.SetScaleX( aMap
.GetScaleX() * aScale
);
196 aMap
.SetScaleY( aMap
.GetScaleY() * aScale
);
197 aNewMtf
.SetPrefMapMode( aMap
);
203 m_xPrgs
->set_percentage(0);
204 m_pDocSh
->SetWaitCursor( false );
207 void SdVectorizeDlg::AddTile( BitmapReadAccess
const * pRAcc
, GDIMetaFile
& rMtf
,
208 tools::Long nPosX
, tools::Long nPosY
, tools::Long nWidth
, tools::Long nHeight
)
210 sal_uLong nSumR
= 0, nSumG
= 0, nSumB
= 0;
211 const tools::Long nRight
= nPosX
+ nWidth
- 1;
212 const tools::Long nBottom
= nPosY
+ nHeight
- 1;
213 const double fMult
= 1.0 / ( nWidth
* nHeight
);
215 for( tools::Long nY
= nPosY
; nY
<= nBottom
; nY
++ )
217 for( tools::Long nX
= nPosX
; nX
<= nRight
; nX
++ )
219 const BitmapColor
aPixel( pRAcc
->GetColor( nY
, nX
) );
221 nSumR
+= aPixel
.GetRed();
222 nSumG
+= aPixel
.GetGreen();
223 nSumB
+= aPixel
.GetBlue();
227 const Color
aColor( basegfx::fround
<sal_uInt8
>( nSumR
* fMult
),
228 basegfx::fround
<sal_uInt8
>( nSumG
* fMult
),
229 basegfx::fround
<sal_uInt8
>( nSumB
* fMult
) );
231 ::tools::Rectangle
aRect( Point( nPosX
, nPosY
), Size( nWidth
+ 1, nHeight
+ 1 ) );
232 const Size
& rMaxSize
= rMtf
.GetPrefSize();
234 aRect
= Application::GetDefaultDevice()->PixelToLogic(aRect
, rMtf
.GetPrefMapMode());
236 if( aRect
.Right() > ( rMaxSize
.Width() - 1 ) )
237 aRect
.SetRight( rMaxSize
.Width() - 1 );
239 if( aRect
.Bottom() > ( rMaxSize
.Height() - 1 ) )
240 aRect
.SetBottom( rMaxSize
.Height() - 1 );
242 rMtf
.AddAction( new MetaLineColorAction( aColor
, true ) );
243 rMtf
.AddAction( new MetaFillColorAction( aColor
, true ) );
244 rMtf
.AddAction( new MetaRectAction( aRect
) );
247 IMPL_LINK( SdVectorizeDlg
, ProgressHdl
, tools::Long
, nData
, void )
249 m_xPrgs
->set_percentage(nData
);
252 IMPL_LINK_NOARG(SdVectorizeDlg
, ClickPreviewHdl
, weld::Button
&, void)
254 Calculate( aBmp
, aMtf
);
255 m_aMtfWin
.SetGraphic( aMtf
);
256 m_xBtnPreview
->set_sensitive(false);
259 IMPL_LINK_NOARG(SdVectorizeDlg
, ClickOKHdl
, weld::Button
&, void)
261 if (m_xBtnPreview
->get_sensitive())
262 Calculate( aBmp
, aMtf
);
265 m_xDialog
->response(RET_OK
);
268 IMPL_LINK( SdVectorizeDlg
, ToggleHdl
, weld::Toggleable
&, rCb
, void )
270 if (rCb
.get_active())
272 m_xFtFillHoles
->set_sensitive(true);
273 m_xMtFillHoles
->set_sensitive(true);
277 m_xFtFillHoles
->set_sensitive(false);
278 m_xMtFillHoles
->set_sensitive(false);
281 m_xBtnPreview
->set_sensitive(true);
284 IMPL_LINK_NOARG(SdVectorizeDlg
, ModifyHdl
, weld::SpinButton
&, void)
286 m_xBtnPreview
->set_sensitive(true);
289 IMPL_LINK_NOARG(SdVectorizeDlg
, MetricModifyHdl
, weld::MetricSpinButton
&, void)
291 m_xBtnPreview
->set_sensitive(true);
294 void SdVectorizeDlg::LoadSettings()
296 m_xNmLayers
->set_value(officecfg::Office::Common::Vectorize::ColorCount::get());
297 m_xMtReduce
->set_value(officecfg::Office::Common::Vectorize::PointReduce::get(), FieldUnit::NONE
);
298 m_xCbFillHoles
->set_active(officecfg::Office::Common::Vectorize::FillHole::get());
299 m_xMtFillHoles
->set_value(officecfg::Office::Common::Vectorize::TileExtent::get(), FieldUnit::NONE
);
301 ToggleHdl(*m_xCbFillHoles
);
304 void SdVectorizeDlg::SaveSettings() const
306 std::shared_ptr
<comphelper::ConfigurationChanges
> batch(
307 comphelper::ConfigurationChanges::create());
308 officecfg::Office::Common::Vectorize::ColorCount::set(m_xNmLayers
->get_value(),batch
);
309 officecfg::Office::Common::Vectorize::PointReduce::set(m_xMtReduce
->get_value(FieldUnit::NONE
),batch
);
310 officecfg::Office::Common::Vectorize::FillHole::set(m_xCbFillHoles
->get_active(),batch
);
311 officecfg::Office::Common::Vectorize::TileExtent::set(m_xMtFillHoles
->get_value(FieldUnit::NONE
),batch
);
315 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */