1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.forgerock.doc.maven.utils;
18
19 import org.apache.commons.io.FileUtils;
20
21 import javax.imageio.IIOImage;
22 import javax.imageio.ImageIO;
23 import javax.imageio.ImageTypeSpecifier;
24 import javax.imageio.ImageWriteParam;
25 import javax.imageio.ImageWriter;
26 import javax.imageio.metadata.IIOInvalidTreeException;
27 import javax.imageio.metadata.IIOMetadata;
28 import javax.imageio.metadata.IIOMetadataNode;
29 import javax.imageio.stream.ImageOutputStream;
30 import java.awt.Graphics2D;
31 import java.awt.RenderingHints;
32 import java.awt.Transparency;
33 import java.awt.image.BufferedImage;
34 import java.io.File;
35 import java.io.IOException;
36 import java.util.Iterator;
37
38
39
40
41 public final class PngUtils {
42
43
44
45
46
47
48
49
50 private static int getHeight(final File image) throws IOException {
51 BufferedImage bufferedImage = ImageIO.read(image);
52 return bufferedImage.getHeight();
53 }
54
55
56
57
58
59
60
61 private static int getWidth(final File image) throws IOException {
62 BufferedImage bufferedImage = ImageIO.read(image);
63 return bufferedImage.getWidth();
64 }
65
66
67
68
69
70
71 public static void resizePng(final File image)
72 throws IOException {
73 BufferedImage originalImage = ImageIO.read(image);
74
75 final int imageWidth = getWidth(image);
76 final int imageHeight = getHeight(image);
77 final int newWidth = 700;
78
79 String absolutePath = image.getAbsolutePath();
80
81
82
83
84
85 File thumbFile = new File(image.getParent(), "thumb_" + image.getName());
86
87 if (imageWidth > newWidth) {
88
89 final int newHeight = Math.round(imageHeight * newWidth / imageWidth);
90
91
92
93
94 BufferedImage scaledBI = getScaledInstance(
95 originalImage,
96 newWidth,
97 newHeight,
98 RenderingHints.VALUE_INTERPOLATION_BILINEAR,
99 true);
100
101 saveBufferedImage(scaledBI, thumbFile, 160);
102 } else {
103 saveBufferedImage(originalImage, thumbFile, 160);
104 }
105 }
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129 public static BufferedImage getScaledInstance(
130 BufferedImage img,
131 int targetWidth,
132 int targetHeight,
133 Object hint,
134 boolean higherQuality) {
135 int type = (img.getTransparency() == Transparency.OPAQUE)
136 ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
137 BufferedImage ret = (BufferedImage) img;
138 int w, h;
139 if (higherQuality) {
140
141
142
143 w = img.getWidth();
144 h = img.getHeight();
145 } else {
146
147
148 w = targetWidth;
149 h = targetHeight;
150 }
151
152 do {
153 if (higherQuality && w > targetWidth) {
154 w /= 2;
155 if (w < targetWidth) {
156 w = targetWidth;
157 }
158 }
159
160 if (higherQuality && h > targetHeight) {
161 h /= 2;
162 if (h < targetHeight) {
163 h = targetHeight;
164 }
165 }
166
167 BufferedImage tmp = new BufferedImage(w, h, type);
168 Graphics2D g2 = tmp.createGraphics();
169 g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
170 g2.drawImage(ret, 0, 0, w, h, null);
171 g2.dispose();
172
173 ret = tmp;
174 } while (w != targetWidth || h != targetHeight);
175
176 return ret;
177 }
178
179
180
181
182
183
184
185
186
187 public static void setSafeDpi(final File image, final int maxHeightInInches)
188 throws IOException {
189 final int imageHeight = getHeight(image);
190 final int defaultDpi = 160;
191 final int defaultMaxHeight = maxHeightInInches * defaultDpi;
192
193
194 if (imageHeight > defaultMaxHeight) {
195 final double dpi = imageHeight * 1.0 / maxHeightInInches;
196 setDpi(image, (int) Math.round(dpi));
197 } else {
198 setDpi(image);
199 }
200 }
201
202
203
204
205
206
207
208 public static void setDpi(final File image) throws IOException {
209 setDpi(image, 160);
210 }
211
212
213
214
215
216
217
218
219 public static void setDpi(final File image, final int dotsPerInch) throws IOException {
220 BufferedImage in = ImageIO.read(image);
221 File updatedImage = File.createTempFile(image.getName(), ".tmp");
222 saveBufferedImage(in, updatedImage, dotsPerInch);
223
224 FileUtils.deleteQuietly(image);
225 FileUtils.moveFile(updatedImage, image);
226 }
227
228
229
230
231
232
233
234
235
236 private static void saveBufferedImage(final BufferedImage bufferedImage,
237 final File outputFile,
238 final int dotsPerInch)
239 throws IOException {
240 for (Iterator<ImageWriter> iw = ImageIO.getImageWritersByFormatName("png"); iw.hasNext();) {
241 ImageWriter writer = iw.next();
242 ImageWriteParam writeParam = writer.getDefaultWriteParam();
243 ImageTypeSpecifier typeSpecifier =
244 ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB);
245 IIOMetadata metadata = writer.getDefaultImageMetadata(typeSpecifier, writeParam);
246 if (metadata.isReadOnly() || !metadata.isStandardMetadataFormatSupported()) {
247 continue;
248 }
249
250 setDpi(metadata, dotsPerInch);
251
252 final ImageOutputStream stream = ImageIO.createImageOutputStream(outputFile);
253 try {
254 writer.setOutput(stream);
255 writer.write(metadata, new IIOImage(bufferedImage, null, metadata), writeParam);
256 } finally {
257 stream.close();
258 }
259 break;
260 }
261 }
262
263
264
265
266
267
268
269
270 private static void setDpi(IIOMetadata metadata, final int dotsPerInch)
271 throws IIOInvalidTreeException {
272
273 final double inchesPerMillimeter = 1.0 / 25.4;
274 final double dotsPerMillimeter = dotsPerInch * inchesPerMillimeter;
275
276 IIOMetadataNode horizontalPixelSize = new IIOMetadataNode("HorizontalPixelSize");
277 horizontalPixelSize.setAttribute("value", Double.toString(dotsPerMillimeter));
278
279 IIOMetadataNode verticalPixelSize = new IIOMetadataNode("VerticalPixelSize");
280 verticalPixelSize.setAttribute("value", Double.toString(dotsPerMillimeter));
281
282 IIOMetadataNode dimension = new IIOMetadataNode("Dimension");
283 dimension.appendChild(horizontalPixelSize);
284 dimension.appendChild(verticalPixelSize);
285
286 IIOMetadataNode root = new IIOMetadataNode("javax_imageio_1.0");
287 root.appendChild(dimension);
288
289 metadata.mergeTree("javax_imageio_1.0", root);
290 }
291
292 private PngUtils() {
293
294 }
295 }