1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.imaging.icc;
18
19 import static org.apache.commons.imaging.common.BinaryFunctions.printCharQuad;
20 import static org.apache.commons.imaging.common.BinaryFunctions.read4Bytes;
21 import static org.apache.commons.imaging.common.BinaryFunctions.skipBytes;
22
23 import java.awt.color.ICC_Profile;
24 import java.io.File;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.nio.ByteOrder;
28 import java.util.logging.Level;
29 import java.util.logging.Logger;
30
31 import org.apache.commons.imaging.common.BinaryFileParser;
32 import org.apache.commons.imaging.common.bytesource.ByteSource;
33 import org.apache.commons.imaging.common.bytesource.ByteSourceArray;
34 import org.apache.commons.imaging.common.bytesource.ByteSourceFile;
35
36 public class IccProfileParser extends BinaryFileParser {
37
38 private static final Logger LOGGER = Logger.getLogger(IccProfileParser.class.getName());
39
40 public IccProfileParser() {
41 this.setByteOrder(ByteOrder.BIG_ENDIAN);
42 }
43
44 public IccProfileInfo getICCProfileInfo(final ICC_Profile iccProfile) {
45 if (iccProfile == null) {
46 return null;
47 }
48
49 return getICCProfileInfo(new ByteSourceArray(iccProfile.getData()));
50 }
51
52 public IccProfileInfo getICCProfileInfo(final byte[] bytes) {
53 if (bytes == null) {
54 return null;
55 }
56
57 return getICCProfileInfo(new ByteSourceArray(bytes));
58 }
59
60 public IccProfileInfo getICCProfileInfo(final File file) {
61 if (file == null) {
62 return null;
63 }
64
65 return getICCProfileInfo(new ByteSourceFile(file));
66 }
67
68 public IccProfileInfo getICCProfileInfo(final ByteSource byteSource) {
69
70 InputStream is = null;
71
72 try {
73
74 is = byteSource.getInputStream();
75 final IccProfileInfo result = readICCProfileInfo(is);
76
77 if (result == null) {
78 return null;
79 }
80
81 is.close();
82 is = null;
83
84 for (final IccTag tag : result.getTags()) {
85 final byte[] bytes = byteSource.getBlock(tag.offset, tag.length);
86
87 tag.setData(bytes);
88
89 }
90
91
92 return result;
93 } catch (final Exception e) {
94
95 LOGGER.log(Level.SEVERE, e.getMessage(), e);
96 } finally {
97 try {
98 if (is != null) {
99 is.close();
100 }
101 } catch (final Exception e) {
102 LOGGER.log(Level.SEVERE, e.getMessage(), e);
103 }
104
105 }
106
107 return null;
108 }
109
110 private IccProfileInfo readICCProfileInfo(InputStream is) {
111 final CachingInputStreamhingInputStream.html#CachingInputStream">CachingInputStream cis = new CachingInputStream(is);
112 is = cis;
113
114
115
116
117
118
119 try {
120 final int profileSize = read4Bytes("ProfileSize", is, "Not a Valid ICC Profile", getByteOrder());
121
122
123
124
125
126
127
128
129
130
131
132
133 final int cmmTypeSignature = read4Bytes("Signature", is, "Not a Valid ICC Profile", getByteOrder());
134 if (LOGGER.isLoggable(Level.FINEST)) {
135 printCharQuad("CMMTypeSignature", cmmTypeSignature);
136 }
137
138 final int profileVersion = read4Bytes("ProfileVersion", is, "Not a Valid ICC Profile", getByteOrder());
139
140 final int profileDeviceClassSignature = read4Bytes("ProfileDeviceClassSignature", is,
141 "Not a Valid ICC Profile", getByteOrder());
142 if (LOGGER.isLoggable(Level.FINEST)) {
143 printCharQuad("ProfileDeviceClassSignature", profileDeviceClassSignature);
144 }
145
146 final int colorSpace = read4Bytes("ColorSpace", is, "Not a Valid ICC Profile", getByteOrder());
147 if (LOGGER.isLoggable(Level.FINEST)) {
148 printCharQuad("ColorSpace", colorSpace);
149 }
150
151 final int profileConnectionSpace = read4Bytes("ProfileConnectionSpace", is, "Not a Valid ICC Profile", getByteOrder());
152 if (LOGGER.isLoggable(Level.FINEST)) {
153 printCharQuad("ProfileConnectionSpace", profileConnectionSpace);
154 }
155
156 skipBytes(is, 12, "Not a Valid ICC Profile");
157
158 final int profileFileSignature = read4Bytes("ProfileFileSignature", is, "Not a Valid ICC Profile", getByteOrder());
159 if (LOGGER.isLoggable(Level.FINEST)) {
160 printCharQuad("ProfileFileSignature", profileFileSignature);
161 }
162
163 final int primaryPlatformSignature = read4Bytes("PrimaryPlatformSignature", is, "Not a Valid ICC Profile", getByteOrder());
164 if (LOGGER.isLoggable(Level.FINEST)) {
165 printCharQuad("PrimaryPlatformSignature", primaryPlatformSignature);
166 }
167
168 final int variousFlags = read4Bytes("VariousFlags", is, "Not a Valid ICC Profile", getByteOrder());
169 if (LOGGER.isLoggable(Level.FINEST)) {
170 printCharQuad("VariousFlags", profileFileSignature);
171 }
172
173 final int deviceManufacturer = read4Bytes("DeviceManufacturer", is, "Not a Valid ICC Profile", getByteOrder());
174 if (LOGGER.isLoggable(Level.FINEST)) {
175 printCharQuad("DeviceManufacturer", deviceManufacturer);
176 }
177
178 final int deviceModel = read4Bytes("DeviceModel", is, "Not a Valid ICC Profile", getByteOrder());
179 if (LOGGER.isLoggable(Level.FINEST)) {
180 printCharQuad("DeviceModel", deviceModel);
181 }
182
183 skipBytes(is, 8, "Not a Valid ICC Profile");
184
185 final int renderingIntent = read4Bytes("RenderingIntent", is, "Not a Valid ICC Profile", getByteOrder());
186 if (LOGGER.isLoggable(Level.FINEST)) {
187 printCharQuad("RenderingIntent", renderingIntent);
188 }
189
190 skipBytes(is, 12, "Not a Valid ICC Profile");
191
192 final int profileCreatorSignature = read4Bytes("ProfileCreatorSignature", is, "Not a Valid ICC Profile", getByteOrder());
193 if (LOGGER.isLoggable(Level.FINEST)) {
194 printCharQuad("ProfileCreatorSignature", profileCreatorSignature);
195 }
196
197 skipBytes(is, 16, "Not a Valid ICC Profile");
198
199
200
201
202
203
204 skipBytes(is, 28, "Not a Valid ICC Profile");
205
206
207
208 final int tagCount = read4Bytes("TagCount", is, "Not a Valid ICC Profile", getByteOrder());
209
210
211 final IccTagg/icc/IccTag.html#IccTag">IccTag[] tags = new IccTag[tagCount];
212
213 for (int i = 0; i < tagCount; i++) {
214 final int tagSignature = read4Bytes("TagSignature[" + i + "]", is, "Not a Valid ICC Profile", getByteOrder());
215
216
217
218
219 final int offsetToData = read4Bytes("OffsetToData[" + i + "]", is, "Not a Valid ICC Profile", getByteOrder());
220 final int elementSize = read4Bytes("ElementSize[" + i + "]", is, "Not a Valid ICC Profile", getByteOrder());
221
222 final IccTagType fIccTagType = getIccTagType(tagSignature);
223
224
225
226
227
228
229
230
231
232
233
234
235 final IccTagging/icc/IccTag.html#IccTag">IccTag tag = new IccTag(tagSignature, offsetToData,
236 elementSize, fIccTagType);
237
238 tags[i] = tag;
239
240 }
241
242 {
243
244 while (is.read() >= 0) {
245 }
246 }
247
248 final byte[] data = cis.getCache();
249
250 if (data.length < profileSize) {
251 throw new IOException("Couldn't read ICC Profile.");
252 }
253
254 final IccProfileInfocProfileInfo.html#IccProfileInfo">IccProfileInfo result = new IccProfileInfo(data, profileSize,
255 cmmTypeSignature, profileVersion,
256 profileDeviceClassSignature, colorSpace,
257 profileConnectionSpace, profileFileSignature,
258 primaryPlatformSignature, variousFlags, deviceManufacturer,
259 deviceModel, renderingIntent, profileCreatorSignature,
260 null, tags);
261
262 if (LOGGER.isLoggable(Level.FINEST)) {
263 LOGGER.finest("issRGB: " + result.issRGB());
264 }
265
266 return result;
267 } catch (final Exception e) {
268 LOGGER.log(Level.SEVERE, e.getMessage(), e);
269 }
270
271 return null;
272 }
273
274 private IccTagType getIccTagType(final int quad) {
275 for (final IccTagType iccTagType : IccTagTypes.values()) {
276 if (iccTagType.getSignature() == quad) {
277 return iccTagType;
278 }
279 }
280
281 return null;
282 }
283
284 public boolean issRGB(final ICC_Profile iccProfile) throws IOException {
285 return issRGB(new ByteSourceArray(iccProfile.getData()));
286 }
287
288 public boolean issRGB(final byte[] bytes) throws IOException {
289 return issRGB(new ByteSourceArray(bytes));
290 }
291
292 public boolean issRGB(final File file) throws IOException {
293 return issRGB(new ByteSourceFile(file));
294 }
295
296 public boolean issRGB(final ByteSource byteSource) throws IOException {
297
298
299
300
301
302
303
304 try (InputStream is = byteSource.getInputStream()) {
305 read4Bytes("ProfileSize", is, "Not a Valid ICC Profile", getByteOrder());
306
307
308
309
310 skipBytes(is, 4 * 5);
311
312 skipBytes(is, 12, "Not a Valid ICC Profile");
313
314 skipBytes(is, 4 * 3);
315
316 final int deviceManufacturer = read4Bytes("ProfileFileSignature", is, "Not a Valid ICC Profile", getByteOrder());
317 if (LOGGER.isLoggable(Level.FINEST)) {
318 printCharQuad("DeviceManufacturer", deviceManufacturer);
319 }
320
321 final int deviceModel = read4Bytes("DeviceModel", is, "Not a Valid ICC Profile", getByteOrder());
322 if (LOGGER.isLoggable(Level.FINEST)) {
323 printCharQuad("DeviceModel", deviceModel);
324 }
325
326 return deviceManufacturer == IccConstants.IEC && deviceModel == IccConstants.sRGB;
327 }
328 }
329
330 }