83 * image is processed scan by scan. |
83 * image is processed scan by scan. |
84 */ |
84 */ |
85 private boolean imageAtOnce = false; |
85 private boolean imageAtOnce = false; |
86 Object dataArray; |
86 Object dataArray; |
87 |
87 |
88 private LCMSImageLayout(int np, int pixelType, int pixelSize) { |
88 private int dataArrayLength; /* in bytes */ |
|
89 |
|
90 private LCMSImageLayout(int np, int pixelType, int pixelSize) |
|
91 throws ImageLayoutException |
|
92 { |
89 this.pixelType = pixelType; |
93 this.pixelType = pixelType; |
90 width = np; |
94 width = np; |
91 height = 1; |
95 height = 1; |
92 nextRowOffset = np * pixelSize; |
96 nextRowOffset = safeMult(pixelSize, np); |
93 offset = 0; |
97 offset = 0; |
94 } |
98 } |
95 |
99 |
96 private LCMSImageLayout(int width, int height, int pixelType, |
100 private LCMSImageLayout(int width, int height, int pixelType, |
97 int pixelSize) { |
101 int pixelSize) |
|
102 throws ImageLayoutException |
|
103 { |
98 this.pixelType = pixelType; |
104 this.pixelType = pixelType; |
99 this.width = width; |
105 this.width = width; |
100 this.height = height; |
106 this.height = height; |
101 nextRowOffset = width * pixelSize; |
107 nextRowOffset = safeMult(pixelSize, width); |
102 offset = 0; |
108 offset = 0; |
103 } |
109 } |
104 |
110 |
105 public LCMSImageLayout(byte[] data, int np, int pixelType, int pixelSize) { |
111 |
|
112 public LCMSImageLayout(byte[] data, int np, int pixelType, int pixelSize) |
|
113 throws ImageLayoutException |
|
114 { |
106 this(np, pixelType, pixelSize); |
115 this(np, pixelType, pixelSize); |
107 dataType = DT_BYTE; |
116 dataType = DT_BYTE; |
108 dataArray = data; |
117 dataArray = data; |
109 } |
118 dataArrayLength = data.length; |
110 |
119 |
111 public LCMSImageLayout(short[] data, int np, int pixelType, int pixelSize) { |
120 verify(); |
|
121 } |
|
122 |
|
123 public LCMSImageLayout(short[] data, int np, int pixelType, int pixelSize) |
|
124 throws ImageLayoutException |
|
125 { |
112 this(np, pixelType, pixelSize); |
126 this(np, pixelType, pixelSize); |
113 dataType = DT_SHORT; |
127 dataType = DT_SHORT; |
114 dataArray = data; |
128 dataArray = data; |
115 } |
129 dataArrayLength = 2 * data.length; |
116 |
130 |
117 public LCMSImageLayout(int[] data, int np, int pixelType, int pixelSize) { |
131 verify(); |
|
132 } |
|
133 |
|
134 public LCMSImageLayout(int[] data, int np, int pixelType, int pixelSize) |
|
135 throws ImageLayoutException |
|
136 { |
118 this(np, pixelType, pixelSize); |
137 this(np, pixelType, pixelSize); |
119 dataType = DT_INT; |
138 dataType = DT_INT; |
120 dataArray = data; |
139 dataArray = data; |
121 } |
140 dataArrayLength = 4 * data.length; |
122 |
141 |
123 public LCMSImageLayout(double[] data, int np, int pixelType, int pixelSize) { |
142 verify(); |
|
143 } |
|
144 |
|
145 public LCMSImageLayout(double[] data, int np, int pixelType, int pixelSize) |
|
146 throws ImageLayoutException |
|
147 { |
124 this(np, pixelType, pixelSize); |
148 this(np, pixelType, pixelSize); |
125 dataType = DT_DOUBLE; |
149 dataType = DT_DOUBLE; |
126 dataArray = data; |
150 dataArray = data; |
|
151 dataArrayLength = 8 * data.length; |
|
152 |
|
153 verify(); |
127 } |
154 } |
128 |
155 |
129 private LCMSImageLayout() { |
156 private LCMSImageLayout() { |
130 } |
157 } |
131 |
158 |
132 /* This method creates a layout object for given image. |
159 /* This method creates a layout object for given image. |
133 * Returns null if the image is not supported by current implementation. |
160 * Returns null if the image is not supported by current implementation. |
134 */ |
161 */ |
135 public static LCMSImageLayout createImageLayout(BufferedImage image) { |
162 public static LCMSImageLayout createImageLayout(BufferedImage image) throws ImageLayoutException { |
136 LCMSImageLayout l = new LCMSImageLayout(); |
163 LCMSImageLayout l = new LCMSImageLayout(); |
137 |
164 |
138 switch (image.getType()) { |
165 switch (image.getType()) { |
139 case BufferedImage.TYPE_INT_RGB: |
166 case BufferedImage.TYPE_INT_RGB: |
140 l.pixelType = PT_ARGB_8; |
167 l.pixelType = PT_ARGB_8; |
191 case BufferedImage.TYPE_INT_ARGB: |
218 case BufferedImage.TYPE_INT_ARGB: |
192 case BufferedImage.TYPE_INT_BGR: |
219 case BufferedImage.TYPE_INT_BGR: |
193 do { |
220 do { |
194 IntegerComponentRaster intRaster = (IntegerComponentRaster) |
221 IntegerComponentRaster intRaster = (IntegerComponentRaster) |
195 image.getRaster(); |
222 image.getRaster(); |
196 l.nextRowOffset = intRaster.getScanlineStride() * 4; |
223 l.nextRowOffset = safeMult(4, intRaster.getScanlineStride()); |
197 l.offset = intRaster.getDataOffset(0) * 4; |
224 l.offset = safeMult(4, intRaster.getDataOffset(0)); |
198 l.dataArray = intRaster.getDataStorage(); |
225 l.dataArray = intRaster.getDataStorage(); |
|
226 l.dataArrayLength = 4 * intRaster.getDataStorage().length; |
199 l.dataType = DT_INT; |
227 l.dataType = DT_INT; |
200 |
228 |
201 if (l.nextRowOffset == l.width * 4 * intRaster.getPixelStride()) { |
229 if (l.nextRowOffset == l.width * 4 * intRaster.getPixelStride()) { |
202 l.imageAtOnce = true; |
230 l.imageAtOnce = true; |
203 } |
231 } |
237 |
267 |
238 case BufferedImage.TYPE_USHORT_GRAY: |
268 case BufferedImage.TYPE_USHORT_GRAY: |
239 do { |
269 do { |
240 ShortComponentRaster shortRaster = (ShortComponentRaster) |
270 ShortComponentRaster shortRaster = (ShortComponentRaster) |
241 image.getRaster(); |
271 image.getRaster(); |
242 l.nextRowOffset = shortRaster.getScanlineStride() * 2; |
272 l.nextRowOffset = safeMult(2, shortRaster.getScanlineStride()); |
243 l.offset = shortRaster.getDataOffset(0) * 2; |
273 l.offset = safeMult(2, shortRaster.getDataOffset(0)); |
244 l.dataArray = shortRaster.getDataStorage(); |
274 l.dataArray = shortRaster.getDataStorage(); |
|
275 l.dataArrayLength = 2 * shortRaster.getDataStorage().length; |
245 l.dataType = DT_SHORT; |
276 l.dataType = DT_SHORT; |
246 |
277 |
247 if (l.nextRowOffset == l.width * 2 * shortRaster.getPixelStride()) { |
278 if (l.nextRowOffset == l.width * 2 * shortRaster.getPixelStride()) { |
248 l.imageAtOnce = true; |
279 l.imageAtOnce = true; |
249 } |
280 } |
250 } while (false); |
281 } while (false); |
251 break; |
282 break; |
252 default: |
283 default: |
253 return null; |
284 return null; |
254 } |
285 } |
|
286 l.verify(); |
255 return l; |
287 return l; |
256 } |
288 } |
257 |
289 |
258 private static enum BandOrder { |
290 private static enum BandOrder { |
259 DIRECT, |
291 DIRECT, |
291 } |
323 } |
292 return order; |
324 return order; |
293 } |
325 } |
294 } |
326 } |
295 |
327 |
|
328 private void verify() throws ImageLayoutException { |
|
329 |
|
330 if (offset < 0 || offset >= dataArrayLength) { |
|
331 throw new ImageLayoutException("Invalid image layout"); |
|
332 } |
|
333 |
|
334 int lastPixelOffset = safeMult(nextRowOffset, (height - 1)); |
|
335 |
|
336 lastPixelOffset = safeAdd(lastPixelOffset, (width - 1)); |
|
337 |
|
338 int off = safeAdd(offset, lastPixelOffset); |
|
339 |
|
340 if (off < 0 || off >= dataArrayLength) { |
|
341 throw new ImageLayoutException("Invalid image layout"); |
|
342 } |
|
343 } |
|
344 |
|
345 static int safeAdd(int a, int b) throws ImageLayoutException { |
|
346 long res = a; |
|
347 res += b; |
|
348 if (res < Integer.MIN_VALUE || res > Integer.MAX_VALUE) { |
|
349 throw new ImageLayoutException("Invalid image layout"); |
|
350 } |
|
351 return (int)res; |
|
352 } |
|
353 |
|
354 static int safeMult(int a, int b) throws ImageLayoutException { |
|
355 long res = a; |
|
356 res *= b; |
|
357 if (res < Integer.MIN_VALUE || res > Integer.MAX_VALUE) { |
|
358 throw new ImageLayoutException("Invalid image layout"); |
|
359 } |
|
360 return (int)res; |
|
361 } |
|
362 |
|
363 public static class ImageLayoutException extends Exception { |
|
364 public ImageLayoutException(String message) { |
|
365 super(message); |
|
366 } |
|
367 } |
296 public static LCMSImageLayout createImageLayout(Raster r) { |
368 public static LCMSImageLayout createImageLayout(Raster r) { |
297 LCMSImageLayout l = new LCMSImageLayout(); |
369 LCMSImageLayout l = new LCMSImageLayout(); |
298 if (r instanceof ByteComponentRaster) { |
370 if (r instanceof ByteComponentRaster) { |
299 ByteComponentRaster br = (ByteComponentRaster)r; |
371 ByteComponentRaster br = (ByteComponentRaster)r; |
300 |
372 |