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.imaging; |
16 | |
17 | import java.awt.Component; |
18 | import java.io.File; |
19 | import java.io.IOException; |
20 | import java.util.ArrayList; |
21 | import java.util.Arrays; |
22 | import java.util.Hashtable; |
23 | import java.util.Iterator; |
24 | import java.util.List; |
25 | import java.util.Set; |
26 | import java.util.TreeSet; |
27 | |
28 | import javax.imageio.ImageIO; |
29 | import javax.imageio.ImageReader; |
30 | import javax.imageio.ImageTypeSpecifier; |
31 | import javax.imageio.ImageWriteParam; |
32 | import javax.imageio.ImageWriter; |
33 | import javax.imageio.stream.FileImageInputStream; |
34 | import javax.imageio.stream.ImageInputStream; |
35 | import javax.swing.JLabel; |
36 | |
37 | /** |
38 | * Helper class providing a few utilities around ImageIO. |
39 | * |
40 | * @author Jean-Francois Poilpret |
41 | */ |
42 | public class ImageIOHelper |
43 | { |
44 | protected ImageIOHelper() |
45 | { |
46 | } |
47 | |
48 | static public String[] getReaderExtensions() |
49 | { |
50 | Set<String> allExtensions = new TreeSet<String>(); |
51 | // First find all formats that have associated image writers |
52 | String[] formats = ImageIO.getReaderFormatNames(); |
53 | for (int i = 0; i < formats.length; i++) |
54 | { |
55 | Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName(formats[i]); |
56 | while (readers.hasNext()) |
57 | { |
58 | ImageReader reader = readers.next(); |
59 | String[] extensions = reader.getOriginatingProvider().getFileSuffixes(); |
60 | allExtensions.addAll(Arrays.asList(extensions)); |
61 | } |
62 | } |
63 | return allExtensions.toArray(new String[allExtensions.size()]); |
64 | } |
65 | |
66 | static public ImageReader getReader(File input) throws IOException |
67 | { |
68 | return getReader(new FileImageInputStream(input)); |
69 | } |
70 | |
71 | static public ImageReader getReader(ImageInputStream stream) |
72 | { |
73 | Iterator<ImageReader> i = ImageIO.getImageReaders(stream); |
74 | if (i == null || !i.hasNext()) |
75 | { |
76 | return null; |
77 | } |
78 | else |
79 | { |
80 | ImageReader reader = i.next(); |
81 | reader.setInput(stream); |
82 | return reader; |
83 | } |
84 | } |
85 | |
86 | static public String[] getAcceptedFormats(ImageTypeSpecifier type) |
87 | { |
88 | // First find all formats that have associated image writers |
89 | Set<String> formats = unique(ImageIO.getWriterFormatNames()); |
90 | Iterator<String> i = formats.iterator(); |
91 | while (i.hasNext()) |
92 | { |
93 | String format = i.next(); |
94 | Iterator<ImageWriter> writers = ImageIO.getImageWriters(type, format); |
95 | if (!writers.hasNext()) |
96 | { |
97 | // No writer in this format for the specified image type. skip it |
98 | i.remove(); |
99 | } |
100 | } |
101 | return formats.toArray(new String[formats.size()]); |
102 | } |
103 | |
104 | static public String[] getWriterExtensions(ImageWriter writer) |
105 | { |
106 | String[] extensions = writer.getOriginatingProvider().getFileSuffixes(); |
107 | if (extensions != null) |
108 | { |
109 | Arrays.sort(extensions); |
110 | } |
111 | return extensions; |
112 | } |
113 | |
114 | static public WriterItem[] getFormatWriters(String format) |
115 | { |
116 | Iterator<ImageWriter> i = ImageIO.getImageWritersByFormatName(format); |
117 | Set<WriterItem> writers = new TreeSet<WriterItem>(); |
118 | while (i.hasNext()) |
119 | { |
120 | writers.add(new WriterItem(i.next())); |
121 | } |
122 | return writers.toArray(new WriterItem[writers.size()]); |
123 | } |
124 | |
125 | static public String[] getAcceptedExtensions(ImageTypeSpecifier type) |
126 | { |
127 | // First find all formats that have associated image writers |
128 | Set<String> formats = unique(ImageIO.getWriterFormatNames()); |
129 | List<String> allExtensions = new ArrayList<String>(); |
130 | for (String format: formats) |
131 | { |
132 | Iterator<ImageWriter> writers = ImageIO.getImageWriters(type, format); |
133 | while (writers.hasNext()) |
134 | { |
135 | ImageWriter writer = writers.next(); |
136 | String[] suffixes = writer.getOriginatingProvider().getFileSuffixes(); |
137 | if (suffixes == null) |
138 | { |
139 | continue; |
140 | } |
141 | for (String suffix: suffixes) |
142 | { |
143 | if (suffix.length() > 0) |
144 | { |
145 | allExtensions.add(suffix); |
146 | } |
147 | } |
148 | } |
149 | } |
150 | return unique(allExtensions); |
151 | } |
152 | |
153 | static public Hashtable<Integer, Component> getDefaultQualityLabels(boolean detail) |
154 | { |
155 | Hashtable<Integer, Component> labels = new Hashtable<Integer, Component>(); |
156 | int step = (detail ? QUALITY_STEP_DETAIL : QUALITY_STEP_GROSS); |
157 | for (int i = 0; i <= QUALITY_MAX; i += step) |
158 | { |
159 | labels.put(i, new JLabel(i + " %")); |
160 | } |
161 | return labels; |
162 | } |
163 | |
164 | static public Hashtable getQualityLabels(ImageWriteParam params, boolean detail) |
165 | { |
166 | String[] descs = params.getCompressionQualityDescriptions(); |
167 | float[] values = params.getCompressionQualityValues(); |
168 | if (descs == null || values == null) |
169 | { |
170 | return null; |
171 | } |
172 | |
173 | Hashtable<Integer, Component> labels = getDefaultQualityLabels(detail); |
174 | if (!detail) |
175 | { |
176 | return labels; |
177 | } |
178 | // According to ImageIO javadoc, the next test should always be true... |
179 | if (descs.length + 1 == values.length) |
180 | { |
181 | // If true, this means that desc[i] gives a description of the |
182 | // range [values[i]..values[i+1]] |
183 | // So position the description label in the middle of both range values |
184 | for (int i = 0; i < descs.length; i++) |
185 | { |
186 | int quality = (int) ((values[i + 1] + values[i]) * MID_VALUE + ROUNDING); |
187 | if (labels.contains(quality)) |
188 | { |
189 | labels.put(quality, new JLabel(quality + " % " + descs[i])); |
190 | } |
191 | else |
192 | { |
193 | labels.put(quality, new JLabel(descs[i])); |
194 | } |
195 | } |
196 | } |
197 | else |
198 | { |
199 | // ... but I never saw any ImageWriteParam for which it was actually true! |
200 | for (int i = 0; i < descs.length; i++) |
201 | { |
202 | int quality = (int) (values[i] * MAX_VALUE + ROUNDING); |
203 | labels.put(quality, new JLabel(quality + " % " + descs[i])); |
204 | } |
205 | } |
206 | return labels; |
207 | } |
208 | |
209 | static private Set<String> unique(String[] strings) |
210 | { |
211 | Set<String> set = new TreeSet<String>(); |
212 | for (int i = 0; i < strings.length; i++) |
213 | { |
214 | set.add(strings[i].toLowerCase()); |
215 | } |
216 | return set; |
217 | } |
218 | |
219 | static private String[] unique(List<String> strings) |
220 | { |
221 | Set<String> set = unique(strings.toArray(new String[strings.size()])); |
222 | return set.toArray(new String[set.size()]); |
223 | } |
224 | |
225 | static public class WriterItem implements Comparable |
226 | { |
227 | public WriterItem(ImageWriter writer) |
228 | { |
229 | _writer = writer; |
230 | _name = writer.getOriginatingProvider().getVendorName(); |
231 | } |
232 | |
233 | public ImageWriter getWriter() |
234 | { |
235 | return _writer; |
236 | } |
237 | |
238 | public int compareTo(Object that) |
239 | { |
240 | return this.toString().compareTo(that.toString()); |
241 | } |
242 | |
243 | @Override public String toString() |
244 | { |
245 | return _name; |
246 | } |
247 | |
248 | private final ImageWriter _writer; |
249 | private final String _name; |
250 | } |
251 | |
252 | static final private double MAX_VALUE = 100.0; |
253 | static final private double MID_VALUE = 50.0; |
254 | static final private double ROUNDING = 0.5; |
255 | |
256 | static final private int QUALITY_MAX = 100; |
257 | static final private int QUALITY_STEP_DETAIL = 10; |
258 | static final private int QUALITY_STEP_GROSS = 25; |
259 | } |