68
|
1 /*
|
|
2 Copyright (c) 2008 Franklin Schmidt <fschmidt@gmail.com>
|
|
3
|
|
4 Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5 of this software and associated documentation files (the "Software"), to deal
|
|
6 in the Software without restriction, including without limitation the rights
|
|
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8 copies of the Software, and to permit persons to whom the Software is
|
|
9 furnished to do so, subject to the following conditions:
|
|
10
|
|
11 The above copyright notice and this permission notice shall be included in
|
|
12 all copies or substantial portions of the Software.
|
|
13
|
|
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
20 THE SOFTWARE.
|
|
21 */
|
|
22
|
|
23 package fschmidt.util.java;
|
|
24
|
|
25 import sun.awt.image.BufferedImageGraphicsConfig;
|
|
26
|
|
27 import javax.imageio.ImageIO;
|
|
28 import java.awt.AlphaComposite;
|
|
29 import java.awt.Graphics2D;
|
|
30 import java.awt.GraphicsConfiguration;
|
|
31 import java.awt.RenderingHints;
|
|
32 import java.awt.Transparency;
|
|
33 import java.awt.image.BufferedImage;
|
|
34 import java.awt.image.BufferedImageOp;
|
|
35 import java.awt.image.ConvolveOp;
|
|
36 import java.awt.image.Kernel;
|
|
37 import java.io.ByteArrayInputStream;
|
|
38 import java.io.ByteArrayOutputStream;
|
|
39 import java.io.File;
|
|
40 import java.io.FileInputStream;
|
|
41 import java.io.FileOutputStream;
|
|
42 import java.io.IOException;
|
|
43 import java.io.InputStream;
|
|
44 import java.util.HashMap;
|
|
45 import java.util.Map;
|
|
46
|
|
47
|
|
48 public final class ImageUtils {
|
|
49 private ImageUtils() {} // never
|
|
50
|
|
51 public static ImageDetails saveImage(String imagePath, BufferedImage image, String format)
|
|
52 throws IllegalArgumentException, IOException
|
|
53 {
|
|
54 FileOutputStream fos = new FileOutputStream(imagePath);
|
|
55 try {
|
|
56 ImageIO.write(image, format, fos);
|
|
57 } finally {
|
|
58 image.flush();
|
|
59 fos.close();
|
|
60 }
|
|
61 return new ImageDetails(image.getHeight(), image.getWidth());
|
|
62 }
|
|
63
|
|
64 public static BufferedImage loadImage(String imagePath)
|
|
65 throws IOException, IllegalArgumentException
|
|
66 {
|
|
67 FileInputStream fis = new FileInputStream(imagePath);
|
|
68 try {
|
|
69 return createCompatibleImage(ImageIO.read(fis));
|
|
70 } finally {
|
|
71 fis.close();
|
|
72 }
|
|
73 }
|
|
74
|
|
75 public static BufferedImage getImage(InputStream in)
|
|
76 throws IOException, IllegalArgumentException
|
|
77 {
|
|
78 BufferedImage img = ImageIO.read(in);
|
|
79 return img == null? null : createCompatibleImage(img);
|
|
80 }
|
|
81
|
|
82 public static void deleteImage(String imagePath) {
|
|
83 File imageFile = new File(imagePath);
|
|
84 if (imageFile.exists())
|
|
85 imageFile.delete();
|
|
86 }
|
|
87
|
|
88 private static BufferedImage fixImage(BufferedImage img) {
|
|
89 // Clone the image using the RGB type to prevent color problems.
|
|
90 BufferedImage temp = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB);
|
|
91 Graphics2D g2 = temp.createGraphics();
|
|
92 g2.drawImage(img, 0, 0, null);
|
|
93 g2.dispose();
|
|
94 return temp;
|
|
95 }
|
|
96
|
|
97 public static ByteArrayOutputStream asOutputStream(BufferedImage img, String format) throws IOException {
|
|
98 ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
99 ImageIO.write(fixImage(img), format, baos);
|
|
100 return baos;
|
|
101 }
|
|
102
|
|
103 public static InputStream asInputStream(BufferedImage img, String format) throws IOException {
|
|
104 ByteArrayOutputStream baos = asOutputStream(img, format);
|
|
105 final byte[] bytes = baos.toByteArray();
|
|
106 return new ByteArrayInputStream(bytes);
|
|
107 }
|
|
108
|
|
109 public static BufferedImage cropImage(BufferedImage image, int x, int y, int width, int height)
|
|
110 throws IllegalArgumentException, IOException
|
|
111 {
|
|
112 if (x < 0) x = 0;
|
|
113 if (y < 0) y = 0;
|
|
114 if (width > image.getWidth())
|
|
115 width = image.getWidth();
|
|
116 if (height > image.getHeight())
|
|
117 height = image.getHeight();
|
|
118 if (x + width > image.getWidth())
|
|
119 x = image.getWidth() - width;
|
|
120 if (y + height > image.getHeight())
|
|
121 y = image.getHeight() - height;
|
|
122 return image.getSubimage(x, y, width, height);
|
|
123 }
|
|
124
|
|
125 public static BufferedImage resizeImage(BufferedImage image, int width, int height) {
|
|
126 int type = image.getType() == 0? BufferedImage.TYPE_INT_ARGB : image.getType();
|
|
127 BufferedImage resizedImage = new BufferedImage(width, height, type);
|
|
128 Graphics2D g = resizedImage.createGraphics();
|
|
129 g.setComposite(AlphaComposite.Src);
|
|
130 g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
|
131 g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
|
|
132 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
|
133 g.drawImage(image, 0, 0, width, height, null);
|
|
134 g.dispose();
|
|
135 return resizedImage;
|
|
136 }
|
|
137
|
|
138 public static BufferedImage resizeKeepRatio(BufferedImage img, int width, int height) {
|
|
139 int newWidth = img.getWidth() < img.getHeight()? (int) Math.ceil(img.getWidth() * height / (float) img.getHeight()) : width;
|
|
140 int newHeight = img.getWidth() < img.getHeight()? height : (int) Math.ceil(img.getHeight() * width / (float) img.getWidth());
|
|
141 if (newWidth > width) {
|
|
142 newWidth = width;
|
|
143 newHeight = img.getHeight() * width / img.getWidth();
|
|
144 } else if (newHeight > height) {
|
|
145 newWidth = img.getWidth() * height / img.getHeight();
|
|
146 newHeight = height;
|
|
147 }
|
|
148 return resizeImage(img, newWidth, newHeight);
|
|
149 }
|
|
150
|
|
151 public static BufferedImage blurImage(BufferedImage image) {
|
|
152 float ninth = 1.0f/9.0f;
|
|
153 float[] blurKernel = {
|
|
154 ninth, ninth, ninth,
|
|
155 ninth, ninth, ninth,
|
|
156 ninth, ninth, ninth
|
|
157 };
|
|
158
|
|
159 Map<RenderingHints.Key, Object> map = new HashMap<RenderingHints.Key, Object>();
|
|
160 map.put(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
|
161 map.put(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
|
|
162 map.put(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
|
|
163 RenderingHints hints = new RenderingHints(map);
|
|
164 BufferedImageOp op = new ConvolveOp(new Kernel(3, 3, blurKernel), ConvolveOp.EDGE_NO_OP, hints);
|
|
165 image = fixImage(image);
|
|
166 return op.filter(image, null);
|
|
167 }
|
|
168
|
|
169 private static BufferedImage createCompatibleImage(BufferedImage image) {
|
|
170 GraphicsConfiguration gc = BufferedImageGraphicsConfig.getConfig(image);
|
|
171 int w = image.getWidth();
|
|
172 int h = image.getHeight();
|
|
173 BufferedImage result = gc.createCompatibleImage(w, h, Transparency.TRANSLUCENT);
|
|
174 Graphics2D g2 = result.createGraphics();
|
|
175 g2.drawRenderedImage(image, null);
|
|
176 g2.dispose();
|
|
177 return result;
|
|
178 }
|
|
179
|
|
180 public static BufferedImage getThumbnail(BufferedImage img, int width, int height) {
|
|
181 if (img.getWidth() <= width && img.getHeight() <= height)
|
|
182 return img;
|
|
183 else {
|
|
184 int widthLimit = 3 * width;
|
|
185 int heightLimit = 3 * height;
|
|
186 if (img.getWidth() > widthLimit || img.getHeight() > heightLimit) {
|
|
187 img = resizeKeepRatio(img, widthLimit, heightLimit);
|
|
188 img = blurImage(img);
|
|
189 }
|
|
190 return resizeKeepRatio(img, width, height);
|
|
191 }
|
|
192 }
|
|
193
|
|
194 public static final class ImageDetails {
|
|
195 private int height;
|
|
196 private int width;
|
|
197
|
|
198 public ImageDetails(int height, int width) {
|
|
199 this.height = height;
|
|
200 this.width = width;
|
|
201 }
|
|
202
|
|
203 public int getHeight() { return height; }
|
|
204 public int getWidth() { return width; }
|
|
205 }
|
|
206
|
|
207 /* public static void main(String[] args) {
|
|
208 // 140 x 100 px
|
|
209 try {
|
|
210 testThumbnail("a.png", "a1");
|
|
211 testThumbnail("b.jpg", "b1");
|
|
212 testThumbnail("c.png", "c1");
|
|
213 testThumbnail("d.jpg", "d1");
|
|
214 testThumbnail("e.jpg", "e1");
|
|
215 testThumbnail("f.jpg", "f1");
|
|
216 testThumbnail("g.png", "g1");
|
|
217 } catch (IOException e) {
|
|
218 e.printStackTrace();
|
|
219 }
|
|
220 }
|
|
221
|
|
222 private static void testThumbnail(String fileIn, String fileOut) throws IOException {
|
|
223 String format = "jpeg";
|
|
224 BufferedImage img = loadImage("c:\\" + fileIn);
|
|
225 System.out.println(fileIn + " w:" + img.getWidth() + " h:" + img.getHeight());
|
|
226 long start = System.currentTimeMillis();
|
|
227 BufferedImage thumb = getThumbnail(img, 140, 100);
|
|
228
|
|
229 BufferedImage temp = new BufferedImage(thumb.getWidth(), thumb.getHeight(), BufferedImage.TYPE_INT_RGB);
|
|
230 Graphics2D g2 = temp.createGraphics();
|
|
231 g2.drawImage(thumb, 0, 0, null);
|
|
232 g2.dispose();
|
|
233 thumb = temp;
|
|
234
|
|
235 System.out.println("Time = " + (System.currentTimeMillis()-start));
|
|
236 saveImage("c:\\"+fileOut+'.'+format, thumb, format);
|
|
237 }*/
|
|
238 }
|