1 | // Copyright 2004-2007 Jean-Francois Poilpret |
2 | // |
3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | // you may not use this file except in compliance with the License. |
5 | // You may obtain a copy of the License at |
6 | // |
7 | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | // |
9 | // Unless required by applicable law or agreed to in writing, software |
10 | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | // See the License for the specific language governing permissions and |
13 | // limitations under the License. |
14 | |
15 | package net.sourceforge.hivegui.component; |
16 | |
17 | import java.awt.Color; |
18 | import java.awt.event.ActionEvent; |
19 | import java.awt.event.ActionListener; |
20 | import java.awt.image.RenderedImage; |
21 | import java.util.Hashtable; |
22 | |
23 | import javax.imageio.ImageTypeSpecifier; |
24 | import javax.imageio.ImageWriteParam; |
25 | import javax.imageio.ImageWriter; |
26 | import javax.swing.DefaultComboBoxModel; |
27 | import javax.swing.JCheckBox; |
28 | import javax.swing.JComboBox; |
29 | import javax.swing.JLabel; |
30 | import javax.swing.JPanel; |
31 | import javax.swing.JSlider; |
32 | import javax.swing.JTextField; |
33 | import javax.swing.border.CompoundBorder; |
34 | import javax.swing.border.EmptyBorder; |
35 | import javax.swing.border.LineBorder; |
36 | import javax.swing.event.ChangeEvent; |
37 | import javax.swing.event.ChangeListener; |
38 | |
39 | import net.sourceforge.hivegui.imaging.ImageIOHelper; |
40 | |
41 | import zappini.designgridlayout.DesignGridLayout; |
42 | import zappini.designgridlayout.Row; |
43 | |
44 | // CSOFF: ClassDataAbstractionCoupling |
45 | /** |
46 | * Special accessory panel to be added to ImageSaveChooser in order to allow |
47 | * user to select image writing format plus additional parameters |
48 | * (eg compression settings). |
49 | */ |
50 | public class ImageWriterSettingsPanel extends JPanel |
51 | { |
52 | static final private String NAME = "image-writer-settings"; |
53 | static final private String ESTIMATED_SIZE = "Estimated size (KB): "; |
54 | |
55 | public ImageWriterSettingsPanel(ImageTypeSpecifier imageType, boolean detail) |
56 | { |
57 | _detail = detail; |
58 | |
59 | setName(NAME); |
60 | setComponentNames(); |
61 | |
62 | // Fill in the list of all recognized formats |
63 | String[] formats = ImageIOHelper.getAcceptedFormats(imageType); |
64 | _formats.setModel(new DefaultComboBoxModel(formats)); |
65 | |
66 | addListeners(); |
67 | |
68 | _lblFormats.setLabelFor(_formats); |
69 | _lblWriters.setLabelFor(_writers); |
70 | _lblCompressionType.setLabelFor(_compressionType); |
71 | _lblQuality.setLabelFor(_compressionQuality); |
72 | |
73 | layoutPanel(); |
74 | |
75 | _formats.setSelectedIndex(0); |
76 | } |
77 | |
78 | private void setComponentNames() |
79 | { |
80 | _lblFormats.setName(NAME + "-formats-label"); |
81 | _formats.setName(NAME + "-formats"); |
82 | _lblWriters.setName(NAME + "-writers-label"); |
83 | _writers.setName(NAME + "-writers"); |
84 | _lblCompressionType.setName(NAME + "-compression-label"); |
85 | _compressionType.setName(NAME + "-compression"); |
86 | _lossless.setName(NAME + "-lossless"); |
87 | _progressive.setName(NAME + "-progressive"); |
88 | _lblQuality.setName(NAME + "-quality-feedback-label"); |
89 | _displayQuality.setName(NAME + "-quality-feedback"); |
90 | _compressionQuality.setName(NAME + "-quality"); |
91 | _size.setName(NAME + "-size-feedback"); |
92 | } |
93 | |
94 | private void layoutPanel() |
95 | { |
96 | setBorder(new CompoundBorder( new EmptyBorder(0, 2, 0, 2), |
97 | new LineBorder(Color.GRAY, 1))); |
98 | |
99 | DesignGridLayout layout = new DesignGridLayout(this); |
100 | setLayout(layout); |
101 | |
102 | layout.row().label(_lblFormats).add(_formats).add(Row.EMPTY); |
103 | layout.row().label(_lblWriters).add(_writers); |
104 | layout.row().label(_lblCompressionType).add(_compressionType); |
105 | layout.row().add(_lossless); |
106 | layout.row().add(_progressive); |
107 | layout.row().label(_lblQuality).add(_displayQuality).add(Row.EMPTY); |
108 | layout.row().add(_compressionQuality); |
109 | layout.row().add(_size); |
110 | |
111 | _lossless.setEnabled(false); |
112 | _displayQuality.setEnabled(false); |
113 | |
114 | _compressionQuality.setOrientation(JSlider.VERTICAL); |
115 | _compressionQuality.setMinorTickSpacing(QUALITY_MINOR_TICK); |
116 | _compressionQuality.setMajorTickSpacing(QUALITY_MAJOR_TICK); |
117 | _compressionQuality.setPaintTicks(true); |
118 | _compressionQuality.setPaintLabels(true); |
119 | |
120 | } |
121 | |
122 | private void addListeners() |
123 | { |
124 | // Update everything when format is changed |
125 | _formats.addActionListener(new ActionListener() |
126 | { |
127 | public void actionPerformed(ActionEvent e) |
128 | { |
129 | setFormat((String) _formats.getSelectedItem()); |
130 | } |
131 | }); |
132 | |
133 | // Update everything else when writer is changed |
134 | _writers.addActionListener(new ActionListener() |
135 | { |
136 | public void actionPerformed(ActionEvent e) |
137 | { |
138 | setWriter(((ImageIOHelper.WriterItem) _writers.getSelectedItem()).getWriter()); |
139 | } |
140 | }); |
141 | |
142 | // Update file size estimate when progressive is clicked |
143 | _progressive.addChangeListener(new ChangeListener() |
144 | { |
145 | public void stateChanged(ChangeEvent e) |
146 | { |
147 | setProgressive(_progressive.isSelected()); |
148 | } |
149 | }); |
150 | |
151 | // Update compression qualities when type is changed |
152 | _compressionType.addActionListener(new ActionListener() |
153 | { |
154 | public void actionPerformed(ActionEvent e) |
155 | { |
156 | setCompressionType((String) _compressionType.getSelectedItem()); |
157 | } |
158 | }); |
159 | |
160 | // Update quality |
161 | _compressionQuality.addChangeListener(new ChangeListener() |
162 | { |
163 | public void stateChanged(ChangeEvent e) |
164 | { |
165 | setQuality((float) (_compressionQuality.getValue() / MAX_PERCENT_FLOAT)); |
166 | } |
167 | }); |
168 | } |
169 | |
170 | public void setImage(RenderedImage image) |
171 | { |
172 | _image = image; |
173 | refreshFileSize(); |
174 | } |
175 | |
176 | public ImageWriter getImageWriter() |
177 | { |
178 | return ((ImageIOHelper.WriterItem) _writers.getSelectedItem()).getWriter(); |
179 | } |
180 | |
181 | public ImageWriteParam getParameters() |
182 | { |
183 | return _params; |
184 | } |
185 | |
186 | private void setFormat(String format) |
187 | { |
188 | _writers.setModel(new DefaultComboBoxModel(ImageIOHelper.getFormatWriters(format))); |
189 | _writers.setSelectedIndex(0); |
190 | } |
191 | |
192 | private void setWriter(ImageWriter writer) |
193 | { |
194 | boolean emptyTypes = true; |
195 | _params = writer.getDefaultWriteParam(); |
196 | if (_params.canWriteCompressed()) |
197 | { |
198 | _params.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); |
199 | |
200 | String[] types = _params.getCompressionTypes(); |
201 | if (types != null && types.length != 0) |
202 | { |
203 | _compressionType.setEnabled(true); |
204 | _compressionType.setModel(new DefaultComboBoxModel(types)); |
205 | if (_params.getCompressionType() == null) |
206 | { |
207 | _params.setCompressionType(types[0]); |
208 | } |
209 | _compressionType.setEnabled(types.length > 1); |
210 | _compressionType.setSelectedItem(_params.getCompressionType()); |
211 | emptyTypes = false; |
212 | } |
213 | } |
214 | if (emptyTypes) |
215 | { |
216 | _compressionType.setEnabled(false); |
217 | _compressionType.setModel(new DefaultComboBoxModel(EMPTY_COMBO_MODEL)); |
218 | _compressionType.setSelectedItem(null); |
219 | } |
220 | } |
221 | |
222 | private void setProgressive(boolean progressive) |
223 | { |
224 | if (_params.canWriteProgressive()) |
225 | { |
226 | if (progressive) |
227 | { |
228 | _params.setProgressiveMode(ImageWriteParam.MODE_DEFAULT); |
229 | } |
230 | else |
231 | { |
232 | _params.setProgressiveMode(ImageWriteParam.MODE_DISABLED); |
233 | } |
234 | } |
235 | refreshFileSize(); |
236 | } |
237 | |
238 | private void setCompressionType(String type) |
239 | { |
240 | boolean emptyQualities = true; |
241 | if (_params.canWriteCompressed() && type != null) |
242 | { |
243 | _params.setCompressionType(type); |
244 | |
245 | Hashtable labels = ImageIOHelper.getQualityLabels(_params, _detail); |
246 | if (labels != null) |
247 | { |
248 | _compressionQuality.setEnabled(true); |
249 | _compressionQuality.setLabelTable(labels); |
250 | _compressionQuality.setValue( |
251 | (int) (_params.getCompressionQuality() * MAX_PERCENT_FLOAT)); |
252 | emptyQualities = false; |
253 | } |
254 | } |
255 | if (emptyQualities) |
256 | { |
257 | _compressionQuality.setEnabled(false); |
258 | _compressionQuality.setValue(DEFAULT_QUALITY); |
259 | _compressionQuality.setLabelTable(ImageIOHelper.getDefaultQualityLabels(_detail)); |
260 | } |
261 | |
262 | if (_params.canWriteProgressive()) |
263 | { |
264 | _progressive.setEnabled(true); |
265 | _progressive.setSelected( |
266 | _params.getProgressiveMode() == ImageWriteParam.MODE_DEFAULT); |
267 | } |
268 | else |
269 | { |
270 | _progressive.setEnabled(false); |
271 | _progressive.setSelected(false); |
272 | } |
273 | } |
274 | |
275 | private void setQuality(float quality) |
276 | { |
277 | if (_params.canWriteCompressed()) |
278 | { |
279 | _params.setCompressionQuality(quality); |
280 | } |
281 | refreshFileSize(); |
282 | } |
283 | |
284 | private void refreshFileSize() |
285 | { |
286 | boolean canDisplaySize = false; |
287 | boolean canDisplayQuality = false; |
288 | if (_params.canWriteCompressed()) |
289 | { |
290 | float rate = _params.getCompressionQuality(); |
291 | rate = _params.getBitRate(rate); |
292 | if (rate != -1.0 && _image != null) |
293 | { |
294 | int size = _image.getHeight() * _image.getWidth() |
295 | * _image.getColorModel().getPixelSize(); |
296 | size = (int) (size * rate); |
297 | size /= ONE_KILO_BYTE; |
298 | _size.setText(ESTIMATED_SIZE + size); |
299 | canDisplaySize = true; |
300 | } |
301 | _displayQuality.setText(_compressionQuality.getValue() + " %"); |
302 | _lossless.setSelected(_params.isCompressionLossless()); |
303 | canDisplayQuality = true; |
304 | } |
305 | if (!canDisplaySize) |
306 | { |
307 | _size.setText(""); |
308 | } |
309 | if (!canDisplayQuality) |
310 | { |
311 | _displayQuality.setText(""); |
312 | _lossless.setSelected(true); |
313 | } |
314 | } |
315 | |
316 | static private final String[] EMPTY_COMBO_MODEL = {" "}; |
317 | |
318 | static private final int MAX_PERCENT_INT = 100; |
319 | static private final double MAX_PERCENT_FLOAT = 100.0; |
320 | static private final int ONE_KILO_BYTE = 1024; |
321 | static private final int DEFAULT_QUALITY = 50; |
322 | |
323 | static private final int QUALITY_MINOR_TICK = 5; |
324 | static private final int QUALITY_MAJOR_TICK = 50; |
325 | |
326 | private ImageWriteParam _params; |
327 | private RenderedImage _image; |
328 | |
329 | final private boolean _detail; |
330 | final private JLabel _lblFormats = new JLabel(); |
331 | final private JComboBox _formats = new JComboBox(); |
332 | final private JLabel _lblWriters = new JLabel(); |
333 | final private JComboBox _writers = new JComboBox(); |
334 | final private JLabel _lblCompressionType = new JLabel(); |
335 | final private JComboBox _compressionType = new JComboBox(); |
336 | final private JCheckBox _lossless = new JCheckBox(); |
337 | final private JCheckBox _progressive = new JCheckBox(); |
338 | final private JLabel _lblQuality = new JLabel(); |
339 | final private JTextField _displayQuality = new JTextField(); |
340 | final private JSlider _compressionQuality = new JSlider(0, MAX_PERCENT_INT); |
341 | final private JLabel _size = new JLabel(); |
342 | } |
343 | // CSON: ClassDataAbstractionCoupling |