ImageUtils: fix scale process
[fanfix.git] / ui / ImageUtilsAwt.java
CommitLineData
80500544
NR
1package be.nikiroo.utils.ui;
2
b3424395
NR
3import java.awt.Dimension;
4import java.awt.Graphics2D;
80500544
NR
5import java.awt.geom.AffineTransform;
6import java.awt.image.AffineTransformOp;
7import java.awt.image.BufferedImage;
80500544
NR
8import java.io.File;
9import java.io.IOException;
10import java.io.InputStream;
11
12import javax.imageio.ImageIO;
13
b3424395 14import be.nikiroo.utils.IOUtils;
80500544
NR
15import be.nikiroo.utils.Image;
16import be.nikiroo.utils.ImageUtils;
c48600a5 17import be.nikiroo.utils.StringUtils;
80500544
NR
18
19/**
20 * This class offer some utilities based around images and uses java.awt.
21 *
22 * @author niki
23 */
24public class ImageUtilsAwt extends ImageUtils {
b3424395
NR
25 /**
26 * A rotation to perform on an image.
27 *
28 * @author niki
29 */
30 public enum Rotation {
31 /** No rotation */
32 NONE,
33 /** Rotate the image to the right */
34 RIGHT,
35 /** Rotate the image to the left */
36 LEFT,
37 /** Rotate the image by 180° */
38 UTURN
39 }
113a5500 40
10b6023d
NR
41 @Override
42 protected boolean check() {
a2c1d5fe
NR
43 // Will not work if ImageIO is not available
44 ImageIO.getCacheDirectory();
10b6023d
NR
45 return true;
46 }
47
80500544
NR
48 @Override
49 public void saveAsImage(Image img, File target, String format)
50 throws IOException {
51 try {
e8aa5bf9 52 BufferedImage image = fromImage(img);
80500544
NR
53
54 boolean ok = false;
55 try {
56
57 ok = ImageIO.write(image, format, target);
58 } catch (IOException e) {
59 ok = false;
60 }
61
62 // Some formats are not reliable
e8aa5bf9 63 // Second chance: PNG
80500544 64 if (!ok && !format.equals("png")) {
89aa5782
NR
65 try {
66 ok = ImageIO.write(image, "png", target);
67 } catch (IllegalArgumentException e) {
68 throw e;
69 } catch (Exception e) {
70 throw new IOException("Undocumented exception occured, "
71 + "converting to IOException", e);
72 }
80500544
NR
73 }
74
75 if (!ok) {
76 throw new IOException(
77 "Cannot find a writer for this image and format: "
78 + format);
79 }
80 } catch (IOException e) {
81 throw new IOException("Cannot write image to " + target, e);
82 }
83 }
84
85 /**
86 * Convert the given {@link Image} into a {@link BufferedImage} object,
87 * respecting the EXIF transformations if any.
88 *
89 * @param img
90 * the {@link Image}
91 *
92 * @return the {@link Image} object
93 *
94 * @throws IOException
95 * in case of IO error
96 */
e704a414 97 public static BufferedImage fromImage(Image img) throws IOException {
b3424395
NR
98 return fromImage(img, Rotation.NONE);
99 }
113a5500 100
b3424395
NR
101 /**
102 * Convert the given {@link Image} into a {@link BufferedImage} object,
103 * respecting the EXIF transformations if any.
104 *
105 * @param img
106 * the {@link Image}
107 * @param rotation
108 * the rotation to apply, if any (can be null, same as
109 * {@link Rotation#NONE})
110 *
111 * @return the {@link Image} object
112 *
113 * @throws IOException
114 * in case of IO error
115 */
113a5500
NR
116 public static BufferedImage fromImage(Image img, Rotation rotation)
117 throws IOException {
7b42695f 118 InputStream in = img.newInputStream();
35466644
NR
119 BufferedImage image;
120 try {
7b42695f
NR
121 int orientation;
122 try {
123 orientation = getExifTransorm(in);
124 } catch (Exception e) {
125 // no EXIF transform, ok
126 orientation = -1;
127 }
80500544 128
7b42695f 129 in.reset();
80500544 130
7b42695f
NR
131 try {
132 image = ImageIO.read(in);
133 } catch (IllegalArgumentException e) {
134 throw e;
135 } catch (Exception e) {
136 throw new IOException("Undocumented exception occured, "
137 + "converting to IOException", e);
138 }
139
140 if (image == null) {
c48600a5 141 String extra = "";
59654e2a 142 if (img.getSize() <= 2048) {
c48600a5 143 try {
b3424395
NR
144 byte[] data = null;
145 InputStream inData = img.newInputStream();
146 try {
147 data = IOUtils.toByteArray(inData);
148 } finally {
149 inData.close();
150 }
113a5500 151 extra = ", content: " + new String(data, "UTF-8");
c48600a5
NR
152 } catch (Exception e) {
153 extra = ", content unavailable";
154 }
155 }
156 String ssize = StringUtils.formatNumber(img.getSize());
157 throw new IOException(
158 "Failed to convert input to image, size was: " + ssize
159 + extra);
7b42695f
NR
160 }
161
162 // Note: this code has been found on Internet;
163 // thank you anonymous coder.
164 int width = image.getWidth();
165 int height = image.getHeight();
166 AffineTransform affineTransform = new AffineTransform();
167
168 switch (orientation) {
169 case 1:
170 affineTransform = null;
171 break;
172 case 2: // Flip X
173 affineTransform.scale(-1.0, 1.0);
174 affineTransform.translate(-width, 0);
175 break;
176 case 3: // PI rotation
177 affineTransform.translate(width, height);
178 affineTransform.rotate(Math.PI);
179 break;
180 case 4: // Flip Y
181 affineTransform.scale(1.0, -1.0);
182 affineTransform.translate(0, -height);
183 break;
184 case 5: // - PI/2 and Flip X
185 affineTransform.rotate(-Math.PI / 2);
186 affineTransform.scale(-1.0, 1.0);
187 break;
188 case 6: // -PI/2 and -width
189 affineTransform.translate(height, 0);
190 affineTransform.rotate(Math.PI / 2);
191 break;
192 case 7: // PI/2 and Flip
193 affineTransform.scale(-1.0, 1.0);
194 affineTransform.translate(-height, 0);
195 affineTransform.translate(0, width);
196 affineTransform.rotate(3 * Math.PI / 2);
197 break;
198 case 8: // PI / 2
199 affineTransform.translate(0, width);
200 affineTransform.rotate(3 * Math.PI / 2);
201 break;
202 default:
203 affineTransform = null;
204 break;
205 }
113a5500 206
b3424395
NR
207 if (rotation == null)
208 rotation = Rotation.NONE;
113a5500 209
b3424395 210 switch (rotation) {
113a5500 211 case RIGHT:
b3424395
NR
212 if (affineTransform == null) {
213 affineTransform = new AffineTransform();
214 }
215 affineTransform.translate(height, 0);
216 affineTransform.rotate(Math.PI / 2);
217 break;
113a5500 218 case LEFT:
b3424395
NR
219 if (affineTransform == null) {
220 affineTransform = new AffineTransform();
221 }
222 affineTransform.translate(0, width);
223 affineTransform.rotate(3 * Math.PI / 2);
224 break;
225 case UTURN:
226 if (affineTransform == null) {
227 affineTransform = new AffineTransform();
228 }
229 affineTransform.translate(width, height);
230 affineTransform.rotate(Math.PI);
231 break;
232 default:
233 break;
234 }
80500544 235
7b42695f
NR
236 if (affineTransform != null) {
237 AffineTransformOp affineTransformOp = new AffineTransformOp(
238 affineTransform, AffineTransformOp.TYPE_BILINEAR);
80500544 239
7b42695f
NR
240 BufferedImage transformedImage = new BufferedImage(width,
241 height, image.getType());
242 transformedImage = affineTransformOp.filter(image,
243 transformedImage);
80500544 244
7b42695f
NR
245 image = transformedImage;
246 }
247 //
248 } finally {
249 in.close();
80500544 250 }
80500544
NR
251
252 return image;
253 }
b3424395
NR
254
255 /**
256 * Resize the given image.
257 *
258 * @param areaSize
259 * the base size of the target dimension for snap sizes
260 * @param image
261 * the image to resize
262 * @param zoom
263 * the zoom factor or -1 for snap size
264 * @param zoomSnapWidth
265 * if snap size, TRUE to snap to width (and FALSE, snap to
266 * height)
267 *
268 * @return a new, resized image
269 */
270 public static BufferedImage scaleImage(Dimension areaSize,
271 BufferedImage image, double zoom, boolean zoomSnapWidth) {
272 Integer scaledSize[] = scaleSize(areaSize.width, areaSize.height,
273 image.getWidth(), image.getHeight(), zoom, zoomSnapWidth);
274 int width = scaledSize[0];
275 int height = scaledSize[1];
276 BufferedImage resizedImage = new BufferedImage(width, height,
277 BufferedImage.TYPE_4BYTE_ABGR);
278 Graphics2D g = resizedImage.createGraphics();
279 try {
280 g.drawImage(image, 0, 0, width, height, null);
281 } finally {
282 g.dispose();
283 }
113a5500 284
b3424395
NR
285 return resizedImage;
286 }
80500544 287}