();
153 |
154 | sourceImageFileList.add(getImageFile("gif", "test-image-transparent.gif"));
155 | sourceImageFileList.add(getImageFile("png", "test-image-transparent.png"));
156 |
157 | for (File sourceImageFile : sourceImageFileList) {
158 |
159 | BufferedImage bufferedImage = createBufferedImage(sourceImageFile);
160 | assertValidBufferedImage(bufferedImage);
161 | assertTrue("Expecting transparency", bufferedImage.getColorModel().hasAlpha());
162 | assertTrue("Expecting non-RGB color model", bufferedImage.getType() == BufferedImage.TYPE_4BYTE_ABGR || bufferedImage.getType() == BufferedImage.TYPE_BYTE_INDEXED);
163 |
164 | int width = bufferedImage.getWidth();
165 | int height = bufferedImage.getHeight();
166 | final int imageType = BufferedImage.TYPE_INT_RGB;
167 | BufferedImage rgbBufferedImage = new BufferedImage(width, height, imageType);
168 | Graphics2D graphics = rgbBufferedImage.createGraphics();
169 | graphics.drawImage(bufferedImage, 0, 0, null);
170 | graphics.dispose();
171 | assertValidBufferedImage(rgbBufferedImage);
172 | assertFalse("Expecting no transparency", rgbBufferedImage.getColorModel().hasAlpha());
173 | assertEquals("Expecting RGB color model", BufferedImage.TYPE_INT_RGB, rgbBufferedImage.getType());
174 |
175 | File targetImageFile = createOutputFileName("testWriteTransparentImagesUsingRGBAsJpeg", sourceImageFile, formatName);
176 | writeBufferedImage(rgbBufferedImage, formatName, targetImageFile);
177 | }
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/code/jipsg/imageio/src/test/java/org/github/jipsg/imageio/ImageLoadImageIoTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package org.github.jipsg.imageio;
18 |
19 | import org.junit.Before;
20 | import org.junit.Ignore;
21 | import org.junit.Test;
22 |
23 | import javax.imageio.ImageIO;
24 | import java.awt.Dimension;
25 | import java.awt.image.BufferedImage;
26 | import java.io.File;
27 | import java.util.ArrayList;
28 | import java.util.HashSet;
29 | import java.util.List;
30 | import java.util.Set;
31 |
32 | import static org.junit.Assert.assertEquals;
33 |
34 | /**
35 | * Load various images.
36 | */
37 | public class ImageLoadImageIoTest extends BaseImageIoTest {
38 |
39 | @Before
40 | public void setup() {
41 | super.setup();
42 | super.setModuleName("imageio");
43 | }
44 |
45 | // ======================================================================
46 | // General
47 | // ======================================================================
48 |
49 | /**
50 | * List available image formats.
51 | *
52 | * see http://examples.javacodegeeks.com/desktop-java/jai/list-read-write-supported-image-formats/
53 | */
54 | @Test
55 | public void testListSupportedImageFormats() throws Exception {
56 |
57 | Set set = new HashSet();
58 |
59 | // Get list of all informal format names understood by the current set of registered readers
60 | String[] formatNames = ImageIO.getReaderFormatNames();
61 |
62 | for (String formatName : formatNames) {
63 | set.add(formatName.toLowerCase());
64 | }
65 | System.out.println("Supported read formats: " + set);
66 |
67 | set.clear();
68 |
69 | // Get list of all informal format names understood by the current set of registered writers
70 | formatNames = ImageIO.getWriterFormatNames();
71 |
72 | for (String formatName : formatNames) {
73 | set.add(formatName.toLowerCase());
74 | }
75 | System.out.println("Supported write formats: " + set);
76 |
77 | set.clear();
78 |
79 | // Get list of all MIME types understood by the current set of registered readers
80 | formatNames = ImageIO.getReaderMIMETypes();
81 |
82 | for (String formatName : formatNames) {
83 | set.add(formatName.toLowerCase());
84 | }
85 | System.out.println("Supported read MIME types: " + set);
86 |
87 | set.clear();
88 |
89 | // Get list of all MIME types understood by the current set of registered writers
90 | formatNames = ImageIO.getWriterMIMETypes();
91 |
92 | for (String formatName : formatNames) {
93 | set.add(formatName.toLowerCase());
94 | }
95 | System.out.println("Supported write MIME types: " + set);
96 | }
97 |
98 | // ======================================================================
99 | // Load various image formats
100 | // ======================================================================
101 |
102 | @Test
103 | public void testLoadVariousImageFormats() throws Exception {
104 |
105 | List sourceImageFileList = new ArrayList();
106 |
107 | sourceImageFileList.add(getImageFile("jpg", "marble.jpg"));
108 | sourceImageFileList.add(getImageFile("png", "marble.png"));
109 | // sourceImageFileList.add(getImageFile("tiff", "marble.tiff"));
110 | sourceImageFileList.add(getImageFile("gif", "marble.gif"));
111 | // sourceImageFileList.add(getImageFile("jp2", "marble.jp2"));
112 |
113 | for (File sourceImageFile : sourceImageFileList) {
114 | BufferedImage bufferedImage = createBufferedImage(sourceImageFile);
115 | assertValidBufferedImage(bufferedImage);
116 | }
117 | }
118 |
119 | // ======================================================================
120 | // JPEG
121 | // ======================================================================
122 |
123 | /**
124 | * Plain-vanilla JPEG
125 | */
126 | @Test
127 | public void testLoadJPEGImage() throws Exception {
128 | assertValidBufferedImage(createBufferedImage(getImageFile("jpg", "test-image-rgb-01.jpg")));
129 | }
130 |
131 | /**
132 | * CMYK color model is not supported and fails with "javax.imageio.IIOException: Unsupported Image Type"
133 | */
134 | @Ignore
135 | @Test
136 | public void testLoadCMYKImage() throws Exception {
137 | assertValidBufferedImage(createBufferedImage(getImageFile("jpg", "test-image-cmyk-uncompressed.jpg")));
138 | }
139 |
140 | // ======================================================================
141 | // TIFF
142 | // ======================================================================
143 |
144 | /**
145 | * Load a TIFF image with compression 2. Silently no buffered image
146 | * is loaded at call causing assertValidBufferedImage() to fail.
147 | */
148 | @Test
149 | @Ignore
150 | public void testLoadTiffGrayWithCompression2() throws Exception {
151 | assertValidBufferedImage(createBufferedImage(getImageFile("tiff", "test-single-gray-compression-type-2.tiff")));
152 | }
153 |
154 | /**
155 | * Load a TIFF image with compression 3. Silently no buffered image
156 | * is loaded at call causing assertValidBufferedImage() to fail.
157 | */
158 | @Test
159 | @Ignore
160 | public void testLoadTiffWithCompression3() throws Exception {
161 | assertValidBufferedImage(createBufferedImage(getImageFile("tiff", "test-single-gray-compression-type-3.tiff")));
162 | }
163 |
164 | /**
165 | * Load a TIFF image with compression 4. Silently no buffered image
166 | * is loaded at call causing assertValidBufferedImage() to fail.
167 | */
168 | @Test
169 | @Ignore
170 | public void testLoadTiffWithCompression4() throws Exception {
171 | assertValidBufferedImage(createBufferedImage(getImageFile("tiff", "test-single-gray-compression-type-4.tiff")));
172 | }
173 |
174 | /**
175 | * Load a TIFF image with compression 4. Silently no buffered image
176 | * is loaded at call causing assertValidBufferedImage() to fail.
177 | */
178 | @Test
179 | @Ignore
180 | public void testLoadTiffMultiPageGray() throws Exception {
181 | assertValidBufferedImage(createBufferedImage(getImageFile("tiff", "test-multi-gray-compression-type-4.tiff")));
182 | }
183 |
184 | /**
185 | * Load a TIFF image with compression LZW. Silently no buffered image
186 | * is loaded at call causing assertValidBufferedImage() to fail.
187 | */
188 | @Test
189 | @Ignore
190 | public void testLoadTiffSingleCmykCompressionLzw() throws Exception {
191 | assertValidBufferedImage(createBufferedImage(getImageFile("tiff", "test-single-cmyk-compression-lzw.tiff")));
192 | }
193 |
194 | // ======================================================================
195 | // Decompression Bombs
196 | // ======================================================================
197 |
198 | @Test
199 | public void testLoadLargeImage() throws Exception {
200 | BufferedImage bufferedImage = createBufferedImage(getImageFile("bombs", "picture-1G-19000x19000.png"));
201 | Dimension dimension = new Dimension(bufferedImage.getWidth(), bufferedImage.getHeight());
202 | assertEquals(19000, dimension.height);
203 | assertEquals(19000, dimension.width);
204 | }
205 | }
206 |
--------------------------------------------------------------------------------
/code/jipsg/imageio/src/test/java/org/github/jipsg/imageio/ImageResamplingImageIoTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package org.github.jipsg.imageio;
18 |
19 | import org.junit.Before;
20 | import org.junit.Test;
21 |
22 | import java.awt.image.BufferedImage;
23 | import java.io.File;
24 | import java.math.BigDecimal;
25 | import java.util.ArrayList;
26 | import java.util.List;
27 |
28 | /**
29 | * Load various images.
30 | */
31 | public class ImageResamplingImageIoTest extends BaseImageIoTest {
32 |
33 | private static final BigDecimal BD_1000 = new BigDecimal(1000);
34 | private static final BigDecimal CM_INCH_RATIO = new BigDecimal(0.0254);
35 |
36 | @Before
37 | public void setup() {
38 | super.setup();
39 | }
40 |
41 | /**
42 | * Load various image types and re-sample them to 640 x 480.
43 | */
44 | @Test
45 | public void testResamplingImagesAsJpeg() throws Exception {
46 |
47 | String formatName = "jpeg";
48 | List sourceImageFileList = new ArrayList();
49 |
50 | sourceImageFileList.add(getImageFile("jpg", "marble.jpg"));
51 | sourceImageFileList.add(getImageFile("png", "marble.png"));
52 | // not supported by Java ImageIO
53 | // sourceImageFileList.add(getImageFile("tiff", "marble.tiff"));
54 | sourceImageFileList.add(getImageFile("gif", "marble.gif"));
55 |
56 | for (File sourceImageFile : sourceImageFileList) {
57 | BufferedImage bufferedImage = createBufferedImage(sourceImageFile);
58 | assertValidBufferedImage(bufferedImage);
59 | BufferedImage resampledBufferdImage = resample(bufferedImage, 640, 640);
60 | assertValidBufferedImage(resampledBufferdImage);
61 | File targetImageFile = createOutputFileName("testResamplingImagesAsJpeg", sourceImageFile, formatName);
62 | writeBufferedImage(resampledBufferdImage, formatName, targetImageFile);
63 | }
64 | }
65 |
66 | @Test
67 | public void testWriteImageWithQualityAndDpi() throws Exception {
68 |
69 | File targetImageFile;
70 | String formatName = "jpeg";
71 |
72 | File sourceImageFile = getImageFile("jpg", "marble.jpg");
73 | BufferedImage bufferedImage = createBufferedImage(sourceImageFile);
74 | assertValidBufferedImage(bufferedImage);
75 | BufferedImage resampledBufferdImage = resample(bufferedImage, 640, 640);
76 | assertValidBufferedImage(resampledBufferdImage);
77 |
78 | // write as JPEG
79 | targetImageFile = createOutputFileName("testWriteImageWithQualityAndDpi", sourceImageFile, "jpg");
80 | writeBufferedImage(resampledBufferdImage, 0.10f, 3145, formatName, targetImageFile);
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/code/jipsg/jai/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | 4.0.0
6 | org.github.jipsg
7 | jipsg-jai
8 | 0.0.1-SNAPSHOT
9 | jipsg-jai
10 | 2014
11 | Java Image Processing Survival Guide JAI
12 |
13 |
14 |
15 | com.sun.media
16 | jai_core
17 | 1.1.3
18 |
19 |
20 | com.sun.media
21 | jai_codec
22 | 1.1.2_01
23 |
24 |
25 | com.sun.media
26 | jai_imageio
27 | 1.1
28 |
29 |
30 | org.github.jipsg
31 | jipsg-common
32 | ${project.version}
33 | test
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/code/jipsg/jai/src/test/java/org/github/jipsg/jai/AbstractJaiTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package org.github.jipsg.jai;
18 |
19 | import com.sun.imageio.plugins.jpeg.JPEGImageWriter;
20 | import org.github.jipsg.common.AbstractImageTest;
21 | import org.github.jipsg.common.image.BufferedImageUtils;
22 | import org.w3c.dom.Element;
23 |
24 | import javax.imageio.IIOImage;
25 | import javax.imageio.ImageIO;
26 | import javax.imageio.ImageTypeSpecifier;
27 | import javax.imageio.ImageWriteParam;
28 | import javax.imageio.metadata.IIOMetadata;
29 | import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
30 | import javax.imageio.stream.ImageOutputStream;
31 | import java.awt.Dimension;
32 | import java.awt.geom.AffineTransform;
33 | import java.awt.image.AffineTransformOp;
34 | import java.awt.image.BufferedImage;
35 | import java.io.File;
36 | import java.io.FileOutputStream;
37 |
38 | /**
39 | * Base class for testing Java Advanced Imaging.
40 | */
41 | public class AbstractJaiTest extends AbstractImageTest {
42 |
43 | @Override
44 | public void setup() {
45 | super.setModuleName("jai");
46 | super.setup();
47 | }
48 |
49 | @Override
50 | public BufferedImage createBufferedImage(File file) throws Exception {
51 | return ImageIO.read(file);
52 | }
53 |
54 | @Override
55 | public void writeBufferedImage(BufferedImage bufferedImage, String formatName, File file) throws Exception {
56 | ImageIO.write(bufferedImage, formatName, file);
57 | }
58 |
59 | @Override
60 | public void writeBufferedImage(BufferedImage bufferedImage, float quality, int dpi, String formatName, File targetFile) throws Exception {
61 |
62 | if (formatName.equalsIgnoreCase("jpg") || formatName.equalsIgnoreCase("jpeg")) {
63 | JPEGImageWriter imageWriter = (JPEGImageWriter) ImageIO.getImageWritersBySuffix(formatName).next();
64 | ImageWriteParam writeParam = imageWriter.getDefaultWriteParam();
65 | ImageTypeSpecifier typeSpecifier = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB);
66 | IIOMetadata metadata = imageWriter.getDefaultImageMetadata(typeSpecifier, writeParam);
67 |
68 | if (formatName.equalsIgnoreCase("jpg") || formatName.equalsIgnoreCase("jpeg")) {
69 |
70 | Element tree = (Element) metadata.getAsTree("javax_imageio_jpeg_image_1.0");
71 | Element jfif = (Element) tree.getElementsByTagName("app0JFIF").item(0);
72 | jfif.setAttribute("Xdensity", Integer.toString(dpi));
73 | jfif.setAttribute("Ydensity", Integer.toString(dpi));
74 | jfif.setAttribute("resUnits", "1");
75 | metadata.setFromTree("javax_imageio_jpeg_image_1.0", tree);
76 | }
77 |
78 | if (quality >= 0 && quality <= 1f) {
79 |
80 | JPEGImageWriteParam jpegParams = (JPEGImageWriteParam) imageWriter.getDefaultWriteParam();
81 | jpegParams.setCompressionMode(JPEGImageWriteParam.MODE_EXPLICIT);
82 | jpegParams.setCompressionQuality(quality);
83 |
84 | }
85 |
86 | FileOutputStream os = new FileOutputStream(targetFile);
87 | final ImageOutputStream stream = ImageIO.createImageOutputStream(os);
88 |
89 | try {
90 | imageWriter.setOutput(stream);
91 | imageWriter.write(metadata, new IIOImage(bufferedImage, null, metadata), writeParam);
92 | } finally {
93 | stream.close();
94 | }
95 | } else {
96 | writeBufferedImage(bufferedImage, formatName, targetFile);
97 | }
98 | }
99 |
100 | /**
101 | * Some quick and dirty image scaling - please note that for best performance
102 | * and quality you should use image rescaling libraries.
103 | */
104 | @Override
105 | public BufferedImage resample(BufferedImage bufferedImage, int width, int height) {
106 |
107 | Dimension imageDimension = new Dimension(bufferedImage.getWidth(), bufferedImage.getHeight());
108 | Dimension boundaryDimension = new Dimension(width, height);
109 | Dimension scaledDimension = BufferedImageUtils.getScaledDimension(imageDimension, boundaryDimension);
110 |
111 | double scaleX = scaledDimension.getWidth() / bufferedImage.getWidth();
112 | double scaleY = scaledDimension.getHeight() / bufferedImage.getHeight();
113 |
114 | AffineTransform scaleTransform = AffineTransform.getScaleInstance(scaleX, scaleY);
115 | AffineTransformOp biLinearScaleOp = new AffineTransformOp(scaleTransform, AffineTransformOp.TYPE_BILINEAR);
116 |
117 | return biLinearScaleOp.filter(
118 | bufferedImage,
119 | new BufferedImage(scaledDimension.width, scaledDimension.height, bufferedImage.getType()));
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/code/jipsg/jai/src/test/java/org/github/jipsg/jai/ImageConversionJaiTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package org.github.jipsg.jai;
18 |
19 | import org.junit.Before;
20 | import org.junit.Ignore;
21 | import org.junit.Test;
22 |
23 | import java.awt.Graphics2D;
24 | import java.awt.image.BufferedImage;
25 | import java.io.File;
26 | import java.util.ArrayList;
27 | import java.util.List;
28 |
29 | import static org.junit.Assert.assertEquals;
30 | import static org.junit.Assert.assertFalse;
31 | import static org.junit.Assert.assertTrue;
32 |
33 | /**
34 | * Load various images.
35 | */
36 | public class ImageConversionJaiTest extends AbstractJaiTest {
37 |
38 | @Before
39 | public void setup() {
40 | super.setup();
41 | super.setModuleName("jai");
42 | }
43 |
44 | // ======================================================================
45 | // Image format conversion
46 | // ======================================================================
47 |
48 | @Test
49 | public void testWriteImageFormatsAsJpeg() throws Exception {
50 |
51 | String formatName = "jpeg";
52 | List sourceImageFileList = new ArrayList();
53 |
54 | sourceImageFileList.add(getImageFile("bmp", "marble.bmp"));
55 | sourceImageFileList.add(getImageFile("gif", "marble.gif"));
56 | sourceImageFileList.add(getImageFile("jp2", "marble.jp2"));
57 | sourceImageFileList.add(getImageFile("jpg", "marble.jpg"));
58 | sourceImageFileList.add(getImageFile("png", "marble.png"));
59 | sourceImageFileList.add(getImageFile("tiff", "marble.tiff"));
60 |
61 | for (File sourceImageFile : sourceImageFileList) {
62 | BufferedImage bufferedImage = createBufferedImage(sourceImageFile);
63 | assertValidBufferedImage(bufferedImage);
64 | File targetImageFile = createOutputFileName("testWriteImageFormatsAsJpeg", sourceImageFile, formatName);
65 | writeBufferedImage(bufferedImage, formatName, targetImageFile);
66 | }
67 | }
68 |
69 | @Test
70 | public void testWriteImageFormatsAsPng() throws Exception {
71 |
72 | String formatName = "png";
73 | List sourceImageFileList = new ArrayList();
74 |
75 | sourceImageFileList.add(getImageFile("bmp", "marble.bmp"));
76 | sourceImageFileList.add(getImageFile("gif", "house-photo.gif"));
77 | sourceImageFileList.add(getImageFile("gif", "marble.gif"));
78 | sourceImageFileList.add(getImageFile("jp2", "marble.jp2"));
79 | sourceImageFileList.add(getImageFile("jpg", "marble.jpg"));
80 | sourceImageFileList.add(getImageFile("png", "marble.png"));
81 | sourceImageFileList.add(getImageFile("tiff", "marble.tiff"));
82 |
83 | for (File sourceImageFile : sourceImageFileList) {
84 | BufferedImage bufferedImage = createBufferedImage(sourceImageFile);
85 | assertValidBufferedImage(bufferedImage);
86 | File targetImageFile = createOutputFileName("testWriteImageFormatsAsPng", sourceImageFile, formatName);
87 | writeBufferedImage(bufferedImage, formatName, targetImageFile);
88 | }
89 | }
90 |
91 | // ======================================================================
92 | // JPEG CMYK Images
93 | // ======================================================================
94 |
95 | /**
96 | * Process the JPEGs with CMYK color space and store them as JPEG again.
97 | */
98 | @Test
99 | @Ignore // javax.imageio.IIOException: Unsupported Image Type
100 | public void testProcessCMYKImages() throws Exception {
101 |
102 | String formatName = "jpeg";
103 | List sourceImageFileList = new ArrayList();
104 |
105 | sourceImageFileList.add(getImageFile("jpg", "test-image-cmyk-lzw.jpg"));
106 | sourceImageFileList.add(getImageFile("jpg", "test-image-cmyk-uncompressed.jpg"));
107 |
108 | for (File sourceImageFile : sourceImageFileList) {
109 | BufferedImage bufferedImage = createBufferedImage(sourceImageFile);
110 | assertValidBufferedImage(bufferedImage);
111 | File targetImageFile = createOutputFileName("testProcessCMYKImages", sourceImageFile, formatName);
112 | writeBufferedImage(resample(bufferedImage, 320, 320), formatName, targetImageFile);
113 | }
114 | }
115 |
116 | // ======================================================================
117 | // Transparent Images
118 | // ======================================================================
119 |
120 | /**
121 | * Convert images having a transparency layer (alpha-channel) to JPG. Without
122 | * further handling the alpha-channel will be rendered black or as a red tint.
123 | */
124 | @Test
125 | public void testWriteTransparentImagesAsJpeg() throws Exception {
126 |
127 | String formatName = "jpeg";
128 | List sourceImageFileList = new ArrayList();
129 |
130 | sourceImageFileList.add(getImageFile("gif", "test-image-transparent.gif"));
131 | sourceImageFileList.add(getImageFile("png", "test-image-transparent.png"));
132 |
133 | for (File sourceImageFile : sourceImageFileList) {
134 |
135 | BufferedImage bufferedImage = createBufferedImage(sourceImageFile);
136 | assertValidBufferedImage(bufferedImage);
137 | assertTrue("Expecting transparency", bufferedImage.getColorModel().hasAlpha());
138 | assertTrue("Expecting non-RGB color model", bufferedImage.getType() == BufferedImage.TYPE_4BYTE_ABGR || bufferedImage.getType() == BufferedImage.TYPE_BYTE_INDEXED);
139 |
140 | File targetImageFile = createOutputFileName("testWriteTransparentImagesAsJpeg", sourceImageFile, formatName);
141 | writeBufferedImage(bufferedImage, formatName, targetImageFile);
142 | }
143 | }
144 |
145 | /**
146 | * Convert images having a transparency layer (alpha-channel) to JPG. Remove
147 | * the alpha-channel (ARGB) by painting the image into an RGB image thereby
148 | * removing the fourth channel and transparency.
149 | */
150 | @Test
151 | public void testWriteTransparentImagesUsingRGBAsJpeg() throws Exception {
152 |
153 | String formatName = "jpeg";
154 | List sourceImageFileList = new ArrayList();
155 |
156 | sourceImageFileList.add(getImageFile("gif", "test-image-transparent.gif"));
157 | sourceImageFileList.add(getImageFile("png", "test-image-transparent.png"));
158 |
159 | for (File sourceImageFile : sourceImageFileList) {
160 |
161 | BufferedImage bufferedImage = createBufferedImage(sourceImageFile);
162 | assertValidBufferedImage(bufferedImage);
163 | assertTrue("Expecting transparency", bufferedImage.getColorModel().hasAlpha());
164 | assertTrue("Expecting non-RGB color model", bufferedImage.getType() == BufferedImage.TYPE_4BYTE_ABGR || bufferedImage.getType() == BufferedImage.TYPE_BYTE_INDEXED);
165 |
166 | BufferedImage rgbBufferedImage = new BufferedImage(bufferedImage.getWidth(), bufferedImage.getHeight(), BufferedImage.TYPE_INT_RGB);
167 | Graphics2D graphics = rgbBufferedImage.createGraphics();
168 | graphics.drawImage(bufferedImage, 0, 0, null);
169 | graphics.dispose();
170 | assertValidBufferedImage(rgbBufferedImage);
171 | assertFalse("Expecting no transparency", rgbBufferedImage.getColorModel().hasAlpha());
172 | assertEquals("Expecting RGB color model", BufferedImage.TYPE_INT_RGB, rgbBufferedImage.getType());
173 |
174 | File targetImageFile = createOutputFileName("testWriteTransparentImagesUsingRGBAsJpeg", sourceImageFile, formatName);
175 | writeBufferedImage(rgbBufferedImage, formatName, targetImageFile);
176 | }
177 | }
178 | }
179 |
--------------------------------------------------------------------------------
/code/jipsg/jai/src/test/java/org/github/jipsg/jai/ImageLoadJaiTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package org.github.jipsg.jai;
18 |
19 | import org.junit.Before;
20 | import org.junit.Ignore;
21 | import org.junit.Test;
22 |
23 | import javax.imageio.ImageIO;
24 | import javax.imageio.ImageReader;
25 | import javax.imageio.stream.ImageInputStream;
26 | import java.awt.image.BufferedImage;
27 | import java.io.File;
28 | import java.util.ArrayList;
29 | import java.util.HashSet;
30 | import java.util.Iterator;
31 | import java.util.List;
32 | import java.util.Set;
33 |
34 | import static org.junit.Assert.assertEquals;
35 |
36 |
37 | /**
38 | * Load various images.
39 | */
40 | public class ImageLoadJaiTest extends AbstractJaiTest {
41 | @Before
42 | public void setup() {
43 | super.setup();
44 | this.setModuleName("jai");
45 | }
46 |
47 | // ======================================================================
48 | // General
49 | // ======================================================================
50 |
51 | /**
52 | * List available image formats.
53 | * see http://examples.javacodegeeks.com/desktop-java/imageio/list-read-write-supported-image-formats/
54 | */
55 | @Test
56 | public void testListSupportedImageFormats() throws Exception {
57 |
58 | Set set = new HashSet();
59 |
60 | // Get list of all informal format names understood by the current set of registered readers
61 | String[] formatNames = ImageIO.getReaderFormatNames();
62 |
63 | for (int i = 0; i < formatNames.length; i++) {
64 | set.add(formatNames[i].toLowerCase());
65 | }
66 | System.out.println("Supported read formats: " + set);
67 |
68 | set.clear();
69 |
70 | // Get list of all informal format names understood by the current set of registered writers
71 | formatNames = ImageIO.getWriterFormatNames();
72 |
73 | for (int i = 0; i < formatNames.length; i++) {
74 | set.add(formatNames[i].toLowerCase());
75 | }
76 | System.out.println("Supported write formats: " + set);
77 |
78 | set.clear();
79 |
80 | // Get list of all MIME types understood by the current set of registered readers
81 | formatNames = ImageIO.getReaderMIMETypes();
82 |
83 | for (int i = 0; i < formatNames.length; i++) {
84 | set.add(formatNames[i].toLowerCase());
85 | }
86 | System.out.println("Supported read MIME types: " + set);
87 |
88 | set.clear();
89 |
90 | // Get list of all MIME types understood by the current set of registered writers
91 | formatNames = ImageIO.getWriterMIMETypes();
92 |
93 | for (int i = 0; i < formatNames.length; i++) {
94 | set.add(formatNames[i].toLowerCase());
95 | }
96 | System.out.println("Supported write MIME types: " + set);
97 | }
98 |
99 | // ======================================================================
100 | // Load various image formats
101 | // ======================================================================
102 |
103 | @Test
104 | public void testLoadVariousImageFormats() throws Exception {
105 |
106 | List sourceImageFileList = new ArrayList();
107 |
108 | sourceImageFileList.add(getImageFile("jpg", "marble.jpg"));
109 | sourceImageFileList.add(getImageFile("png", "marble.png"));
110 | sourceImageFileList.add(getImageFile("tiff", "marble.tiff"));
111 | sourceImageFileList.add(getImageFile("gif", "marble.gif"));
112 | sourceImageFileList.add(getImageFile("jp2", "marble.jp2"));
113 |
114 | for (File sourceImageFile : sourceImageFileList) {
115 | BufferedImage bufferedImage = createBufferedImage(sourceImageFile);
116 | assertValidBufferedImage(bufferedImage);
117 | }
118 | }
119 |
120 | // ======================================================================
121 | // JPEG
122 | // ======================================================================
123 |
124 | /**
125 | * Plain-vanilla JPEG
126 | */
127 | @Test
128 | public void testLoadJPEGImage() throws Exception {
129 | assertValidBufferedImage(createBufferedImage(getImageFile("jpg", "test-image-rgb-01.jpg")));
130 | }
131 |
132 | /**
133 | * CMYK color model is not supported. The test fails with "javax.imageio.IIOException: Unsupported Image Type"
134 | */
135 | @Test
136 | @Ignore
137 | public void testLoadCMYKImage() throws Exception {
138 | assertValidBufferedImage(createBufferedImage(getImageFile("jpg", "test-image-cmyk-uncompressed.jpg")));
139 | }
140 |
141 | // ======================================================================
142 | // TIFF
143 | // ======================================================================
144 |
145 | /**
146 | * Load a TIFF image with compression 2.
147 | */
148 | @Test
149 | public void testLoadTiffGrayWithCompression2() throws Exception {
150 | assertValidBufferedImage(createBufferedImage(getImageFile("tiff", "test-single-gray-compression-type-2.tiff")));
151 | }
152 |
153 | /**
154 | * Load a TIFF image with compression 3.
155 | */
156 | @Test
157 | public void testLoadTiffWithCompression3() throws Exception {
158 | assertValidBufferedImage(createBufferedImage(getImageFile("tiff", "test-single-gray-compression-type-3.tiff")));
159 | }
160 |
161 | /**
162 | * Load a single-page TIFF image with compression 4.
163 | */
164 | @Test
165 | public void testLoadTiffWithCompression4() throws Exception {
166 | assertValidBufferedImage(createBufferedImage(getImageFile("tiff", "test-single-gray-compression-type-4.tiff")));
167 | }
168 |
169 | /**
170 | * Load a multi-page TIFF image with compression 4.
171 | */
172 | @Test
173 | public void testLoadTiffMultiPageGray() throws Exception {
174 | assertValidBufferedImage(createBufferedImage(getImageFile("tiff", "test-multi-gray-compression-type-4.tiff")));
175 | }
176 |
177 | /**
178 | * Load a TIFF image with compression LZW.
179 | */
180 | @Test
181 | public void testLoadTiffSingleCmykCompressionLzw() throws Exception {
182 | assertValidBufferedImage(createBufferedImage(getImageFile("tiff", "test-single-cmyk-compression-lzw.tiff")));
183 | }
184 |
185 | /**
186 | * Load a TIFF image with compression type 7 (JPEG).
187 | */
188 | @Test
189 | public void testLoadTiffMultiRgbCompression7() throws Exception {
190 | assertValidBufferedImage(createBufferedImage(getImageFile("tiff", "test-multi-rgb-compression-type-7.tiff")));
191 | }
192 |
193 | // ======================================================================
194 | // Multi-page TIFF extraction
195 | // ======================================================================
196 |
197 | /**
198 | * Load a multi-page TIFF image and split it into its individual pages.
199 | */
200 | @Test
201 | public void testExtractPagesFromMultiPageTiffCompression4() throws Exception {
202 |
203 | File sourceImageFile = getImageFile("tiff", "test-multi-gray-compression-type-4.tiff");
204 | ImageInputStream is = ImageIO.createImageInputStream(sourceImageFile);
205 |
206 | // get the first matching reader
207 | Iterator iterator = ImageIO.getImageReaders(is);
208 | ImageReader imageReader = iterator.next();
209 | imageReader.setInput(is);
210 |
211 | // split the multi-page TIFF
212 | int pages = imageReader.getNumImages(true);
213 | for (int i = 0; i < pages; i++) {
214 | BufferedImage bufferedImage = imageReader.read(i);
215 | assertValidBufferedImage(bufferedImage);
216 | }
217 |
218 | assertEquals("Expect to have 2 pages", 2, pages);
219 | }
220 |
221 | /**
222 | * Load a multi-page TIFF image and split it into its individual pages.
223 | */
224 | @Test
225 | public void testExtractPagesFromMultiPageTiffCompression7() throws Exception {
226 |
227 | File sourceImageFile = getImageFile("tiff", "test-multi-rgb-compression-type-7.tiff");
228 | ImageInputStream is = ImageIO.createImageInputStream(sourceImageFile);
229 |
230 | // get the first matching reader
231 | Iterator iterator = ImageIO.getImageReaders(is);
232 | ImageReader imageReader = iterator.next();
233 | imageReader.setInput(is);
234 |
235 | // split the multi-page TIFF
236 | int pages = imageReader.getNumImages(true);
237 | for (int i = 0; i < pages; i++) {
238 | BufferedImage bufferedImage = imageReader.read(i);
239 | assertValidBufferedImage(bufferedImage);
240 | }
241 |
242 | assertEquals("Expect to have 10 pages", 10, pages);
243 | }
244 |
245 | }
246 |
--------------------------------------------------------------------------------
/code/jipsg/jai/src/test/java/org/github/jipsg/jai/ImageResamplingJaiTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package org.github.jipsg.jai;
18 |
19 | import org.junit.Before;
20 | import org.junit.Test;
21 |
22 | import java.awt.image.BufferedImage;
23 | import java.io.File;
24 | import java.util.ArrayList;
25 | import java.util.List;
26 |
27 | /**
28 | * Load various images.
29 | */
30 | public class ImageResamplingJaiTest extends AbstractJaiTest {
31 |
32 | @Before
33 | public void setup() {
34 | super.setup();
35 | }
36 |
37 | /**
38 | * Load various image types and re-sample them to 640 x 480.
39 | */
40 | @Test
41 | public void testResamplingImagesAsJpeg() throws Exception {
42 |
43 | String formatName = "jpeg";
44 | List sourceImageFileList = new ArrayList();
45 |
46 | sourceImageFileList.add(getImageFile("jpg", "marble.jpg"));
47 | sourceImageFileList.add(getImageFile("png", "marble.png"));
48 | // JAI fails with java.lang.IllegalArgumentException: Unknown image type 0
49 | // sourceImageFileList.add(getImageFile("tiff", "marble.tiff"));
50 | sourceImageFileList.add(getImageFile("gif", "marble.gif"));
51 |
52 | for (File sourceImageFile : sourceImageFileList) {
53 | BufferedImage bufferedImage = createBufferedImage(sourceImageFile);
54 | assertValidBufferedImage(bufferedImage);
55 | BufferedImage resampledBufferedImage = resample(bufferedImage, 640, 480);
56 | assertValidBufferedImage(resampledBufferedImage);
57 | File targetImageFile = createOutputFileName("testResamplingImagesAsJpeg", sourceImageFile, formatName);
58 | writeBufferedImage(resampledBufferedImage, formatName, targetImageFile);
59 | }
60 | }
61 |
62 | @Test
63 | public void testWriteImageWithQualityAndDpi() throws Exception {
64 |
65 | File targetImageFile;
66 | String formatName = "jpeg";
67 |
68 | File sourceImageFile = getImageFile("jpg", "marble.jpg");
69 | BufferedImage bufferedImage = createBufferedImage(sourceImageFile);
70 | assertValidBufferedImage(bufferedImage);
71 | BufferedImage resampledBufferdImage = resample(bufferedImage, 640, 640);
72 | assertValidBufferedImage(resampledBufferdImage);
73 |
74 | // write as JPEG
75 | targetImageFile = createOutputFileName("testWriteImageWithQualityAndDpi", sourceImageFile, "jpg");
76 | writeBufferedImage(resampledBufferdImage, 0.10f, 123, formatName, targetImageFile);
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/code/jipsg/pdfbox/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | 4.0.0
6 | org.github.jipsg
7 | jipsg-pdfbox
8 | 0.0.1-SNAPSHOT
9 | jipsg-pdfbox
10 | 2016
11 | Java Image Processing Survival Guide PdfBox
12 |
13 |
14 |
15 | org.github.jipsg
16 | jipsg-common
17 | ${project.version}
18 | test
19 |
20 |
21 | org.github.jipsg
22 | jipsg-imageio
23 | ${project.version}
24 | test
25 |
26 |
27 | org.apache.pdfbox
28 | pdfbox
29 | 1.8.12
30 | test
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/code/jipsg/pdfbox/src/test/java/org/github/jipsg/pdfbox/PdfBoxPreviewTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package org.github.jipsg.pdfbox;
18 |
19 | import org.apache.pdfbox.pdmodel.PDDocument;
20 | import org.apache.pdfbox.pdmodel.PDPage;
21 | import org.apache.pdfbox.pdmodel.common.PDRectangle;
22 | import org.github.jipsg.imageio.BaseImageIoTest;
23 | import org.junit.Before;
24 | import org.junit.Test;
25 |
26 | import java.awt.image.BufferedImage;
27 | import java.io.File;
28 | import java.util.ArrayList;
29 | import java.util.List;
30 |
31 | import static java.awt.image.BufferedImage.TYPE_INT_RGB;
32 | import static org.junit.Assert.assertEquals;
33 | import static org.junit.Assert.assertFalse;
34 | import static org.junit.Assert.assertNotNull;
35 |
36 | /**
37 | * PDF manipulation code based on Apache PDFBox.
38 | */
39 | public class PdfBoxPreviewTest extends BaseImageIoTest {
40 |
41 | private static final int DPI_72 = 72;
42 | private static final int START_PAGE = 1;
43 | private static final int LAST_PAGE = 16;
44 |
45 | @Before
46 | @Override
47 | public void setup() {
48 | super.setup();
49 | setModuleName("pdfbox");
50 | }
51 |
52 | @Test
53 | public void shouldCreatePdfPreviewImages() throws Exception {
54 |
55 | final int imageType = TYPE_INT_RGB;
56 |
57 | // final PDDocument pdDocument = PDDocument.load("./../../pdf/test-large-scan.pdf");
58 | final PDDocument pdDocument = PDDocument.load("./../../pdf/erste-document-01.pdf");
59 |
60 | final List images = toImages(pdDocument, START_PAGE, LAST_PAGE, DPI_72, imageType);
61 |
62 | assertNotNull(images);
63 | assertFalse(images.isEmpty());
64 | assertEquals(images.get(0).getType(), imageType);
65 |
66 | for (int i = 0; i < images.size(); i++) {
67 | File targetImageFile = createOutputFileName("shouldCreatePdfPreviewImages", "page-" + i, "jpeg");
68 | writeBufferedImage(images.get(i), "jpeg", targetImageFile);
69 | }
70 | }
71 |
72 | @SuppressWarnings("unchecked")
73 | public List toImages(PDDocument pdDocument, int startPage, int endPage, int resolution, int imageType) throws Exception {
74 | final List result = new ArrayList();
75 | final List pages = pdDocument.getDocumentCatalog().getAllPages();
76 | final int pagesSize = pages.size();
77 |
78 | for (int i = startPage - 1; i < endPage && i < pagesSize; i++) {
79 | PDPage page = pages.get(i);
80 | PDRectangle cropBox = page.findCropBox();
81 | float width = cropBox.getWidth();
82 | float height = cropBox.getHeight();
83 | int currResolution = calculateResolution(resolution, width, height);
84 | BufferedImage image = page.convertToImage(imageType, currResolution);
85 |
86 | if (image != null) {
87 | result.add(image);
88 | }
89 | }
90 |
91 | return result;
92 | }
93 |
94 | /**
95 | * Calculate the resolution being used assuming that the DPI is used
96 | * for an A4 page.
97 | */
98 | protected int calculateResolution(int dpi, float cropBoxWidth, float cropBoxHeight) {
99 | int result;
100 |
101 | float maxPoints = Math.max(cropBoxWidth, cropBoxHeight);
102 | float pointForRequestedResolution = 29.7f * dpi / 2.54f;
103 | result = Math.round((pointForRequestedResolution * DPI_72 / maxPoints));
104 | return result;
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/code/jipsg/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | 4.0.0
6 | org.github.jipsg
7 | jipsg
8 | pom
9 | 0.0.1-SNAPSHOT
10 | jipsg
11 | 2014
12 | Java Image Processing Survival Guide JAI
13 |
14 |
15 | common
16 | imageio
17 | jai
18 | sanselan
19 | twelvemonkeys
20 | image-manipulation
21 | thumbnailator
22 | pdfbox
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/code/jipsg/readme.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sgoeschl/java-image-processing-survival-guide/3cde84bba0b8018d6fcf222f76d041b6b950baa7/code/jipsg/readme.md
--------------------------------------------------------------------------------
/code/jipsg/sanselan/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | 4.0.0
6 | org.github.jipsg
7 | jipsg-sanselan
8 | 0.0.1-SNAPSHOT
9 | jipsg-sanselan
10 | 2014
11 | Java Image Processing Survival Guide ImageIO
12 |
13 |
14 |
15 | org.github.jipsg
16 | jipsg-common
17 | ${project.version}
18 | test
19 |
20 |
21 | org.apache.commons
22 | commons-imaging
23 | 1.0-SNAPSHOT
24 | test
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/code/jipsg/sanselan/src/test/java/org/github/jipsg/sanselan/BaseSanselanTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package org.github.jipsg.sanselan;
18 |
19 | import org.apache.commons.imaging.ImageFormat;
20 | import org.apache.commons.imaging.ImageFormats;
21 | import org.apache.commons.imaging.Imaging;
22 | import org.apache.commons.imaging.ImagingConstants;
23 | import org.github.jipsg.common.AbstractImageTest;
24 | import org.github.jipsg.common.image.BufferedImageUtils;
25 |
26 | import java.awt.Dimension;
27 | import java.awt.geom.AffineTransform;
28 | import java.awt.image.AffineTransformOp;
29 | import java.awt.image.BufferedImage;
30 | import java.io.File;
31 | import java.util.HashMap;
32 | import java.util.Map;
33 |
34 | /**
35 | * Base class for testing Apache Sanselan.
36 | */
37 | public class BaseSanselanTest extends AbstractImageTest {
38 |
39 | @Override
40 | public void setup() {
41 | super.setModuleName("sanselan");
42 | super.setup();
43 | }
44 |
45 | @Override
46 | public BufferedImage createBufferedImage(File file) throws Exception {
47 | final Map params = new HashMap();
48 | // set optional parameters if you like
49 | params.put(ImagingConstants.BUFFERED_IMAGE_FACTORY,
50 | new ManagedImageBufferedImageFactory());
51 | // read image
52 | return Imaging.getBufferedImage(file, params);
53 | }
54 |
55 | @Override
56 | public void writeBufferedImage(final BufferedImage bufferedImage, final String formatName, final File file) throws Exception {
57 | final ImageFormat format = getImageFormat(formatName);
58 | final Map params = new HashMap();
59 | Imaging.writeImage(bufferedImage, file, format, params);
60 | }
61 |
62 | @Override
63 | public void writeBufferedImage(BufferedImage bufferedImage, float quality, int dpi, String formatName, File file) throws Exception {
64 | writeBufferedImage(bufferedImage, formatName, file);
65 | }
66 |
67 | /**
68 | * Some quick and dirty image scaling - please note that for best performance
69 | * and quality you should use image rescaling libraries.
70 | */
71 | @Override
72 | public BufferedImage resample(BufferedImage bufferedImage, int width, int height) {
73 |
74 | Dimension imageDimension = new Dimension(bufferedImage.getWidth(), bufferedImage.getHeight());
75 | Dimension boundaryDimension = new Dimension(width, height);
76 | Dimension scaledDimension = BufferedImageUtils.getScaledDimension(imageDimension, boundaryDimension);
77 |
78 | double scaleX = scaledDimension.getWidth() / bufferedImage.getWidth();
79 | double scaleY = scaledDimension.getHeight() / bufferedImage.getHeight();
80 |
81 | AffineTransform scaleTransform = AffineTransform.getScaleInstance(scaleX, scaleY);
82 | AffineTransformOp biLinearScaleOp = new AffineTransformOp(scaleTransform, AffineTransformOp.TYPE_BILINEAR);
83 |
84 | return biLinearScaleOp.filter(
85 | bufferedImage,
86 | new BufferedImage(scaledDimension.width, scaledDimension.height, bufferedImage.getType()));
87 | }
88 |
89 | private ImageFormat getImageFormat(String formatName) {
90 |
91 | if ("jpg".equalsIgnoreCase(formatName)) {
92 | return ImageFormats.JPEG;
93 | } else if ("jpeg".equalsIgnoreCase(formatName)) {
94 | return ImageFormats.JPEG;
95 | } else if ("png".equalsIgnoreCase(formatName)) {
96 | return ImageFormats.PNG;
97 | } else {
98 | throw new IllegalArgumentException("Don't know how to handle : " + formatName);
99 | }
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/code/jipsg/sanselan/src/test/java/org/github/jipsg/sanselan/ImageConversionSanselanTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package org.github.jipsg.sanselan;
18 |
19 | import org.junit.Before;
20 | import org.junit.Ignore;
21 | import org.junit.Test;
22 |
23 | import javax.imageio.ImageIO;
24 | import java.awt.Graphics2D;
25 | import java.awt.image.BufferedImage;
26 | import java.io.File;
27 | import java.util.ArrayList;
28 | import java.util.List;
29 |
30 | import static org.junit.Assert.assertEquals;
31 | import static org.junit.Assert.assertFalse;
32 | import static org.junit.Assert.assertTrue;
33 |
34 | /**
35 | * Load various images.
36 | */
37 | public class ImageConversionSanselanTest extends BaseSanselanTest {
38 |
39 | @Before
40 | public void setup() {
41 | super.setup();
42 | }
43 |
44 | // ======================================================================
45 | // Image format conversion
46 | // ======================================================================
47 |
48 | @Test
49 | public void testWriteImageFormatsAsJpeg() throws Exception {
50 |
51 | String formatName = "jpeg";
52 | List sourceImageFileList = new ArrayList();
53 |
54 | // fails with org.apache.commons.imaging.ImageReadException: Invalid marker found in entropy data
55 | // sourceImageFileList.add(getImageFile("jpg", "marble.jpg"));
56 |
57 | sourceImageFileList.add(getImageFile("png", "marble.png"));
58 | sourceImageFileList.add(getImageFile("tiff", "marble.tiff"));
59 | sourceImageFileList.add(getImageFile("gif", "marble.gif"));
60 | sourceImageFileList.add(getImageFile("gif", "house-photo.gif"));
61 |
62 | for (File sourceImageFile : sourceImageFileList) {
63 | BufferedImage bufferedImage = createBufferedImage(sourceImageFile);
64 | assertValidBufferedImage(bufferedImage);
65 | File targetImageFile = createOutputFileName("testWriteImageFormatsAsJpeg", sourceImageFile, formatName);
66 | ImageIO.write(bufferedImage, formatName, targetImageFile);
67 | }
68 | }
69 |
70 | @Test
71 | public void testWriteImageFormatsAsPng() throws Exception {
72 |
73 | String formatName = "png";
74 | List sourceImageFileList = new ArrayList();
75 |
76 | // sourceImageFileList.add(getImageFile("bmp", "marble.bmp"));
77 | sourceImageFileList.add(getImageFile("gif", "house-photo.gif"));
78 | sourceImageFileList.add(getImageFile("gif", "marble.gif"));
79 | // sourceImageFileList.add(getImageFile("jp2", "marble.jp2"));
80 | // fails with org.apache.commons.imaging.ImageReadException: Invalid marker found in entropy data
81 | // sourceImageFileList.add(getImageFile("jpg", "marble.jpg"));
82 | sourceImageFileList.add(getImageFile("png", "marble.png"));
83 | sourceImageFileList.add(getImageFile("tiff", "marble.tiff"));
84 |
85 | for (File sourceImageFile : sourceImageFileList) {
86 | BufferedImage bufferedImage = createBufferedImage(sourceImageFile);
87 | assertValidBufferedImage(bufferedImage);
88 | File targetImageFile = createOutputFileName("testWriteImageFormatsAsPng", sourceImageFile, formatName);
89 | ImageIO.write(bufferedImage, formatName, targetImageFile);
90 | }
91 | }
92 |
93 | // ======================================================================
94 | // JPEG CMYK Images
95 | // ======================================================================
96 |
97 | /**
98 | * Process the JPEGs with CMYK color space and store them as JPEG again.
99 | */
100 | @Test
101 | @Ignore // org.apache.commons.imaging.ImageReadException: 4 components are invalid or unsupported
102 | public void testProcessCMYKImages() throws Exception {
103 |
104 | String formatName = "jpeg";
105 | List sourceImageFileList = new ArrayList();
106 |
107 | sourceImageFileList.add(getImageFile("jpg", "test-image-cmyk-lzw.jpg"));
108 | sourceImageFileList.add(getImageFile("jpg", "test-image-cmyk-uncompressed.jpg"));
109 |
110 | for (File sourceImageFile : sourceImageFileList) {
111 | BufferedImage bufferedImage = createBufferedImage(sourceImageFile);
112 | assertValidBufferedImage(bufferedImage);
113 | File targetImageFile = createOutputFileName("testProcessCMYKImages", sourceImageFile, formatName);
114 | writeBufferedImage(resample(bufferedImage, 320, 320), formatName, targetImageFile);
115 | }
116 | }
117 |
118 | // ======================================================================
119 | // Transparent Images
120 | // ======================================================================
121 |
122 | /**
123 | * Convert images having a transparency layer (alpha-channel) to JPG. Without
124 | * further handling the alpha-channel will be rendered black.
125 | * The test fails with "org.apache.commons.imaging.ImageWriteException: This image format (Jpeg-Custom) cannot be written."
126 | */
127 | @Test(expected = org.apache.commons.imaging.ImageWriteException.class)
128 | public void testWriteTransparentImagesAsJpeg() throws Exception {
129 |
130 | String formatName = "jpeg";
131 | List sourceImageFileList = new ArrayList();
132 |
133 | sourceImageFileList.add(getImageFile("gif", "test-image-transparent.gif"));
134 | sourceImageFileList.add(getImageFile("png", "test-image-transparent.png"));
135 |
136 | for (File sourceImageFile : sourceImageFileList) {
137 |
138 | BufferedImage bufferedImage = createBufferedImage(sourceImageFile);
139 | assertValidBufferedImage(bufferedImage);
140 | assertTrue("Expecting transparency", bufferedImage.getColorModel().hasAlpha());
141 | assertTrue("Expecting ARGB color model", bufferedImage.getType() == BufferedImage.TYPE_INT_ARGB);
142 |
143 | File targetImageFile = createOutputFileName("testWriteTransparentImagesAsJpeg", sourceImageFile, formatName);
144 | writeBufferedImage(bufferedImage, formatName, targetImageFile);
145 | }
146 | }
147 |
148 | /**
149 | * Convert images having a transparency layer (alpha-channel) to JPG. Fill
150 | * the alpha-channel with Color.WHITE to have a useful image.
151 | * The test fails with "org.apache.commons.imaging.ImageWriteException: This image format (Jpeg-Custom) cannot be written."
152 | */
153 | @Test(expected = org.apache.commons.imaging.ImageWriteException.class)
154 | public void testWriteTransparentImagesWithAlphaChannelHandlingAsJpeg() throws Exception {
155 |
156 | String formatName = "jpeg";
157 | List sourceImageFileList = new ArrayList();
158 |
159 | sourceImageFileList.add(getImageFile("gif", "test-image-transparent.gif"));
160 | sourceImageFileList.add(getImageFile("png", "test-image-transparent.png"));
161 |
162 | for (File sourceImageFile : sourceImageFileList) {
163 |
164 | BufferedImage bufferedImage = createBufferedImage(sourceImageFile);
165 | assertValidBufferedImage(bufferedImage);
166 | assertTrue("Expecting transparency", bufferedImage.getColorModel().hasAlpha());
167 | assertTrue("Expecting ARGB color model", bufferedImage.getType() == BufferedImage.TYPE_INT_ARGB);
168 |
169 | BufferedImage rgbBufferedImage = new BufferedImage(bufferedImage.getWidth(), bufferedImage.getHeight(), BufferedImage.TYPE_INT_RGB);
170 | Graphics2D graphics = rgbBufferedImage.createGraphics();
171 | graphics.drawImage(bufferedImage, 0, 0, null);
172 | graphics.dispose();
173 | assertValidBufferedImage(rgbBufferedImage);
174 | assertFalse("Expecting no transparency", rgbBufferedImage.getColorModel().hasAlpha());
175 | assertEquals("Expecting RGB color model", BufferedImage.TYPE_INT_RGB, rgbBufferedImage.getType());
176 |
177 | File targetImageFile = createOutputFileName("testWriteTransparentImagesWithAlphaChannelHandlingAsJpeg", sourceImageFile, formatName);
178 | writeBufferedImage(bufferedImage, formatName, targetImageFile);
179 | }
180 | }
181 | }
182 |
--------------------------------------------------------------------------------
/code/jipsg/sanselan/src/test/java/org/github/jipsg/sanselan/ImageResamplingSanselanTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package org.github.jipsg.sanselan;
18 |
19 | import org.junit.Before;
20 | import org.junit.Ignore;
21 | import org.junit.Test;
22 |
23 | import java.awt.image.BufferedImage;
24 | import java.io.File;
25 | import java.util.ArrayList;
26 | import java.util.List;
27 |
28 | /**
29 | * Load various images.
30 | */
31 | public class ImageResamplingSanselanTest extends BaseSanselanTest {
32 |
33 | @Before
34 | public void setup() {
35 | super.setup();
36 | }
37 |
38 | /**
39 | * Fails for unknown reasons with standard Sanselan code
40 | */
41 | @Test
42 | @Ignore
43 | public void testResamplingImagesAsJpeg() throws Exception {
44 |
45 | String formatName = "jpeg";
46 | List sourceImageFileList = new ArrayList();
47 |
48 | // fails with org.apache.commons.imaging.ImageReadException: Invalid marker found in entropy data
49 | // sourceImageFileList.add(getImageFile("jpg", "marble.jpg"));
50 | sourceImageFileList.add(getImageFile("png", "marble.png"));
51 | sourceImageFileList.add(getImageFile("tiff", "marble.tiff"));
52 | sourceImageFileList.add(getImageFile("gif", "marble.gif"));
53 |
54 | for (File sourceImageFile : sourceImageFileList) {
55 | BufferedImage bufferedImage = createBufferedImage(sourceImageFile);
56 | assertValidBufferedImage(bufferedImage);
57 | BufferedImage resampledBufferdImage = resample(bufferedImage, 640, 480);
58 | assertValidBufferedImage(resampledBufferdImage);
59 | File targetImageFile = createOutputFileName("testResamplingImagesAsJpeg", sourceImageFile, formatName);
60 | writeBufferedImage(resampledBufferdImage, formatName, targetImageFile);
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/code/jipsg/sanselan/src/test/java/org/github/jipsg/sanselan/LoadImageSanselanTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package org.github.jipsg.sanselan;
18 |
19 | import org.apache.commons.imaging.Imaging;
20 | import org.junit.Before;
21 | import org.junit.Ignore;
22 | import org.junit.Test;
23 |
24 | import java.awt.image.BufferedImage;
25 | import java.io.File;
26 | import java.util.ArrayList;
27 | import java.util.List;
28 |
29 | import static org.junit.Assert.assertEquals;
30 |
31 | /**
32 | * Load various images using Apache Commons Imaging.
33 | */
34 | public class LoadImageSanselanTest extends BaseSanselanTest {
35 |
36 | @Before
37 | public void setup() {
38 | super.setup();
39 | }
40 |
41 | /**
42 | * List available image formats.
43 | *
44 | * see http://examples.javacodegeeks.com/desktop-java/imageio/list-read-write-supported-image-formats/
45 | */
46 | @Test
47 | public void testListSupportedImageFormats() throws Exception {
48 |
49 | }
50 |
51 | // ======================================================================
52 | // Load various image formats
53 | // ======================================================================
54 |
55 | @Test
56 | public void testLoadVariousImageFormats() throws Exception {
57 |
58 | List sourceImageFileList = new ArrayList();
59 |
60 | sourceImageFileList.add(getImageFile("gif", "marble.gif"));
61 | // fails with org.apache.commons.imaging.ImageReadException: Invalid marker found in entropy data
62 | // sourceImageFileList.add(getImageFile("jpg", "marble.jpg"));
63 | sourceImageFileList.add(getImageFile("png", "marble.png"));
64 | sourceImageFileList.add(getImageFile("tiff", "marble.tiff"));
65 |
66 | for (File sourceImageFile : sourceImageFileList) {
67 | BufferedImage bufferedImage = createBufferedImage(sourceImageFile);
68 | assertValidBufferedImage(bufferedImage);
69 | }
70 | }
71 |
72 | // ======================================================================
73 | // JPG
74 | // ======================================================================
75 |
76 | /**
77 | * Plain-vanilla JPEG
78 | */
79 | @Test
80 | @Ignore // org.apache.commons.imaging.ImageReadException: Invalid marker found in entropy data
81 | public void testLoadJPEGImage() throws Exception {
82 | assertValidBufferedImage(createBufferedImage(getImageFile("jpg", "test-image-rgb-01.jpg")));
83 | }
84 |
85 | /**
86 | * CMYK color model is supported.
87 | */
88 | @Test
89 | @Ignore // org.apache.commons.imaging.ImageReadException: 4 components are invalid or unsupported
90 | public void testLoadCMYKImage() throws Exception {
91 | assertValidBufferedImage(createBufferedImage(getImageFile("jpg", "test-image-cmyk-uncompressed.jpg")));
92 | }
93 |
94 | // ======================================================================
95 | // TIFF
96 | // ======================================================================
97 |
98 | /**
99 | * Load a TIFF image with compression 2.
100 | * Expecting a "javax.imageio.IIOException: Unsupported TIFF Compression value: 2" but got
101 | * an "ArrayIndexOutOfBoundsException"
102 | */
103 | @Test
104 | public void testLoadTiffGrayWithCompression2() throws Exception {
105 | assertValidBufferedImage(createBufferedImage(getImageFile("tiff", "test-single-gray-compression-type-2.tiff")));
106 | }
107 |
108 | /**
109 | * Load a TIFF image with compression 3.
110 | * Expecting a "javax.imageio.IIOException: Unsupported TIFF Compression value: 3"
111 | */
112 | @Test
113 | public void testLoadTiffWithCompression3() throws Exception {
114 | assertValidBufferedImage(createBufferedImage(getImageFile("tiff", "test-single-gray-compression-type-3.tiff")));
115 | }
116 |
117 | /**
118 | * Load a TIFF image with compression 4.
119 | * Expecting a "javax.imageio.IIOException: Unsupported TIFF Compression value: 4"
120 | */
121 | @Test
122 | public void testLoadTiffWithCompression4() throws Exception {
123 | assertValidBufferedImage(createBufferedImage(getImageFile("tiff", "test-single-gray-compression-type-4.tiff")));
124 | }
125 |
126 | /**
127 | * Load a TIFF image with compression 4.
128 | * Expecting a "javax.imageio.IIOException: Unsupported TIFF Compression value: 4"
129 | */
130 | @Test
131 | public void testLoadTiffMultiPageGray() throws Exception {
132 | assertValidBufferedImage(createBufferedImage(getImageFile("tiff", "test-multi-gray-compression-type-4.tiff")));
133 | }
134 |
135 | /**
136 | * Load a TIFF image with compression LZW.
137 | */
138 | @Test
139 | public void testLoadTiffSingleCmykCompressionLzw() throws Exception {
140 | assertValidBufferedImage(createBufferedImage(getImageFile("tiff", "test-single-cmyk-compression-lzw.tiff")));
141 | }
142 |
143 | /**
144 | * Load a TIFF image with compression type 7 (JPEG).
145 | */
146 | @Ignore
147 | public void testLoadTiffMultiRgbCompression7() throws Exception {
148 | assertValidBufferedImage(createBufferedImage(getImageFile("tiff", "test-multi-rgb-compression-type-7.tiff")));
149 | }
150 |
151 | // ======================================================================
152 | // Multi-page TIFF extraction
153 | // ======================================================================
154 |
155 | /**
156 | * Load a multi-page TIFF image and split it into its individual pages.
157 | */
158 | @Test
159 | public void testExtractPagesFromMultiPageTiff() throws Exception {
160 |
161 | File sourceImageFile = getImageFile("tiff", "test-multi-gray-compression-type-4.tiff");
162 |
163 | List bufferedImageList = Imaging.getAllBufferedImages(sourceImageFile);
164 |
165 | for (BufferedImage bufferedImage : bufferedImageList) {
166 | assertValidBufferedImage(bufferedImage);
167 | }
168 | assertEquals("Expect to have 2 pages", 2, bufferedImageList.size());
169 | }
170 | }
171 |
--------------------------------------------------------------------------------
/code/jipsg/sanselan/src/test/java/org/github/jipsg/sanselan/ManagedImageBufferedImageFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package org.github.jipsg.sanselan;
18 |
19 | import org.apache.commons.imaging.common.BufferedImageFactory;
20 |
21 | import java.awt.GraphicsConfiguration;
22 | import java.awt.GraphicsDevice;
23 | import java.awt.GraphicsEnvironment;
24 | import java.awt.Transparency;
25 | import java.awt.image.BufferedImage;
26 |
27 | /**
28 | * Created with IntelliJ IDEA.
29 | * User: sgoeschl
30 | * Date: 13/08/14
31 | * Time: 20:40
32 | * To change this template use File | Settings | File Templates.
33 | */
34 | public class ManagedImageBufferedImageFactory implements
35 | BufferedImageFactory {
36 |
37 | public BufferedImage getColorBufferedImage(final int width, final int height,
38 | final boolean hasAlpha) {
39 | final GraphicsEnvironment ge = GraphicsEnvironment
40 | .getLocalGraphicsEnvironment();
41 | final GraphicsDevice gd = ge.getDefaultScreenDevice();
42 | final GraphicsConfiguration gc = gd.getDefaultConfiguration();
43 | return gc.createCompatibleImage(width, height,
44 | Transparency.TRANSLUCENT);
45 | }
46 |
47 | public BufferedImage getGrayscaleBufferedImage(final int width, final int height,
48 | final boolean hasAlpha) {
49 | return getColorBufferedImage(width, height, hasAlpha);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/code/jipsg/thumbnailator/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | 4.0.0
6 | org.github.jipsg
7 | jipsg-thumbnailator
8 | 0.0.1-SNAPSHOT
9 | jipsg-thumbnailator
10 | 2014
11 | Java Image Processing Survival Guide Thumbnailator
12 |
13 |
14 |
15 | net.coobird
16 | thumbnailator
17 | 0.4.7
18 |
19 |
20 | org.github.jipsg
21 | jipsg-imageio
22 | ${project.version}
23 | test
24 |
25 |
26 | org.github.jipsg
27 | jipsg-common
28 | ${project.version}
29 | test
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/code/jipsg/thumbnailator/src/test/java/org/github/jipsg/thumbnailator/ImageScalingThumbnailatorTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package org.github.jipsg.thumbnailator;
18 |
19 | import junit.framework.TestCase;
20 | import net.coobird.thumbnailator.Thumbnails;
21 | import net.coobird.thumbnailator.resizers.configurations.Antialiasing;
22 | import org.github.jipsg.common.image.BufferedImageFactory;
23 | import org.junit.Test;
24 |
25 | import javax.imageio.ImageIO;
26 | import java.awt.image.BufferedImage;
27 | import java.io.File;
28 |
29 | /**
30 | * Image manipulation samples.
31 | */
32 | public class ImageScalingThumbnailatorTest extends TestCase {
33 |
34 | public File createOutputFileName(String directory, String fileName, String format) {
35 |
36 | File outputDir = new File(new File(new File(new File("./target"), "out"), "thumbnailator"), directory);
37 |
38 | if (!outputDir.exists()) {
39 | outputDir.mkdirs();
40 | }
41 |
42 | return new File(outputDir, fileName + "." + format);
43 | }
44 |
45 |
46 | public File createOutputFileName(String directory, File file, String format) {
47 | return createOutputFileName(directory, file.getName(), format);
48 | }
49 |
50 | // ======================================================================
51 | // Image Scaling
52 | // ======================================================================
53 |
54 | @Test
55 | public void testScaleImages() throws Exception {
56 |
57 | final int[] IMAGE_SCALE_DIMENSIONS = new int[] {575, 199, 80, 60};
58 | final float QUALITY = 0.8f;
59 |
60 | File sourceImageDir = new File("../../images/willhaben");
61 | File[] sourceImageFiles = sourceImageDir.listFiles();
62 |
63 | long currentTime = System.currentTimeMillis();
64 |
65 | for (File sourceImageFile : sourceImageFiles) {
66 |
67 | BufferedImage bufferedImage = ImageIO.read(sourceImageFile);
68 |
69 | for (int size : IMAGE_SCALE_DIMENSIONS) {
70 |
71 | BufferedImage scaledBufferedImage = Thumbnails.of(bufferedImage).
72 | width(size).
73 | height(size).
74 | keepAspectRatio(true).
75 | outputQuality(QUALITY).
76 | antialiasing(Antialiasing.ON).
77 | asBufferedImage();
78 |
79 | bufferedImage = scaledBufferedImage;
80 |
81 | BufferedImageFactory.writeBufferedImage(scaledBufferedImage, "jpeg", createOutputFileName("testScaleImages/" + size, sourceImageFile, "jpeg"));
82 | }
83 | }
84 |
85 | long duration = System.currentTimeMillis() - currentTime;
86 |
87 | System.out.println("Scaling source images to " + IMAGE_SCALE_DIMENSIONS.length + " previews took " + duration / sourceImageFiles.length + " ms");
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/code/jipsg/twelvemonkeys/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | 4.0.0
6 | org.github.jipsg
7 | jipsg-twelvemonkeys
8 | 0.0.1-SNAPSHOT
9 | jipsg-twelvemonkeys
10 | 2014
11 | Java Image Processing Survival Guide Twelvemonkeys
12 |
13 |
14 |
15 | com.twelvemonkeys.imageio
16 | imageio-tiff
17 | 3.2.1
18 |
19 |
20 | com.twelvemonkeys.imageio
21 | imageio-jpeg
22 | 3.2.1
23 |
24 |
25 | com.twelvemonkeys.imageio
26 | imageio-core
27 | 3.2.1
28 |
29 |
30 | com.twelvemonkeys.imageio
31 | imageio-metadata
32 | 3.2.1
33 |
34 |
35 | com.twelvemonkeys.common
36 | common-image
37 | 3.2.1
38 |
39 |
40 | com.twelvemonkeys.common
41 | common-io
42 | 3.2.1
43 |
44 |
45 | com.twelvemonkeys.common
46 | common-lang
47 | 3.2.1
48 |
49 |
50 | org.github.jipsg
51 | jipsg-common
52 | ${project.version}
53 | test
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/code/jipsg/twelvemonkeys/src/test/java/org/github/jipsg/twelvemonkeys/BaseTwelveMonkeysTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package org.github.jipsg.twelvemonkeys;
18 |
19 | import com.twelvemonkeys.image.ResampleOp;
20 | import org.github.jipsg.common.AbstractImageTest;
21 | import org.github.jipsg.common.image.BufferedImageUtils;
22 |
23 | import javax.imageio.ImageIO;
24 | import java.awt.Dimension;
25 | import java.awt.image.BufferedImage;
26 | import java.io.File;
27 |
28 | /**
29 | * Base class for testing TwelveMonkey library.
30 | */
31 | public class BaseTwelveMonkeysTest extends AbstractImageTest {
32 |
33 | @Override
34 | public void setup() {
35 | super.setModuleName("twelvemonkeys");
36 | super.setup();
37 | }
38 |
39 | @Override
40 | public BufferedImage createBufferedImage(File file) throws Exception {
41 | return ImageIO.read(file);
42 | }
43 |
44 | @Override
45 | public void writeBufferedImage(BufferedImage bufferedImage, String formatName, File file) throws Exception {
46 | System.out.println("Saving " + file.getPath());
47 | ImageIO.write(bufferedImage, formatName, file);
48 | }
49 |
50 | @Override
51 | public void writeBufferedImage(BufferedImage bufferedImage, float quality, int dpi, String formatName, File file) throws Exception {
52 | throw new UnsupportedOperationException();
53 | }
54 |
55 | @Override
56 | public BufferedImage resample(BufferedImage bufferedImage, int width, int height) {
57 | Dimension imageDimension = new Dimension(bufferedImage.getWidth(), bufferedImage.getHeight());
58 | Dimension boundaryDimension = new Dimension(width, height);
59 | Dimension scaledDimension = BufferedImageUtils.getScaledDimension(imageDimension, boundaryDimension);
60 | ResampleOp resampleOp = new ResampleOp(scaledDimension.width, scaledDimension.height);
61 | return resampleOp.filter(bufferedImage, null);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/code/jipsg/twelvemonkeys/src/test/java/org/github/jipsg/twelvemonkeys/ImageConversionTwelveMonkeysTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package org.github.jipsg.twelvemonkeys;
18 |
19 | import org.junit.Before;
20 | import org.junit.Test;
21 |
22 | import java.awt.Graphics2D;
23 | import java.awt.image.BufferedImage;
24 | import java.io.File;
25 | import java.util.ArrayList;
26 | import java.util.List;
27 |
28 | import static org.junit.Assert.assertEquals;
29 | import static org.junit.Assert.assertFalse;
30 | import static org.junit.Assert.assertTrue;
31 |
32 | /**
33 | * Load various images.
34 | */
35 | public class ImageConversionTwelveMonkeysTest extends BaseTwelveMonkeysTest {
36 |
37 | @Before
38 | public void setup() {
39 | super.setup();
40 | }
41 |
42 | // ======================================================================
43 | // Image format conversion
44 | // ======================================================================
45 |
46 | @Test
47 | public void testImageWriteAsJpeg() throws Exception {
48 |
49 | String formatName = "jpeg";
50 | List sourceImageFileList = new ArrayList();
51 |
52 | // sourceImageFileList.add(getImageFile("bmp", "marble.bmp"));
53 | sourceImageFileList.add(getImageFile("gif", "marble.gif"));
54 | // sourceImageFileList.add(getImageFile("jp2", "marble.jp2"));
55 | sourceImageFileList.add(getImageFile("jpg", "marble.jpg"));
56 | sourceImageFileList.add(getImageFile("png", "marble.png"));
57 | sourceImageFileList.add(getImageFile("tiff", "marble.tiff"));
58 |
59 | for (File sourceImageFile : sourceImageFileList) {
60 | BufferedImage bufferedImage = createBufferedImage(sourceImageFile);
61 | assertValidBufferedImage(bufferedImage);
62 | File targetImageFile = createOutputFileName("testImageWriteAsJpeg", sourceImageFile, formatName);
63 | writeBufferedImage(bufferedImage, formatName, targetImageFile);
64 | }
65 | }
66 |
67 | @Test
68 | public void testImageWriteAsPng() throws Exception {
69 |
70 | String formatName = "png";
71 | List sourceImageFileList = new ArrayList();
72 |
73 | // sourceImageFileList.add(getImageFile("bmp", "marble.bmp"));
74 | sourceImageFileList.add(getImageFile("gif", "marble.gif"));
75 | // sourceImageFileList.add(getImageFile("jp2", "marble.jp2"));
76 | sourceImageFileList.add(getImageFile("jpg", "marble.jpg"));
77 | sourceImageFileList.add(getImageFile("png", "marble.png"));
78 | sourceImageFileList.add(getImageFile("tiff", "marble.tiff"));
79 |
80 | for (File sourceImageFile : sourceImageFileList) {
81 | BufferedImage bufferedImage = createBufferedImage(sourceImageFile);
82 | assertValidBufferedImage(bufferedImage);
83 | File targetImageFile = createOutputFileName("testImageWriteAsPng", sourceImageFile, formatName);
84 | writeBufferedImage(bufferedImage, formatName, targetImageFile);
85 | }
86 | }
87 |
88 | // ======================================================================
89 | // JPEG CMYK Images
90 | // ======================================================================
91 |
92 | /**
93 | * Process the JPEGs with CMYK color space and store them as JPEG again.
94 | */
95 | @Test
96 | public void testProcessCMYKImages() throws Exception {
97 |
98 | String formatName = "jpeg";
99 | List sourceImageFileList = new ArrayList();
100 |
101 | sourceImageFileList.add(getImageFile("jpg", "test-image-cmyk-lzw.jpg"));
102 | sourceImageFileList.add(getImageFile("jpg", "test-image-cmyk-uncompressed.jpg"));
103 |
104 | for (File sourceImageFile : sourceImageFileList) {
105 | BufferedImage bufferedImage = createBufferedImage(sourceImageFile);
106 | assertValidBufferedImage(bufferedImage);
107 | File targetImageFile = createOutputFileName("testProcessCMYKImages", sourceImageFile, formatName);
108 | writeBufferedImage(resample(bufferedImage, 320, 320), formatName, targetImageFile);
109 | }
110 | }
111 |
112 | // ======================================================================
113 | // Transparent Images
114 | // ======================================================================
115 |
116 | /**
117 | * Convert images having a transparency layer (alpha-channel) to JPG. Without
118 | * further handling the alpha-channel will be rendered black or as a red tint.
119 | */
120 | @Test
121 | public void testWriteTransparentImagesAsJpeg() throws Exception {
122 |
123 | String formatName = "jpeg";
124 | List sourceImageFileList = new ArrayList();
125 |
126 | sourceImageFileList.add(getImageFile("gif", "test-image-transparent.gif"));
127 | sourceImageFileList.add(getImageFile("png", "test-image-transparent.png"));
128 |
129 | for (File sourceImageFile : sourceImageFileList) {
130 |
131 | BufferedImage bufferedImage = createBufferedImage(sourceImageFile);
132 | assertValidBufferedImage(bufferedImage);
133 | assertTrue("Expecting transparency", bufferedImage.getColorModel().hasAlpha());
134 | assertTrue("Expecting non-RGB color model", bufferedImage.getType() == BufferedImage.TYPE_4BYTE_ABGR || bufferedImage.getType() == BufferedImage.TYPE_BYTE_INDEXED);
135 |
136 | File targetImageFile = createOutputFileName("testWriteTransparentImagesAsJpeg", sourceImageFile, formatName);
137 | writeBufferedImage(bufferedImage, formatName, targetImageFile);
138 | }
139 | }
140 |
141 | /**
142 | * Convert images having a transparency layer (alpha-channel) to JPG. Remove
143 | * the alpha-channel (ARGB) by painting the image into an RGB image thereby
144 | * removing the fourth channel and transparency.
145 | */
146 | @Test
147 | public void testWriteTransparentImagesUsingRGBAsJpeg() throws Exception {
148 |
149 | String formatName = "jpeg";
150 | List sourceImageFileList = new ArrayList();
151 |
152 | sourceImageFileList.add(getImageFile("gif", "test-image-transparent.gif"));
153 | sourceImageFileList.add(getImageFile("png", "test-image-transparent.png"));
154 |
155 | for (File sourceImageFile : sourceImageFileList) {
156 |
157 | BufferedImage bufferedImage = createBufferedImage(sourceImageFile);
158 | assertValidBufferedImage(bufferedImage);
159 | assertTrue("Expecting transparency", bufferedImage.getColorModel().hasAlpha());
160 | assertTrue("Expecting non-RGB color model", bufferedImage.getType() == BufferedImage.TYPE_4BYTE_ABGR || bufferedImage.getType() == BufferedImage.TYPE_BYTE_INDEXED);
161 |
162 | BufferedImage rgbBufferedImage = new BufferedImage(bufferedImage.getWidth(), bufferedImage.getHeight(), BufferedImage.TYPE_INT_RGB);
163 | Graphics2D graphics = rgbBufferedImage.createGraphics();
164 | graphics.drawImage(bufferedImage, 0, 0, null);
165 | graphics.dispose();
166 | assertValidBufferedImage(rgbBufferedImage);
167 | assertFalse("Expecting no transparency", rgbBufferedImage.getColorModel().hasAlpha());
168 | assertEquals("Expecting RGB color model", BufferedImage.TYPE_INT_RGB, rgbBufferedImage.getType());
169 |
170 | File targetImageFile = createOutputFileName("testWriteTransparentImagesUsingRGBAsJpeg", sourceImageFile, formatName);
171 | writeBufferedImage(rgbBufferedImage, formatName, targetImageFile);
172 | }
173 | }
174 |
175 | // ======================================================================
176 | // TIFF Images
177 | // ======================================================================
178 |
179 | @Test
180 | public void testConvertTiffImagesToJpeg() throws Exception {
181 |
182 | String formatName = "jpeg";
183 | List sourceImageFileList = new ArrayList();
184 |
185 | sourceImageFileList.add(getImageFile("tiff", "marble.tiff"));
186 | sourceImageFileList.add(getImageFile("tiff", "test-multi-gray-compression-type-4.tiff"));
187 | sourceImageFileList.add(getImageFile("tiff", "test-multi-rgb-compression-type-7.tiff"));
188 | // sourceImageFileList.add(getImageFile("tiff", "test-single-cmyk-compression-lzw.tiff"));
189 | sourceImageFileList.add(getImageFile("tiff", "test-single-gray-compression-lzw.tiff"));
190 | sourceImageFileList.add(getImageFile("tiff", "test-single-gray-compression-type-2.tiff"));
191 | sourceImageFileList.add(getImageFile("tiff", "test-single-gray-compression-type-3.tiff"));
192 | sourceImageFileList.add(getImageFile("tiff", "test-single-gray-compression-type-4.tiff"));
193 | sourceImageFileList.add(getImageFile("tiff", "test-single-rgb-uncompressed.tiff"));
194 |
195 | for (File sourceImageFile : sourceImageFileList) {
196 | BufferedImage bufferedImage = createBufferedImage(sourceImageFile);
197 | assertValidBufferedImage(bufferedImage);
198 | File targetImageFile = createOutputFileName("testConvertTiffImageWriteToJpeg", sourceImageFile, formatName);
199 | writeBufferedImage(bufferedImage, formatName, targetImageFile);
200 | }
201 | }
202 | }
203 |
--------------------------------------------------------------------------------
/code/jipsg/twelvemonkeys/src/test/java/org/github/jipsg/twelvemonkeys/ImageLoadTwelveMonkeysTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package org.github.jipsg.twelvemonkeys;
18 |
19 | import org.junit.Before;
20 | import org.junit.Test;
21 |
22 | import javax.imageio.ImageIO;
23 | import javax.imageio.ImageReader;
24 | import javax.imageio.stream.ImageInputStream;
25 | import java.awt.image.BufferedImage;
26 | import java.io.File;
27 | import java.util.ArrayList;
28 | import java.util.HashSet;
29 | import java.util.Iterator;
30 | import java.util.List;
31 | import java.util.Set;
32 |
33 | import static org.junit.Assert.assertEquals;
34 |
35 | /**
36 | * Load various images.
37 | */
38 | public class ImageLoadTwelveMonkeysTest extends BaseTwelveMonkeysTest {
39 |
40 | @Before
41 | @Override
42 | public void setup() {
43 | super.setup();
44 | }
45 |
46 | // ======================================================================
47 | // General
48 | // ======================================================================
49 |
50 | /**
51 | * List available image formats.
52 | *
53 | * see http://examples.javacodegeeks.com/desktop-java/imageio/list-read-write-supported-image-formats/
54 | */
55 | @Test
56 | public void testListSupportedImageFormats() throws Exception {
57 |
58 | Set set = new HashSet();
59 |
60 | // Get list of all informal format names understood by the current set of registered readers
61 | String[] formatNames = ImageIO.getReaderFormatNames();
62 |
63 | for (final String formatName : formatNames) {
64 | set.add(formatName.toLowerCase());
65 | }
66 | System.out.println("Supported read formats: " + set);
67 |
68 | set.clear();
69 |
70 | // Get list of all informal format names understood by the current set of registered writers
71 | formatNames = ImageIO.getWriterFormatNames();
72 |
73 | for (final String formatName : formatNames) {
74 | set.add(formatName.toLowerCase());
75 | }
76 | System.out.println("Supported write formats: " + set);
77 |
78 | set.clear();
79 |
80 | // Get list of all MIME types understood by the current set of registered readers
81 | formatNames = ImageIO.getReaderMIMETypes();
82 |
83 | for (final String formatName : formatNames) {
84 | set.add(formatName.toLowerCase());
85 | }
86 | System.out.println("Supported read MIME types: " + set);
87 |
88 | set.clear();
89 |
90 | // Get list of all MIME types understood by the current set of registered writers
91 | formatNames = ImageIO.getWriterMIMETypes();
92 |
93 | for (final String formatName : formatNames) {
94 | set.add(formatName.toLowerCase());
95 | }
96 | System.out.println("Supported write MIME types: " + set);
97 | }
98 |
99 | // ======================================================================
100 | // Load various image formats
101 | // ======================================================================
102 |
103 | @Test
104 | public void testLoadVariousImageFormats() throws Exception {
105 |
106 | List sourceImageFileList = new ArrayList();
107 |
108 | sourceImageFileList.add(getImageFile("jpg", "marble.jpg"));
109 | sourceImageFileList.add(getImageFile("png", "marble.png"));
110 | sourceImageFileList.add(getImageFile("tiff", "marble.tiff"));
111 | sourceImageFileList.add(getImageFile("gif", "marble.gif"));
112 | // sourceImageFileList.add(getImageFile("jp2", "marble.jp2"));
113 |
114 | for (File sourceImageFile : sourceImageFileList) {
115 | BufferedImage bufferedImage = createBufferedImage(sourceImageFile);
116 | assertValidBufferedImage(bufferedImage);
117 | }
118 | }
119 |
120 | // ======================================================================
121 | // JPEG
122 | // ======================================================================
123 |
124 | /**
125 | * Plain-vanilla JPEG
126 | */
127 | @Test
128 | public void testLoadJPEGImage() throws Exception {
129 | assertValidBufferedImage(createBufferedImage(getImageFile("jpg", "test-image-rgb-01.jpg")));
130 | }
131 |
132 | /**
133 | * CMYK color model is supported.
134 | */
135 | @Test
136 | public void testLoadCMYKImage() throws Exception {
137 | assertValidBufferedImage(createBufferedImage(getImageFile("jpg", "test-image-cmyk-uncompressed.jpg")));
138 | }
139 |
140 | // ======================================================================
141 | // TIFF
142 | // ======================================================================
143 |
144 | /**
145 | * Load a TIFF image with compression 2.
146 | */
147 | @Test
148 | public void testLoadTiffGrayWithCompression2() throws Exception {
149 | assertValidBufferedImage(createBufferedImage(getImageFile("tiff", "test-single-gray-compression-type-2.tiff")));
150 | }
151 |
152 | /**
153 | * Load a TIFF image with compression 3.
154 | */
155 | @Test
156 | public void testLoadTiffWithCompression3() throws Exception {
157 | assertValidBufferedImage(createBufferedImage(getImageFile("tiff", "test-single-gray-compression-type-3.tiff")));
158 | }
159 |
160 | /**
161 | * Load a TIFF image with compression 4.
162 | */
163 | @Test
164 | public void testLoadTiffWithCompression4() throws Exception {
165 | assertValidBufferedImage(createBufferedImage(getImageFile("tiff", "test-single-gray-compression-type-4.tiff")));
166 | }
167 |
168 | /**
169 | * Load a multi-page TIFF.
170 | */
171 | @Test
172 | public void testLoadTiffMultiPageGray() throws Exception {
173 | assertValidBufferedImage(createBufferedImage(getImageFile("tiff", "test-multi-gray-compression-type-4.tiff")));
174 | }
175 |
176 | /**
177 | * Load a TIFF image with compression type 7 (JPEG).
178 | */
179 | @Test
180 | public void testLoadTiffMultiRgbCompression7() throws Exception {
181 | assertValidBufferedImage(createBufferedImage(getImageFile("tiff", "test-multi-rgb-compression-type-7.tiff")));
182 | }
183 |
184 | /**
185 | * Load a TIFF image with compression LZW.
186 | */
187 | @Test
188 | public void testLoadTiffSingleCmykCompressionLzw() throws Exception {
189 | assertValidBufferedImage(createBufferedImage(getImageFile("tiff", "test-single-cmyk-compression-lzw.tiff")));
190 | }
191 |
192 | // ======================================================================
193 | // Multi-page TIFF extraction
194 | // ======================================================================
195 |
196 | /**
197 | * Load a multi-page TIFF image and split it into its individual pages.
198 | */
199 | @Test
200 | public void testExtractPagesFromMultiPageTiffCompression4() throws Exception {
201 |
202 | File sourceImageFile = getImageFile("tiff", "test-multi-gray-compression-type-4.tiff");
203 | ImageInputStream is = ImageIO.createImageInputStream(sourceImageFile);
204 |
205 | // get the first matching reader
206 | Iterator iterator = ImageIO.getImageReaders(is);
207 | ImageReader imageReader = iterator.next();
208 | imageReader.setInput(is);
209 |
210 | // split the multi-page TIFF
211 | int pages = imageReader.getNumImages(true);
212 | for (int i = 0; i < pages; i++) {
213 | BufferedImage bufferedImage = imageReader.read(i);
214 | assertValidBufferedImage(bufferedImage);
215 | }
216 |
217 | assertEquals("Expect to have 2 pages", 2, pages);
218 | }
219 |
220 | /**
221 | * Load a multi-page TIFF image and split it into its individual pages.
222 | */
223 | @Test
224 | public void testExtractPagesFromMultiPageTiffCompression7() throws Exception {
225 |
226 | File sourceImageFile = getImageFile("tiff", "test-multi-rgb-compression-type-7.tiff");
227 | ImageInputStream is = ImageIO.createImageInputStream(sourceImageFile);
228 |
229 | // get the first matching reader
230 | Iterator iterator = ImageIO.getImageReaders(is);
231 | ImageReader imageReader = iterator.next();
232 | imageReader.setInput(is);
233 |
234 | // split the multi-page TIFF
235 | int pages = imageReader.getNumImages(true);
236 | for (int i = 0; i < pages; i++) {
237 | BufferedImage bufferedImage = imageReader.read(i);
238 | assertValidBufferedImage(bufferedImage);
239 | }
240 |
241 | assertEquals("Expect to have 10 pages", 10, pages);
242 | }
243 |
244 | }
245 |
--------------------------------------------------------------------------------
/code/jipsg/twelvemonkeys/src/test/java/org/github/jipsg/twelvemonkeys/ImageResamplingTwelveMonkeysTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package org.github.jipsg.twelvemonkeys;
18 |
19 | import org.junit.Before;
20 | import org.junit.Test;
21 |
22 | import java.awt.image.BufferedImage;
23 | import java.io.File;
24 | import java.util.ArrayList;
25 | import java.util.List;
26 |
27 | /**
28 | * Load various images.
29 | */
30 | public class ImageResamplingTwelveMonkeysTest extends BaseTwelveMonkeysTest {
31 |
32 | @Before
33 | public void setup() {
34 | super.setup();
35 | }
36 |
37 | /**
38 | * Load various image types and re-sample them to 640 x 480.
39 | */
40 | @Test
41 | public void testResamplingImagesAsJpeg() throws Exception {
42 |
43 | String formatName = "jpeg";
44 | List sourceImageFileList = new ArrayList();
45 |
46 | sourceImageFileList.add(getImageFile("jpg", "marble.jpg"));
47 | sourceImageFileList.add(getImageFile("png", "marble.png"));
48 | sourceImageFileList.add(getImageFile("tiff", "marble.tiff"));
49 | sourceImageFileList.add(getImageFile("gif", "marble.gif"));
50 |
51 | for (File sourceImageFile : sourceImageFileList) {
52 | BufferedImage bufferedImage = createBufferedImage(sourceImageFile);
53 | assertValidBufferedImage(bufferedImage);
54 | BufferedImage resampledBufferdImage = resample(bufferedImage, 640, 480);
55 | assertValidBufferedImage(resampledBufferdImage);
56 | File targetImageFile = createOutputFileName("testResamplingImagesAsJpeg", sourceImageFile, formatName);
57 | writeBufferedImage(resampledBufferdImage, formatName, targetImageFile);
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/code/jipsg/twelvemonkeys/src/test/java/org/github/jipsg/twelvemonkeys/ImageScalingTwelveMonkeysTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 | package org.github.jipsg.twelvemonkeys;
18 |
19 | import org.junit.Before;
20 | import org.junit.Test;
21 |
22 | import java.awt.image.BufferedImage;
23 | import java.io.File;
24 |
25 | /**
26 | * Load various images.
27 | */
28 | public class ImageScalingTwelveMonkeysTest extends BaseTwelveMonkeysTest {
29 |
30 | @Before
31 | public void setup() {
32 | super.setup();
33 | }
34 |
35 | // ======================================================================
36 | // Image Scaling
37 | // ======================================================================
38 |
39 | @Test
40 | public void testScaleImages() throws Exception {
41 |
42 | final int[] IMAGE_SCALE_DIMENSIONS = new int[] {575, 199, 80, 60};
43 |
44 | File sourceImageDir = new File("../../images/willhaben");
45 | File[] sourceImageFiles = sourceImageDir.listFiles();
46 |
47 | long currentTime = System.currentTimeMillis();
48 |
49 | for (File sourceImageFile : sourceImageFiles) {
50 |
51 | BufferedImage bufferedImage = createBufferedImage(sourceImageFile);
52 |
53 | for (int size : IMAGE_SCALE_DIMENSIONS) {
54 | BufferedImage scaledBufferedImage = resample(bufferedImage, size, size);
55 | bufferedImage = scaledBufferedImage;
56 | writeBufferedImage(scaledBufferedImage, "jpeg", createOutputFileName("testScaleImages/" + size, sourceImageFile, "jpeg"));
57 | }
58 | }
59 |
60 | long duration = System.currentTimeMillis() - currentTime;
61 |
62 | System.out.println("Scaling one source image to " + IMAGE_SCALE_DIMENSIONS.length + " previews took " + duration / sourceImageFiles.length + " ms");
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/code/libs/commons-imaging-1.0-20160915.001141-89.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sgoeschl/java-image-processing-survival-guide/3cde84bba0b8018d6fcf222f76d041b6b950baa7/code/libs/commons-imaging-1.0-20160915.001141-89.jar
--------------------------------------------------------------------------------
/code/libs/jai_codec-1.1.2_01.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sgoeschl/java-image-processing-survival-guide/3cde84bba0b8018d6fcf222f76d041b6b950baa7/code/libs/jai_codec-1.1.2_01.jar
--------------------------------------------------------------------------------
/code/libs/jai_core-1.1.3.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sgoeschl/java-image-processing-survival-guide/3cde84bba0b8018d6fcf222f76d041b6b950baa7/code/libs/jai_core-1.1.3.jar
--------------------------------------------------------------------------------
/code/libs/jai_imageio-1.1.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sgoeschl/java-image-processing-survival-guide/3cde84bba0b8018d6fcf222f76d041b6b950baa7/code/libs/jai_imageio-1.1.jar
--------------------------------------------------------------------------------
/code/libs/mvn-install-file.bat:
--------------------------------------------------------------------------------
1 | # Java Advanced Imaging (JAI)
2 |
3 | call mvn install:install-file -Dfile=jai_core-1.1.3.jar -Dversion=1.1.3 -DgroupId=com.sun.media -DartifactId=jai_core -Dpackaging=jar -DcreateChecksum=true -DgeneratePom=true
4 | call mvn install:install-file -Dfile=jai_codec-1.1.2_01.jar -Dversion=1.1.2_01 -DgroupId=com.sun.media -DartifactId=jai_codec -Dpackaging=jar -DcreateChecksum=true -DgeneratePom=true
5 | call mvn install:install-file -Dfile=jai_imageio-1.1.jar -Dversion=1.1 -DgroupId=com.sun.media -DartifactId=jai_imageio -Dpackaging=jar -DcreateChecksum=true -DgeneratePom=true
6 | call mvn install:install-file -Dfile=commons-imaging-1.0-20160915.001141-89.jar -Dversion=1.0-20160915.001141-89 -DgroupId=org.apache.commons -DartifactId=commons-imaging -Dpackaging=jar -DcreateChecksum=true -DgeneratePom=true
7 |
--------------------------------------------------------------------------------
/code/libs/mvn-install-file.sh:
--------------------------------------------------------------------------------
1 | # Java Advanced Imaging (JAI)
2 |
3 | mvn install:install-file -Dfile=jai_core-1.1.3.jar -Dversion=1.1.3 -DgroupId=com.sun.media -DartifactId=jai_core -Dpackaging=jar -DcreateChecksum=true -DgeneratePom=true
4 | mvn install:install-file -Dfile=jai_codec-1.1.2_01.jar -Dversion=1.1.2_01 -DgroupId=com.sun.media -DartifactId=jai_codec -Dpackaging=jar -DcreateChecksum=true -DgeneratePom=true
5 | mvn install:install-file -Dfile=jai_imageio-1.1.jar -Dversion=1.1 -DgroupId=com.sun.media -DartifactId=jai_imageio -Dpackaging=jar -DcreateChecksum=true -DgeneratePom=true
6 | mvn install:install-file -Dfile=commons-imaging-1.0-20160915.001141-89.jar -Dversion=1.0-SNAPSHOT -DgroupId=org.apache.commons -DartifactId=commons-imaging -Dpackaging=jar -DcreateChecksum=true -DgeneratePom=true
7 |
--------------------------------------------------------------------------------
/code/libs/readme.md:
--------------------------------------------------------------------------------
1 | This folder contains libraries not found in Maven Central which need to be imported manually
--------------------------------------------------------------------------------
/code/pdf/erste-document-01.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sgoeschl/java-image-processing-survival-guide/3cde84bba0b8018d6fcf222f76d041b6b950baa7/code/pdf/erste-document-01.pdf
--------------------------------------------------------------------------------
/code/pdf/sigice9_172.CVISION.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sgoeschl/java-image-processing-survival-guide/3cde84bba0b8018d6fcf222f76d041b6b950baa7/code/pdf/sigice9_172.CVISION.pdf
--------------------------------------------------------------------------------
/code/pdf/test-large-scan.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sgoeschl/java-image-processing-survival-guide/3cde84bba0b8018d6fcf222f76d041b6b950baa7/code/pdf/test-large-scan.pdf
--------------------------------------------------------------------------------
/paper/images/alpha-channel-after.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sgoeschl/java-image-processing-survival-guide/3cde84bba0b8018d6fcf222f76d041b6b950baa7/paper/images/alpha-channel-after.png
--------------------------------------------------------------------------------
/paper/images/alpha-channel-before.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sgoeschl/java-image-processing-survival-guide/3cde84bba0b8018d6fcf222f76d041b6b950baa7/paper/images/alpha-channel-before.png
--------------------------------------------------------------------------------
/paper/images/house-after.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sgoeschl/java-image-processing-survival-guide/3cde84bba0b8018d6fcf222f76d041b6b950baa7/paper/images/house-after.jpg
--------------------------------------------------------------------------------
/paper/images/house-before.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sgoeschl/java-image-processing-survival-guide/3cde84bba0b8018d6fcf222f76d041b6b950baa7/paper/images/house-before.gif
--------------------------------------------------------------------------------
/paper/images/pdf-jbig2-image-result.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sgoeschl/java-image-processing-survival-guide/3cde84bba0b8018d6fcf222f76d041b6b950baa7/paper/images/pdf-jbig2-image-result.jpg
--------------------------------------------------------------------------------
/paper/images/pdf-jbig2-image-source.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sgoeschl/java-image-processing-survival-guide/3cde84bba0b8018d6fcf222f76d041b6b950baa7/paper/images/pdf-jbig2-image-source.jpg
--------------------------------------------------------------------------------
/paper/images/willhaben-advert-desktop-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sgoeschl/java-image-processing-survival-guide/3cde84bba0b8018d6fcf222f76d041b6b950baa7/paper/images/willhaben-advert-desktop-small.png
--------------------------------------------------------------------------------
/paper/images/willhaben-advert-desktop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sgoeschl/java-image-processing-survival-guide/3cde84bba0b8018d6fcf222f76d041b6b950baa7/paper/images/willhaben-advert-desktop.png
--------------------------------------------------------------------------------
/paper/images/willhaben-advert-mobile-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sgoeschl/java-image-processing-survival-guide/3cde84bba0b8018d6fcf222f76d041b6b950baa7/paper/images/willhaben-advert-mobile-small.png
--------------------------------------------------------------------------------
/paper/images/willhaben-advert-mobile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sgoeschl/java-image-processing-survival-guide/3cde84bba0b8018d6fcf222f76d041b6b950baa7/paper/images/willhaben-advert-mobile.png
--------------------------------------------------------------------------------
/slides/images/12-monkeys-505001e4d6467.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sgoeschl/java-image-processing-survival-guide/3cde84bba0b8018d6fcf222f76d041b6b950baa7/slides/images/12-monkeys-505001e4d6467.png
--------------------------------------------------------------------------------
/slides/images/TwelveMonkeys ImageIO_logo.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sgoeschl/java-image-processing-survival-guide/3cde84bba0b8018d6fcf222f76d041b6b950baa7/slides/images/TwelveMonkeys ImageIO_logo.pdf
--------------------------------------------------------------------------------
/slides/images/challanger-launch-wikipedia.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sgoeschl/java-image-processing-survival-guide/3cde84bba0b8018d6fcf222f76d041b6b950baa7/slides/images/challanger-launch-wikipedia.jpg
--------------------------------------------------------------------------------
/slides/images/large-image-scan-pdf.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sgoeschl/java-image-processing-survival-guide/3cde84bba0b8018d6fcf222f76d041b6b950baa7/slides/images/large-image-scan-pdf.jpg
--------------------------------------------------------------------------------
/slides/images/logo/bouvet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sgoeschl/java-image-processing-survival-guide/3cde84bba0b8018d6fcf222f76d041b6b950baa7/slides/images/logo/bouvet.png
--------------------------------------------------------------------------------
/slides/images/logo/willhaben.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sgoeschl/java-image-processing-survival-guide/3cde84bba0b8018d6fcf222f76d041b6b950baa7/slides/images/logo/willhaben.png
--------------------------------------------------------------------------------
/slides/images/pdf-jbig2-image-result.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sgoeschl/java-image-processing-survival-guide/3cde84bba0b8018d6fcf222f76d041b6b950baa7/slides/images/pdf-jbig2-image-result.jpg
--------------------------------------------------------------------------------
/slides/images/pdf-jbig2-image-source.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sgoeschl/java-image-processing-survival-guide/3cde84bba0b8018d6fcf222f76d041b6b950baa7/slides/images/pdf-jbig2-image-source.jpg
--------------------------------------------------------------------------------
/slides/images/willhaben-advert-desktop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sgoeschl/java-image-processing-survival-guide/3cde84bba0b8018d6fcf222f76d041b6b950baa7/slides/images/willhaben-advert-desktop.png
--------------------------------------------------------------------------------
/slides/images/willhaben-advert-mobile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sgoeschl/java-image-processing-survival-guide/3cde84bba0b8018d6fcf222f76d041b6b950baa7/slides/images/willhaben-advert-mobile.png
--------------------------------------------------------------------------------
/slides/jipsg.key:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sgoeschl/java-image-processing-survival-guide/3cde84bba0b8018d6fcf222f76d041b6b950baa7/slides/jipsg.key
--------------------------------------------------------------------------------
/slides/jipsg.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sgoeschl/java-image-processing-survival-guide/3cde84bba0b8018d6fcf222f76d041b6b950baa7/slides/jipsg.pdf
--------------------------------------------------------------------------------
/slides/twelvemonkeys-slides.txt:
--------------------------------------------------------------------------------
1 | The Twelvemonkeys ImageIO project was created to solve many of the problems or similar problems to those mentioned by Sigfried.
2 |
3 |
4 |
5 | It was started when I was working for a CMS (Conntent managment system) vendor [Escenic, but we might skip mentioning names], that created CMS solutions targeted for the media insdustry (newspapers, broadcast). It's a web-centric CMS, and thus needed rich media/image support.
6 | The initial version was created, because we (the web content management system I worked on at the time) needed support for more image formats.
7 |
8 | History
9 |
10 | 2005...ish
11 | 1.x version:
12 | - Java (prior to J2SE 1.4) had only limitted support for reading JPEG, PNG and GIF
13 | - And more importantly, no official API for writing images existed.
14 | - The APIs that existed was based- around the java.awt.Image class, and not the more versatile BufferedImage class.
15 |
16 | - JMagick had support for many formats, but had no stream support, wich is very bad when working with web architectures. Temporary writing to disk increases the response time, and slows down overall performance. Plus the lack of binary compatibiltiy from version to version and being a nightmare to install.
17 | - JAI was around, but at the time reading/writing images using JAI requrired a different API.
18 | - None of the libraries had proper support for PSD format (JMagick didn't support reading individual layers)
19 |
20 | The initial version had a simple read/write API, that dealt with BufferedImages.
21 |
22 | 2008..ish
23 | 2.x version:
24 | Nowadays, the world is a little different, thus the goals have changed:
25 |
26 | - ImageIO (javax.imageio package) has become the standard API to read/write images in Java.
27 | - Thus the goal has been to help the Java platform read as many formats, as complete as possible, using the ImageIO API.
28 | - JAI ImageIO has rich support for formats:
29 | - However, it has bugs, and when you hit them: No-one listens. Seems to have no support from Oracle.
30 | - No official updates for the last years (last release was ...)
31 | - Dying community for the same reasons
32 | - Requires native libraries for full format support/best performance. Which means more difficult installation. And worse, no native libraries exist for many modern popular architectures (ie, 64 bit architectures)
33 | - License issues (http://stackoverflow.com/questions/23166231/java-advanced-imaging-license).
34 | - Some parts seems to be open source, some parts not (like the native code)
35 | - Multiple, semi-overlapping forks (GitHub, Google code, private) with the same + its own license issues...
36 |
37 | - JMagick hasn't changed much. TwelveMonkeys has wrapper readers/writers to allow users to use ImageMagicks rich format support, while using the ImageIO API. However, due to the nature of the library, it will never have the same performance or rich features.
38 |
39 | - Apache Commons Imaging has emerged from Sanselan. A quite mature library, but unfortunately has its own API. Combined with the the fact that it doesn't support all the same formats as ImageIO, this means you either have to program against multiple APIs, create your own wrappers or even your own abstraction API on top of these multiple APIs.
40 |
41 | - Conclusion: We need something better! We deserver better. :-)
42 |
43 | 3.0 version (current):
44 | - To be released "very soon" (development/pre-release versions has been in use at customer sites for 1-2 years)
45 | - Very much improved JPEG (read) support (CMYK handling, improved color profile handling, JFIF and EXIF support) over the standard JPEGImageReader that comes with the (Oracle) JRE.
46 | - Solves most of the issues that usually crops up at StackOverflow, "Exception reading JPEG with colorspace X", "Inconsistent metadata when reading JPEG" etc.
47 | - Full TIFF baseline support + most de facto standards + many popular extensions (read-only for now)
48 | - Support for CMYK color space and proper ICC profile based CMYK to RGB conversion support throughout the project
49 |
50 | 3.1 [this is all unofficial and its perhaps becoming too much "commercial"-like, so I'm fine with skipping this part]:
51 | - CMYK JPEG write support, better JPEG metadata support
52 | - TIFF write support, TIFF metadata support
53 | - PNM read/write, metadata support
54 | - CR2 support (limited read, thumbnail), TIFF/EXIF metadata
55 |
56 |
57 |
58 |
59 |
60 | TwevelMonkeys JPEG plug-in in aprticular:
61 | Goal: Read everything that can be read by other software*.
62 |
63 | Currently, not doing too bad.
64 | - However, because the base JPEG decoding is done by the same JNI code that the standard Java JPEGImageReader uses, we only support Huffman encoded, lossy JPEG, either baseline or progressive (ie, no Arithmetic encoding, no lossless compression). I guess this covers around 90% of all JPEGs in the known universe.
65 |
66 | *) Other software here, typically means libJPEG, but also Adobe Photoshop and others.
67 |
68 |
69 | - Memory mapped buffers, can they be used of anyting?
70 |
71 |
72 |
73 | Some thoughts and questions I have no answer for (and might be off-topic :-):
74 | - What about the future of Java and JavaFX?
75 | - JavaFX has its own Image class, can be converted from BufferedImage using some Swing/FX brigde utilities, but costly... Seems to be no direct replacement for ImageIO in the JavaFX world. Do we have to start from scratch? Again?
76 |
77 |
78 | Of course not: FX-IIO project started on GitHub. Acts as a bridge to allow creating BufferedImages backed by native JavaFX Image/WritableImage.
79 |
80 |
81 | Future development:
82 | - Mostly done:
83 | - PNM format (PBM, PGM, PPM and PAM)
84 | - Read + write + metadata
85 | - PCX, TGA and SGI formats
86 | - Read-only support + metadata
87 |
88 | - Work in progress: More complete TIFF image read and write support
89 | - Read support for FAX compressions (CCITT T4 and T6)
90 | - Write support
91 | - LZW compression as well as all baseline compressions
92 | - JPEG (Compresssion: 7, aka New-style JPEG)
93 | - Tiles/Strips
94 | - Metadata
95 |
96 | - Work in progress: Camera RAW support
97 | - TIFF/EP + DNG support (Adobe Digital Negative)
98 | - NEF support (Nikon Electronic File)
99 | - CR2 support (Cannon RAW file)
100 | - Currently able to extract all non-compressed and lossy JPEG data previews + thumbnails
101 | (Actually easier than I thought, as all camera RAW formats are Exif-based, meaning they are basically a TIFF structure)
102 |
103 | - Work in progress: Pure Java JPEG lossless + arithmetic decoder (+encoder?)
104 | - Needed for Camera RAW plugins
105 | - Most RAW files uses lossless JPEG encoding
106 |
107 |
--------------------------------------------------------------------------------
/slides/twelvemonkeys-slides2.txt:
--------------------------------------------------------------------------------
1 | TwelveMonkeys ImageIO
2 |
3 | What is it:
4 |
5 | Mainly: A collection of plug-ins for Java's ImageIO.
6 | - Expands the number of formats supported
7 | - Supports variants of formats not supported by the JRE (ie. JPEG)
8 |
9 | Also:
10 | - Extension for deploying ImageIO plugins in web app
11 | - Basic support for on-demand dynamic image processing
12 |
13 | Last but not least:
14 | - It's free! As in Speech and Beer.
15 | - OSS project lincensed under BSD license
16 |
17 |
18 | Goal:
19 | - Make it easy to work with images in various file formats in Java.
20 |
21 | Side goals for me:
22 | - Learn new stuff
23 | - Color theory, ICC profiles etc
24 | - Compressions and algorithms (even if I'm a little bored after writing 6-7 different RLE schemes)
25 | - Computer History
26 | - Meet people
27 | - Like Sigfried :-)
28 |
29 |
30 | History pt I:
31 |
32 | The name:
33 | - We were a couple of bored consultants that had worked together for years,
34 | not satisfied with the company we were working for, conspiring in a dark pub...
35 | - Maybe we should start our own company?
36 | - It never happened, but at least we found a name for our fictive company:
37 |
38 | TwelveMonkeys (yes, after the movie)
39 |
40 |
41 | History pt II:
42 |
43 | I was working at a CMS company, creating tools to suport the workflow of online publishing.
44 | - Escenic, large in the media industry (newspapers, TV). As we were serving the same content in various channels (web, mobile, TV, paper, etc);
45 | - We needed a way to achieve on-demand re-sizing of images
46 | - This is where the web/servlet part comes from
47 |
48 | - Image editor in our editing tool, Content Studio (Swing based)
49 | - Open any file
50 | - Copy/Paste, Drag/Drop
51 |
52 | - For weird reasons (historical) OS X clipboard data in Java is available in PICT format. However, there's no easy way to read PICT data in Java. PICT is an archaic format that uses op-codes to allow vector-graphics as well as regions of pixels. Just reading normal RGB pixel data is "quite easy". Result: One of the first plugins was the PICTImageReader
53 |
54 |
55 | - Working with an online digital workflow, pretty much every customer had PhotoShop
56 | - Being able to open Photoshop documents was a key feature.
57 | Result: The PSDImageReader.
58 |
59 | (PS: I once found that another Java-based CMS (that was later acquired by Adobe) uses my PSD plugin. So, ironically, Adobe uses my PSD plugin for Java. :-))
60 |
61 | History pt III:
62 |
63 | Many years later I found myself working for an online bookstore.
64 | - Our problem was that 5-10% of the book cover images we had couldn't be properly opened and resized, even if they were in JPEG format.
65 | - Main problem: CMYK color model
66 | - Another common problem: Broken ICC profiles
67 |
68 | - The Sun/Oracle standard JPEGImageReader actually reads such files, but it can only be read using the less known readAsRaster method.
69 | - And you have to "manually" apply YCCK -> CMYK conversion,
70 | - before doing a CMYK -> RGB conversion (or apply ICC profile) for correct colors.
71 | - A lot of work.
72 |
73 | Result: The first version of the JPEGImageReader
74 |
75 | About the same time, I got a request from a friend
76 | - I can't read this JPEG, with a common AdobeRGB ICC profile..?
77 | - The Java2D ColorConvertOp that is used internally in the JPEGImageReader (default JRE and ours) when reading JPEGs with embedded color profiles, threw exceptions because of bad ICC profiles. Even if Java could otherwise read them fine...
78 | - Result: We now hot-fix a lot of the ICC profiles upon reading
79 | - Numerous other fixes are applied to bad/incorrect ICC profiles, like CorbisRGB profile etc
80 | - Bonus: We now have an internal cache of ICC color profiles and associated Java ColorSpace objects to allow reuse, and avoid excessive memory use when dealing with ICC profiles.
81 |
82 | - With "JPEG" there are so many different possible ways to encode.
83 | - In many cases, we just have to do our best, and show an image
84 | - Ignore some data, if multiple JPEG segments conflict
85 | - Log warnings, to alert the user
86 | - Don't crash (like the JRE version does)
87 |
88 | - Allow "inconsistent metadata" when reading
89 | - It's already in the file!
90 | - Let the client code/user decide what to keep
91 | - When writing, resolve in same way as reading, to make sure we only write good JPEGs
92 |
93 |
94 | Some notes/observations:
95 | - Surprisingly easy to write more plugins (especially ImageReaders) when you have already written one (especially if the one you did was TIFF :-)).
96 | - You basically needs the spec and some sample images
97 | - Most raster-based (not vector) image formats consists of pixels in RGB, gray or palette (indexed), layed out top/down (some bottom/up or even rotated)
98 | - PNM, PCX, TGA and SGI format plugins was written in as little as 3-4 evenings!
99 | - (+ a little more to fix some corner cases and meta data... ;-))
100 |
101 |
102 | A note about deploying ImageIO plugins as part of your web app
103 |
104 |
105 | Because the ImageIO plugin registry (the IIORegistry) is "VM global", it doesn't by default work well with servlet contexts. This is especially evident if you load plugins from the WEB-INF/lib or classes folder. Unless you add ImageIO.scanForPlugins() somewhere in your code, the plugins might never be available at all.
106 |
107 | I addition, servlet contexts dynamically loads and unloads classes (using a new class loader per context). If you restart your application, old classes will by default remain in memory forever (because the next time scanForPlugins is called, it's another ClassLoader that scans/loads classes, and thus they will be new instances in the registry). If a read is attempted using one of the remaining ("old") readers, weird exceptions (like NullPointerExceptions when accessing static final initialized fields) may occur.
108 |
109 | To work around both the discovery problem and the resource leak, it is recommended to use the IIOProviderContextListener that implements dynamic loading and unloading of ImageIO plugins for web applications.
110 |
111 |
112 |
113 | ...
114 |
115 |
116 | ImageIO service provider loader/unloader
117 | com.twelvemonkeys.servlet.image.IIOProviderContextListener
118 |
119 |
120 | ...
121 |
122 |
123 |
124 |
125 | Java 8 brings along one important change you should know about
126 |
127 | - The original, proprietary Kodak CMS (Color Managment System) that has been used in Java since the early days, has been replaced
128 | - Now uses the open source LittleCMS (de facto CMS for most OSS software for years) by default.
129 | - Widely used an maintained
130 | - Most users won't notice
131 | - Does affect ICC color profile handling (not 100% compatible)
132 | - Some profiles will crash/break on reading
133 | - Performance of ColorConvertOp drops :-(
134 |
135 | - For now (Java 8) it's possible to revert to the "old" KCMS using the switch
136 | - -Dsun.java2d.cmm=sun.java2d.cmm.kcms.KcmsServiceProvider
137 | - I recommend using this switch for now, if working with images
138 |
139 |
140 |
141 |
142 | Why chose TwelveMonkeys over other software?
143 |
144 | - Uses standard ImageIO API (no need to learn loads of new API)
145 | - Actively maintained
146 | - Large (and groving) user base
147 | - No native code
148 | - Open source with liberal license (BSD)
149 |
150 | Why not?
151 |
152 | - JAI ImageIO plugins still has better
153 | - Metadata and TIFF support
154 | - Lossless JPEG and JPEG-LS (using native library)
155 |
156 | - Commons Imaging (Sanselan) probably has better TIFF support (Fax compressions)
157 |
158 |
159 |
160 | Future/current work in progress:
161 | - TIFF:
162 | - metadata
163 | - write support
164 |
165 | - JPEG:
166 | - Lossless JPEG
167 | - Arithmetic coding
168 | - CMYK write support
169 |
170 | - Camera RAW plugins
171 | - CR2 (Cannon)
172 | - NEF (Nikon)
173 | - TIFF/EP and DNG (ISO/Adobe)
174 | (all TIFF/Exif derivates, so depends heavily on TIFF reading code + JPEG Lossless)
175 |
--------------------------------------------------------------------------------