1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.imaging.formats.tiff;
18
19 import static org.junit.jupiter.api.Assertions.assertEquals;
20 import static org.junit.jupiter.api.Assertions.fail;
21
22 import java.awt.AlphaComposite;
23 import java.awt.Color;
24 import java.awt.Graphics2D;
25 import java.awt.image.BufferedImage;
26 import java.io.BufferedOutputStream;
27 import java.io.File;
28 import java.io.FileOutputStream;
29 import java.nio.ByteOrder;
30 import java.nio.file.Path;
31
32 import org.apache.commons.imaging.ImageFormats;
33 import org.apache.commons.imaging.Imaging;
34 import org.apache.commons.imaging.formats.tiff.constants.TiffTagConstants;
35 import org.apache.commons.imaging.formats.tiff.write.TiffImageWriterLossy;
36 import org.apache.commons.imaging.formats.tiff.write.TiffOutputDirectory;
37 import org.apache.commons.imaging.formats.tiff.write.TiffOutputSet;
38 import org.junit.jupiter.api.Test;
39 import org.junit.jupiter.api.io.TempDir;
40
41
42
43
44 public class TiffAlphaRoundTripTest {
45
46 @TempDir
47 Path tempDir;
48
49
50
51
52
53
54
55
56
57
58 boolean componentMatch(final int a, final int b, final int iShift, final int iTolerance) {
59 int delta = (a >> iShift & 0xff) - (b >> iShift & 0xff);
60 if (delta < 0) {
61 delta = -delta;
62 }
63 return delta < iTolerance;
64 }
65
66 void doPixelsMatch(final int x, final int y, final int a, final int b) {
67 if (!componentMatch(a, b, 0, 2) || !componentMatch(a, b, 8, 2) || !componentMatch(a, b, 16, 2) || !componentMatch(a, b, 24, 2)) {
68
69 final String complaint = String.format("Pixel mismatch at (%d,%d): 0x%08x 0x%08x", x, y, a, b);
70 fail(complaint);
71 }
72 }
73
74 @Test
75 public void test() throws Exception {
76
77
78
79
80
81 for (int i = 0; i < 2; i++) {
82
83
84
85 final int width = 400;
86 final int height = 400;
87 BufferedImage image0;
88 if (i == 0) {
89 image0 = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
90 } else {
91 image0 = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
92 }
93 Graphics2D g2d = image0.createGraphics();
94 g2d.setColor(Color.red);
95 g2d.fillRect(0, 0, width, height);
96 g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC));
97 g2d.setColor(new Color(0, 0, 0, 0));
98 g2d.fillRect(100, 100, 100, 100);
99 g2d.setColor(new Color(0xff, 0, 0, 0x80));
100 g2d.fillRect(200, 200, 100, 100);
101
102
103
104
105 final File file = new File(tempDir.toFile(), "TiffAlphaRoundTripTest.tif");
106 file.delete();
107 Imaging.writeImage(image0, file, ImageFormats.TIFF);
108 final BufferedImage image1 = Imaging.getBufferedImage(file);
109
110
111
112 final BufferedImage compImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
113 g2d = compImage.createGraphics();
114 g2d.setColor(Color.white);
115 g2d.fillRect(0, 0, width, height);
116 g2d.drawImage(image1, 0, 0, null);
117
118
119 final int test1 = compImage.getRGB(150, 150);
120 final int test2 = compImage.getRGB(250, 250);
121 if (i == 0) {
122 doPixelsMatch(150, 150, 0xffffffff, test1);
123 doPixelsMatch(250, 250, 0xffff7f7f, test2);
124 } else {
125 doPixelsMatch(151, 151, 0xff000000, test1);
126 doPixelsMatch(251, 251, 0xffff0000, test2);
127 }
128 }
129 }
130
131 @Test
132 void testExtraSamples() throws Exception {
133
134 final int bytesPerSample = 4;
135 final int width = 10;
136 final int height = 10;
137 final int nBytesPerStrip = bytesPerSample * height * width;
138 final ByteOrder byteOrder = ByteOrder.nativeOrder();
139
140 final int[] samples = new int[width * height];
141 for (int i = 0; i < 10; i++) {
142 for (int j = 0; j < 10; j++) {
143 final int index = i * width + j;
144 samples[index] = j > i ? 0xffff0000 : 0x88ff0000;
145 }
146 }
147
148 for (int iExtra = 0; iExtra < 3; iExtra++) {
149 final TiffOutputSet outputSet = new TiffOutputSet(byteOrder);
150 final TiffOutputDirectory outDir = outputSet.addRootDirectory();
151 outDir.add(TiffTagConstants.TIFF_TAG_IMAGE_WIDTH, width);
152 outDir.add(TiffTagConstants.TIFF_TAG_IMAGE_LENGTH, height);
153 outDir.add(TiffTagConstants.TIFF_TAG_SAMPLES_PER_PIXEL, (short) 4);
154 outDir.add(TiffTagConstants.TIFF_TAG_BITS_PER_SAMPLE, new short[] { 8, 8, 8, 8 });
155 outDir.add(TiffTagConstants.TIFF_TAG_PHOTOMETRIC_INTERPRETATION, (short) TiffTagConstants.PHOTOMETRIC_INTERPRETATION_VALUE_RGB);
156 outDir.add(TiffTagConstants.TIFF_TAG_COMPRESSION, (short) TiffTagConstants.COMPRESSION_VALUE_UNCOMPRESSED);
157 outDir.add(TiffTagConstants.TIFF_TAG_PLANAR_CONFIGURATION, (short) TiffTagConstants.PLANAR_CONFIGURATION_VALUE_CHUNKY);
158 outDir.add(TiffTagConstants.TIFF_TAG_ROWS_PER_STRIP, height);
159 outDir.add(TiffTagConstants.TIFF_TAG_STRIP_BYTE_COUNTS, nBytesPerStrip);
160
161 outDir.add(TiffTagConstants.TIFF_TAG_EXTRA_SAMPLES, (short) iExtra);
162
163 final byte[] b = new byte[nBytesPerStrip];
164 int k = 0;
165 for (final int sample : samples) {
166 b[k++] = (byte) (sample >> 16 & 0xff);
167 b[k++] = (byte) (sample >> 8 & 0xff);
168 b[k++] = (byte) (sample & 0xff);
169 b[k++] = (byte) (sample >> 24 & 0xff);
170 }
171
172 final AbstractTiffElement.DataElement[] imageData = new AbstractTiffElement.DataElement[1];
173 imageData[0] = new AbstractTiffImageData.Data(0, b.length, b);
174
175 final AbstractTiffImageData abstractTiffImageData = new AbstractTiffImageData.Strips(imageData, height);
176
177 outDir.setTiffImageData(abstractTiffImageData);
178
179 final File outputFile = new File(tempDir.toFile(), "TestExtraSamples" + iExtra + ".tiff");
180 try (FileOutputStream fos = new FileOutputStream(outputFile);
181 BufferedOutputStream bos = new BufferedOutputStream(fos)) {
182 final TiffImageWriterLossy writer = new TiffImageWriterLossy(byteOrder);
183 writer.write(bos, outputSet);
184 bos.flush();
185 }
186
187 final BufferedImage result = Imaging.getBufferedImage(outputFile);
188 final int[] argb = new int[samples.length];
189 result.getRGB(0, 0, width, height, argb, 0, width);
190 final int index = 3 * width + 1;
191 int iSample = samples[index];
192 final int iArgb = argb[index];
193 if (iExtra == 0) {
194
195
196
197 iSample |= 0xff000000;
198 } else if (iExtra == 1) {
199
200 iSample = 0x89de0000;
201 }
202 final String p = String.format("%08x", iSample);
203 final String q = String.format("%08x", iArgb);
204 assertEquals(p, q, "Failure on ExtraSamples=" + iExtra);
205 }
206 }
207 }