1 package com.atlassian.core.util.thumbnail;
2
3 import com.atlassian.core.util.ImageInfo;
4 import com.google.common.base.Predicates;
5 import junit.framework.TestCase;
6 import org.apache.log4j.Appender;
7 import org.apache.log4j.Level;
8 import org.apache.log4j.Logger;
9 import org.apache.log4j.spi.LoggingEvent;
10 import org.mockito.ArgumentCaptor;
11
12 import javax.imageio.ImageIO;
13 import java.awt.*;
14 import java.awt.image.BufferedImage;
15 import java.io.File;
16 import java.io.FileInputStream;
17 import java.io.IOException;
18
19 import static org.mockito.Mockito.mock;
20 import static org.mockito.Mockito.spy;
21 import static org.mockito.Mockito.verify;
22
23
24
25
26
27
28
29
30 public class ThumberTest extends TestCase
31 {
32 private static final String[] CMYK_IMAGES = new String[] {
33 "/cmyk/CMYK Coated FOGRA27 (ISO 12647-2-2004).jpg",
34 "/cmyk/CMYK Coated FOGRA39 (ISO 12647-2-2004).jpg",
35 "/cmyk/CMYK Euroscale Coated v2.jpg",
36 "/cmyk/CMYK Euroscale Uncoated v2.jpg",
37 "/cmyk/CMYK Generic Profile.jpg",
38 "/cmyk/CMYK Japan Color 2001 Coated.jpg",
39 "/cmyk/CMYK Japan Color 2001 Uncoated.jpg",
40 "/cmyk/CMYK Japan Color 2002 Newspaper.jpg",
41 "/cmyk/CMYK Japan Web Coated (Ad).jpg",
42 "/cmyk/CMYK No Profile.jpg",
43 "/cmyk/CMYK Uncoated FOGRA29 (ISO 12647-2-2004).jpg",
44 "/cmyk/CMYK US Sheetfed Coated v2.jpg",
45 "/cmyk/CMYK US Sheetfed Uncoated v2.jpg",
46 "/cmyk/CMYK US Web Coated (SWOP) v2.jpg",
47 "/cmyk/CMYK US Web Uncoated v2.jpg",
48 "/cmyk/CMYK Web Coated FOGRA28 (ISO 12647-2-2004).jpg",
49 };
50
51 private static final int MAX_WIDTH = 300;
52 private static final int MAX_HEIGHT = 400;
53 private final File tempFile;
54 private static final String TEST_FILE_NAME = "mypicture.png";
55
56 public ThumberTest() throws IOException
57 {
58 tempFile = File.createTempFile("atlassian-core-thumbnail", "test");
59 }
60
61 @Override
62 protected void setUp() throws Exception
63 {
64
65 tempFile.delete();
66 }
67
68 @Override
69 protected void tearDown() throws Exception
70 {
71
72 tempFile.delete();
73 }
74
75 public void testRetrieveOrCreateThumbnailTransparentPng() throws IOException
76 {
77 Thumber thumber = new Thumber(Thumbnail.MimeType.PNG);
78 testRetrieveOrCreateThumbnail(thumber, "/transparent-png.png", Transparency.TRANSLUCENT, ImageInfo.FORMAT_PNG);
79 }
80
81 public void testRetrieveOrCreateThumbnailBrokenGif() throws IOException
82 {
83 Appender appender = mock(Appender.class);
84 Logger.getRootLogger().addAppender(appender);
85 try
86 {
87 ArgumentCaptor arguments = ArgumentCaptor.forClass(LoggingEvent.class);
88 Thumber thumber = spy(new Thumber());
89
90 assertNull(thumber.retrieveOrCreateThumbNail(getClass().getResourceAsStream("/NotAnImage.jpg"), TEST_FILE_NAME, tempFile, MAX_WIDTH, MAX_HEIGHT, 1));
91 verify(appender).doAppend((LoggingEvent) arguments.capture());
92
93 final LoggingEvent loggingEvent = (LoggingEvent) arguments.getValue();
94 assertEquals(Level.ERROR, loggingEvent.getLevel());
95 assertEquals("com.atlassian.core.util.thumbnail.Thumber", loggingEvent.categoryName);
96 assertEquals("Unable to create thumbnail image for id 1", loggingEvent.getMessage());
97 }
98 finally
99 {
100 Logger.getRootLogger().removeAppender(appender);
101 }
102 }
103
104 public void testRetrieveOrCreateThumbnailOpaqueGif() throws IOException
105 {
106 Thumber thumber = new Thumber();
107 testRetrieveOrCreateThumbnail(thumber, "/opaque-gif.gif", Transparency.OPAQUE, ImageInfo.FORMAT_JPEG);
108 }
109
110 public void testRetrieveOrCreateThumbnailOpaqueGifAsStream() throws IOException
111 {
112 Thumber thumber = new Thumber();
113 testRetrieveOrCreateThumbnailAsStream(thumber, "/opaque-gif.gif", Transparency.OPAQUE, ImageInfo.FORMAT_JPEG);
114 }
115
116 public void testRetrieveOrCreateThumbnailOpaquePng() throws IOException
117 {
118 Thumber thumber = new Thumber();
119 testRetrieveOrCreateThumbnail(thumber, "/opaque-png.png", Transparency.OPAQUE, ImageInfo.FORMAT_JPEG);
120 }
121
122 public void testRetrieveOrCreateThumbnailOpaquePngAsStream() throws IOException
123 {
124 Thumber thumber = new Thumber();
125 testRetrieveOrCreateThumbnailAsStream(thumber, "/opaque-png.png", Transparency.OPAQUE, ImageInfo.FORMAT_JPEG);
126 }
127
128 public void testRetrieveOrCreateThumbnailJpg() throws IOException
129 {
130 Thumber thumber = new Thumber();
131 testRetrieveOrCreateThumbnail(thumber, "/test-jpg.jpg", Transparency.OPAQUE, ImageInfo.FORMAT_JPEG);
132 }
133
134 public void testRetrieveOrCreateThumbnailJpgAsStream() throws IOException
135 {
136 Thumber thumber = new Thumber();
137 testRetrieveOrCreateThumbnailAsStream(thumber, "/test-jpg.jpg", Transparency.OPAQUE, ImageInfo.FORMAT_JPEG);
138 }
139
140 public void testRetrieveOrCreateThumbnailTransparentGif() throws IOException
141 {
142 Thumber thumber = new Thumber(Thumbnail.MimeType.PNG);
143 testRetrieveOrCreateThumbnail(thumber, "/transparent-gif.gif", Transparency.TRANSLUCENT, ImageInfo.FORMAT_PNG);
144 }
145
146 public void testRetrieveOrCreateThumbnailTransparentGifAsStream() throws IOException
147 {
148 Thumber thumber = new Thumber(Thumbnail.MimeType.PNG);
149
150 testRetrieveOrCreateThumbnailAsStream(thumber, "/transparent-gif.gif", Transparency.BITMASK, ImageInfo.FORMAT_PNG);
151 }
152
153 public void testRetrieveOrCreateThumbnailCMYKJpg() throws IOException {
154 Thumber thumber = new Thumber();
155
156 final Thumbnail thumbnail = thumber.retrieveOrCreateThumbNail(
157 getClass().getResourceAsStream("/cmyk.jpg"), TEST_FILE_NAME,
158 tempFile, MAX_WIDTH, MAX_HEIGHT, 1);
159
160
161
162 assertThumbnail(thumbnail, Transparency.OPAQUE, ImageInfo.FORMAT_JPEG,
163 MAX_WIDTH, MAX_WIDTH * 1134 / 1134);
164 }
165
166 public void testAllCmykImagesShouldBeLoaded() throws Exception {
167 Thumber thumber = new Thumber();
168
169 for (String cmykImage : CMYK_IMAGES) {
170 final Thumbnail thumbnail = thumber.retrieveOrCreateThumbNail(
171 getClass().getResourceAsStream(cmykImage), TEST_FILE_NAME,
172 tempFile, MAX_WIDTH, MAX_HEIGHT, 1);
173 assertNotNull(thumbnail);
174 }
175 }
176
177 public void testScaleImageForNonBufferedImage()
178 {
179
180 final Image image = Toolkit.getDefaultToolkit().getImage(getClass().getResource("/opaque-gif.gif"));
181 final BufferedImage thumbnail = new Thumber().scaleImage(image,
182 new Thumber.WidthHeightHelper(MAX_WIDTH, MAX_HEIGHT));
183
184
185 assertEquals(MAX_WIDTH, thumbnail.getWidth());
186 assertEquals(MAX_HEIGHT, thumbnail.getHeight());
187 assertEquals(Transparency.OPAQUE, thumbnail.getTransparency());
188 }
189
190 public void testScaleImageForNonBufferedImageTransparentGif()
191 {
192
193 final Image image = Toolkit.getDefaultToolkit().getImage(getClass().getResource("/transparent-gif.gif"));
194 final BufferedImage thumbnail = new Thumber().scaleImage(image,
195 new Thumber.WidthHeightHelper(MAX_WIDTH, MAX_HEIGHT));
196
197
198 assertEquals(MAX_WIDTH, thumbnail.getWidth());
199 assertEquals(MAX_HEIGHT, thumbnail.getHeight());
200 assertEquals(Transparency.TRANSLUCENT, thumbnail.getTransparency());
201 }
202
203 public void testUpscalingShouldReturnOriginalSize() throws IOException
204 {
205 final String resourceName = "/opaque-png.png";
206 final BufferedImage image = ImageIO.read(getClass().getResourceAsStream(resourceName));
207 final int width = image.getWidth();
208 final int height = image.getHeight();
209 final Thumbnail thumbnail = new Thumber().retrieveOrCreateThumbNail(
210 getClass().getResourceAsStream(resourceName), TEST_FILE_NAME,
211 tempFile, width * 3, height * 3, 1);
212
213 assertThumbnail(thumbnail, Transparency.OPAQUE, ImageInfo.FORMAT_JPEG, width, height);
214 }
215
216 public void testScaleImageUpscaling() throws IOException
217 {
218 final String resourceName = "/opaque-png.png";
219 final BufferedImage image = ImageIO.read(getClass().getResourceAsStream(resourceName));
220 final int width = image.getWidth();
221 final int height = image.getHeight();
222 assertScaleImage(image, width * 3, height * 3);
223 assertScaleImage(image, width - 10, height + 100);
224 assertScaleImage(image, width + 100, height - 20);
225 }
226
227 public void testScaleImageWithInvalidParams() throws IOException
228 {
229 final String resourceName = "/opaque-png.png";
230 final BufferedImage image = ImageIO.read(getClass().getResourceAsStream(resourceName));
231 try
232 {
233 assertScaleImage(image, -30, -20);
234 fail(IllegalArgumentException.class.getName() + " expected");
235 }
236 catch (IllegalArgumentException ignore)
237 {
238
239 }
240 }
241
242 private void assertScaleImage(final BufferedImage image, int aWidth, int aHeight)
243 {
244 final BufferedImage thumbnail = new Thumber().scaleImage(image, new Thumber.WidthHeightHelper(aWidth,
245 aHeight));
246 assertEquals(aWidth, thumbnail.getWidth());
247 assertEquals(aHeight, thumbnail.getHeight());
248 assertEquals(image.getTransparency(), thumbnail.getTransparency());
249 }
250
251 private void testRetrieveOrCreateThumbnail(Thumber thumber, String imageResourceName, int expectedTransparency, int expectedFormat) throws IOException
252 {
253 final Thumbnail thumbnail = thumber.retrieveOrCreateThumbNail(
254 getClass().getResourceAsStream(imageResourceName), TEST_FILE_NAME,
255 tempFile, MAX_WIDTH, MAX_HEIGHT, 1);
256
257 assertNotNull(thumbnail);
258 final BufferedImage image = ImageIO.read(getClass().getResourceAsStream(imageResourceName));
259
260 assertThumbnail(thumbnail, expectedTransparency, expectedFormat,
261 MAX_WIDTH, MAX_WIDTH * image.getHeight() / image.getWidth());
262 }
263
264 private void testRetrieveOrCreateThumbnailAsStream(Thumber thumber, String imageResourceName, int expectedTransparency, int expectedFormat) throws IOException
265 {
266 final Thumbnail thumbnail = thumber.retrieveOrCreateThumbNail(
267 getClass().getResourceAsStream(imageResourceName), TEST_FILE_NAME,
268 tempFile, MAX_WIDTH, MAX_HEIGHT, 1, Predicates.<Dimensions>alwaysFalse());
269
270 assertNotNull(thumbnail);
271 final BufferedImage image = ImageIO.read(getClass().getResourceAsStream(imageResourceName));
272
273 assertThumbnail(thumbnail, expectedTransparency, expectedFormat,
274 MAX_WIDTH, MAX_WIDTH * image.getHeight() / image.getWidth());
275 }
276
277 private void assertThumbnail(final Thumbnail thumbnail, final int expectedTransparency, final int expectedFormat,
278 int expectedWidth, int expectedHeight) throws IOException
279 {
280 assertEquals(expectedWidth, thumbnail.getWidth());
281 assertEquals(expectedHeight, thumbnail.getHeight());
282 assertEquals(TEST_FILE_NAME, thumbnail.getFilename());
283
284 final BufferedImage thumbnailImage = ImageIO.read(tempFile);
285 assertEquals(expectedWidth, thumbnailImage.getWidth());
286 assertEquals(expectedHeight, thumbnailImage.getHeight());
287 assertEquals(expectedTransparency, thumbnailImage.getTransparency());
288 assertImageType(tempFile, expectedFormat);
289 }
290
291
292 private void assertImageType(final File tempFile, int format) throws IOException
293 {
294 final ImageInfo imageInfo = new ImageInfo();
295 final FileInputStream fis = new FileInputStream(tempFile);
296 imageInfo.setInput(fis);
297 assertTrue(imageInfo.check());
298 assertEquals(format, imageInfo.getFormat());
299 fis.close();
300 }
301 }