|
1 /* |
|
2 * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. Oracle designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Oracle in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 * or visit www.oracle.com if you need additional information or have any |
|
23 * questions. |
|
24 */ |
|
25 |
|
26 package java.awt.image; |
|
27 |
|
28 import java.awt.color.ColorSpace; |
|
29 import java.awt.color.ICC_ColorSpace; |
|
30 import java.util.Arrays; |
|
31 |
|
32 /** |
|
33 * A {@code ColorModel} class that works with pixel values that |
|
34 * represent color and alpha information as separate samples and that |
|
35 * store each sample in a separate data element. This class can be |
|
36 * used with an arbitrary {@code ColorSpace}. The number of |
|
37 * color samples in the pixel values must be same as the number of |
|
38 * color components in the {@code ColorSpace}. There may be a |
|
39 * single alpha sample. |
|
40 * <p> |
|
41 * For those methods that use |
|
42 * a primitive array pixel representation of type {@code transferType}, |
|
43 * the array length is the same as the number of color and alpha samples. |
|
44 * Color samples are stored first in the array followed by the alpha |
|
45 * sample, if present. The order of the color samples is specified |
|
46 * by the {@code ColorSpace}. Typically, this order reflects the |
|
47 * name of the color space type. For example, for {@code TYPE_RGB}, |
|
48 * index 0 corresponds to red, index 1 to green, and index 2 to blue. |
|
49 * <p> |
|
50 * The translation from pixel sample values to color/alpha components for |
|
51 * display or processing purposes is based on a one-to-one correspondence of |
|
52 * samples to components. |
|
53 * Depending on the transfer type used to create an instance of |
|
54 * {@code ComponentColorModel}, the pixel sample values |
|
55 * represented by that instance may be signed or unsigned and may |
|
56 * be of integral type or float or double (see below for details). |
|
57 * The translation from sample values to normalized color/alpha components |
|
58 * must follow certain rules. For float and double samples, the translation |
|
59 * is an identity, i.e. normalized component values are equal to the |
|
60 * corresponding sample values. For integral samples, the translation |
|
61 * should be only a simple scale and offset, where the scale and offset |
|
62 * constants may be different for each component. The result of |
|
63 * applying the scale and offset constants is a set of color/alpha |
|
64 * component values, which are guaranteed to fall within a certain |
|
65 * range. Typically, the range for a color component will be the range |
|
66 * defined by the {@code getMinValue} and {@code getMaxValue} |
|
67 * methods of the {@code ColorSpace} class. The range for an |
|
68 * alpha component should be 0.0 to 1.0. |
|
69 * <p> |
|
70 * Instances of {@code ComponentColorModel} created with transfer types |
|
71 * {@code DataBuffer.TYPE_BYTE}, {@code DataBuffer.TYPE_USHORT}, |
|
72 * and {@code DataBuffer.TYPE_INT} have pixel sample values which |
|
73 * are treated as unsigned integral values. |
|
74 * The number of bits in a color or alpha sample of a pixel value might not |
|
75 * be the same as the number of bits for the corresponding color or alpha |
|
76 * sample passed to the |
|
77 * {@code ComponentColorModel(ColorSpace, int[], boolean, boolean, int, int)} |
|
78 * constructor. In |
|
79 * that case, this class assumes that the least significant n bits of a sample |
|
80 * value hold the component value, where n is the number of significant bits |
|
81 * for the component passed to the constructor. It also assumes that |
|
82 * any higher-order bits in a sample value are zero. Thus, sample values |
|
83 * range from 0 to 2<sup>n</sup> - 1. This class maps these sample values |
|
84 * to normalized color component values such that 0 maps to the value |
|
85 * obtained from the {@code ColorSpace's getMinValue} |
|
86 * method for each component and 2<sup>n</sup> - 1 maps to the value |
|
87 * obtained from {@code getMaxValue}. To create a |
|
88 * {@code ComponentColorModel} with a different color sample mapping |
|
89 * requires subclassing this class and overriding the |
|
90 * {@code getNormalizedComponents(Object, float[], int)} method. |
|
91 * The mapping for an alpha sample always maps 0 to 0.0 and |
|
92 * 2<sup>n</sup> - 1 to 1.0. |
|
93 * <p> |
|
94 * For instances with unsigned sample values, |
|
95 * the unnormalized color/alpha component representation is only |
|
96 * supported if two conditions hold. First, sample value 0 must |
|
97 * map to normalized component value 0.0 and sample value 2<sup>n</sup> - 1 |
|
98 * to 1.0. Second the min/max range of all color components of the |
|
99 * {@code ColorSpace} must be 0.0 to 1.0. In this case, the |
|
100 * component representation is the n least |
|
101 * significant bits of the corresponding sample. Thus each component is |
|
102 * an unsigned integral value between 0 and 2<sup>n</sup> - 1, where |
|
103 * n is the number of significant bits for a particular component. |
|
104 * If these conditions are not met, any method taking an unnormalized |
|
105 * component argument will throw an {@code IllegalArgumentException}. |
|
106 * <p> |
|
107 * Instances of {@code ComponentColorModel} created with transfer types |
|
108 * {@code DataBuffer.TYPE_SHORT}, {@code DataBuffer.TYPE_FLOAT}, and |
|
109 * {@code DataBuffer.TYPE_DOUBLE} have pixel sample values which |
|
110 * are treated as signed short, float, or double values. |
|
111 * Such instances do not support the unnormalized color/alpha component |
|
112 * representation, so any methods taking such a representation as an argument |
|
113 * will throw an {@code IllegalArgumentException} when called on one |
|
114 * of these instances. The normalized component values of instances |
|
115 * of this class have a range which depends on the transfer |
|
116 * type as follows: for float samples, the full range of the float data |
|
117 * type; for double samples, the full range of the float data type |
|
118 * (resulting from casting double to float); for short samples, |
|
119 * from approximately -maxVal to +maxVal, where maxVal is the per |
|
120 * component maximum value for the {@code ColorSpace} |
|
121 * (-32767 maps to -maxVal, 0 maps to 0.0, and 32767 maps |
|
122 * to +maxVal). A subclass may override the scaling for short sample |
|
123 * values to normalized component values by overriding the |
|
124 * {@code getNormalizedComponents(Object, float[], int)} method. |
|
125 * For float and double samples, the normalized component values are |
|
126 * taken to be equal to the corresponding sample values, and subclasses |
|
127 * should not attempt to add any non-identity scaling for these transfer |
|
128 * types. |
|
129 * <p> |
|
130 * Instances of {@code ComponentColorModel} created with transfer types |
|
131 * {@code DataBuffer.TYPE_SHORT}, {@code DataBuffer.TYPE_FLOAT}, and |
|
132 * {@code DataBuffer.TYPE_DOUBLE} |
|
133 * use all the bits of all sample values. Thus all color/alpha components |
|
134 * have 16 bits when using {@code DataBuffer.TYPE_SHORT}, 32 bits when |
|
135 * using {@code DataBuffer.TYPE_FLOAT}, and 64 bits when using |
|
136 * {@code DataBuffer.TYPE_DOUBLE}. When the |
|
137 * {@code ComponentColorModel(ColorSpace, int[], boolean, boolean, int, int)} |
|
138 * form of constructor is used with one of these transfer types, the |
|
139 * bits array argument is ignored. |
|
140 * <p> |
|
141 * It is possible to have color/alpha sample values |
|
142 * which cannot be reasonably interpreted as component values for rendering. |
|
143 * This can happen when {@code ComponentColorModel} is subclassed to |
|
144 * override the mapping of unsigned sample values to normalized color |
|
145 * component values or when signed sample values outside a certain range |
|
146 * are used. (As an example, specifying an alpha component as a signed |
|
147 * short value outside the range 0 to 32767, normalized range 0.0 to 1.0, can |
|
148 * lead to unexpected results.) It is the |
|
149 * responsibility of applications to appropriately scale pixel data before |
|
150 * rendering such that color components fall within the normalized range |
|
151 * of the {@code ColorSpace} (obtained using the {@code getMinValue} |
|
152 * and {@code getMaxValue} methods of the {@code ColorSpace} class) |
|
153 * and the alpha component is between 0.0 and 1.0. If color or alpha |
|
154 * component values fall outside these ranges, rendering results are |
|
155 * indeterminate. |
|
156 * <p> |
|
157 * Methods that use a single int pixel representation throw |
|
158 * an {@code IllegalArgumentException}, unless the number of components |
|
159 * for the {@code ComponentColorModel} is one and the component |
|
160 * value is unsigned -- in other words, a single color component using |
|
161 * a transfer type of {@code DataBuffer.TYPE_BYTE}, |
|
162 * {@code DataBuffer.TYPE_USHORT}, or {@code DataBuffer.TYPE_INT} |
|
163 * and no alpha. |
|
164 * <p> |
|
165 * A {@code ComponentColorModel} can be used in conjunction with a |
|
166 * {@code ComponentSampleModel}, a {@code BandedSampleModel}, |
|
167 * or a {@code PixelInterleavedSampleModel} to construct a |
|
168 * {@code BufferedImage}. |
|
169 * |
|
170 * @see ColorModel |
|
171 * @see ColorSpace |
|
172 * @see ComponentSampleModel |
|
173 * @see BandedSampleModel |
|
174 * @see PixelInterleavedSampleModel |
|
175 * @see BufferedImage |
|
176 * |
|
177 */ |
|
178 public class ComponentColorModel extends ColorModel { |
|
179 |
|
180 /** |
|
181 * {@code signed} is {@code true} for {@code short}, |
|
182 * {@code float}, and {@code double} transfer types; it |
|
183 * is {@code false} for {@code byte}, {@code ushort}, |
|
184 * and {@code int} transfer types. |
|
185 */ |
|
186 private boolean signed; // true for transfer types short, float, double |
|
187 // false for byte, ushort, int |
|
188 private boolean is_sRGB_stdScale; |
|
189 private boolean is_LinearRGB_stdScale; |
|
190 private boolean is_LinearGray_stdScale; |
|
191 private boolean is_ICCGray_stdScale; |
|
192 private byte[] tosRGB8LUT; |
|
193 private byte[] fromsRGB8LUT8; |
|
194 private short[] fromsRGB8LUT16; |
|
195 private byte[] fromLinearGray16ToOtherGray8LUT; |
|
196 private short[] fromLinearGray16ToOtherGray16LUT; |
|
197 private boolean needScaleInit; |
|
198 private boolean noUnnorm; |
|
199 private boolean nonStdScale; |
|
200 private float[] min; |
|
201 private float[] diffMinMax; |
|
202 private float[] compOffset; |
|
203 private float[] compScale; |
|
204 private volatile int hashCode; |
|
205 |
|
206 /** |
|
207 * Constructs a {@code ComponentColorModel} from the specified |
|
208 * parameters. Color components will be in the specified |
|
209 * {@code ColorSpace}. The supported transfer types are |
|
210 * {@code DataBuffer.TYPE_BYTE}, {@code DataBuffer.TYPE_USHORT}, |
|
211 * {@code DataBuffer.TYPE_INT}, |
|
212 * {@code DataBuffer.TYPE_SHORT}, {@code DataBuffer.TYPE_FLOAT}, |
|
213 * and {@code DataBuffer.TYPE_DOUBLE}. |
|
214 * If not null, the {@code bits} array specifies the |
|
215 * number of significant bits per color and alpha component and its |
|
216 * length should be at least the number of components in the |
|
217 * {@code ColorSpace} if there is no alpha |
|
218 * information in the pixel values, or one more than this number if |
|
219 * there is alpha information. When the {@code transferType} is |
|
220 * {@code DataBuffer.TYPE_SHORT}, {@code DataBuffer.TYPE_FLOAT}, |
|
221 * or {@code DataBuffer.TYPE_DOUBLE} the {@code bits} array |
|
222 * argument is ignored. {@code hasAlpha} indicates whether alpha |
|
223 * information is present. If {@code hasAlpha} is true, then |
|
224 * the boolean {@code isAlphaPremultiplied} |
|
225 * specifies how to interpret color and alpha samples in pixel values. |
|
226 * If the boolean is true, color samples are assumed to have been |
|
227 * multiplied by the alpha sample. The {@code transparency} |
|
228 * specifies what alpha values can be represented by this color model. |
|
229 * The acceptable {@code transparency} values are |
|
230 * {@code OPAQUE}, {@code BITMASK} or {@code TRANSLUCENT}. |
|
231 * The {@code transferType} is the type of primitive array used |
|
232 * to represent pixel values. |
|
233 * |
|
234 * @param colorSpace The {@code ColorSpace} associated |
|
235 * with this color model. |
|
236 * @param bits The number of significant bits per component. |
|
237 * May be null, in which case all bits of all |
|
238 * component samples will be significant. |
|
239 * Ignored if transferType is one of |
|
240 * {@code DataBuffer.TYPE_SHORT}, |
|
241 * {@code DataBuffer.TYPE_FLOAT}, or |
|
242 * {@code DataBuffer.TYPE_DOUBLE}, |
|
243 * in which case all bits of all component |
|
244 * samples will be significant. |
|
245 * @param hasAlpha If true, this color model supports alpha. |
|
246 * @param isAlphaPremultiplied If true, alpha is premultiplied. |
|
247 * @param transparency Specifies what alpha values can be represented |
|
248 * by this color model. |
|
249 * @param transferType Specifies the type of primitive array used to |
|
250 * represent pixel values. |
|
251 * |
|
252 * @throws IllegalArgumentException If the {@code bits} array |
|
253 * argument is not null, its length is less than the number of |
|
254 * color and alpha components, and transferType is one of |
|
255 * {@code DataBuffer.TYPE_BYTE}, |
|
256 * {@code DataBuffer.TYPE_USHORT}, or |
|
257 * {@code DataBuffer.TYPE_INT}. |
|
258 * @throws IllegalArgumentException If transferType is not one of |
|
259 * {@code DataBuffer.TYPE_BYTE}, |
|
260 * {@code DataBuffer.TYPE_USHORT}, |
|
261 * {@code DataBuffer.TYPE_INT}, |
|
262 * {@code DataBuffer.TYPE_SHORT}, |
|
263 * {@code DataBuffer.TYPE_FLOAT}, or |
|
264 * {@code DataBuffer.TYPE_DOUBLE}. |
|
265 * |
|
266 * @see ColorSpace |
|
267 * @see java.awt.Transparency |
|
268 */ |
|
269 public ComponentColorModel (ColorSpace colorSpace, |
|
270 int[] bits, |
|
271 boolean hasAlpha, |
|
272 boolean isAlphaPremultiplied, |
|
273 int transparency, |
|
274 int transferType) { |
|
275 super (bitsHelper(transferType, colorSpace, hasAlpha), |
|
276 bitsArrayHelper(bits, transferType, colorSpace, hasAlpha), |
|
277 colorSpace, hasAlpha, isAlphaPremultiplied, transparency, |
|
278 transferType); |
|
279 switch(transferType) { |
|
280 case DataBuffer.TYPE_BYTE: |
|
281 case DataBuffer.TYPE_USHORT: |
|
282 case DataBuffer.TYPE_INT: |
|
283 signed = false; |
|
284 needScaleInit = true; |
|
285 break; |
|
286 case DataBuffer.TYPE_SHORT: |
|
287 signed = true; |
|
288 needScaleInit = true; |
|
289 break; |
|
290 case DataBuffer.TYPE_FLOAT: |
|
291 case DataBuffer.TYPE_DOUBLE: |
|
292 signed = true; |
|
293 needScaleInit = false; |
|
294 noUnnorm = true; |
|
295 nonStdScale = false; |
|
296 break; |
|
297 default: |
|
298 throw new IllegalArgumentException("This constructor is not "+ |
|
299 "compatible with transferType " + transferType); |
|
300 } |
|
301 setupLUTs(); |
|
302 } |
|
303 |
|
304 /** |
|
305 * Constructs a {@code ComponentColorModel} from the specified |
|
306 * parameters. Color components will be in the specified |
|
307 * {@code ColorSpace}. The supported transfer types are |
|
308 * {@code DataBuffer.TYPE_BYTE}, {@code DataBuffer.TYPE_USHORT}, |
|
309 * {@code DataBuffer.TYPE_INT}, |
|
310 * {@code DataBuffer.TYPE_SHORT}, {@code DataBuffer.TYPE_FLOAT}, |
|
311 * and {@code DataBuffer.TYPE_DOUBLE}. The number of significant |
|
312 * bits per color and alpha component will be 8, 16, 32, 16, 32, or 64, |
|
313 * respectively. The number of color components will be the |
|
314 * number of components in the {@code ColorSpace}. There will be |
|
315 * an alpha component if {@code hasAlpha} is {@code true}. |
|
316 * If {@code hasAlpha} is true, then |
|
317 * the boolean {@code isAlphaPremultiplied} |
|
318 * specifies how to interpret color and alpha samples in pixel values. |
|
319 * If the boolean is true, color samples are assumed to have been |
|
320 * multiplied by the alpha sample. The {@code transparency} |
|
321 * specifies what alpha values can be represented by this color model. |
|
322 * The acceptable {@code transparency} values are |
|
323 * {@code OPAQUE}, {@code BITMASK} or {@code TRANSLUCENT}. |
|
324 * The {@code transferType} is the type of primitive array used |
|
325 * to represent pixel values. |
|
326 * |
|
327 * @param colorSpace The {@code ColorSpace} associated |
|
328 * with this color model. |
|
329 * @param hasAlpha If true, this color model supports alpha. |
|
330 * @param isAlphaPremultiplied If true, alpha is premultiplied. |
|
331 * @param transparency Specifies what alpha values can be represented |
|
332 * by this color model. |
|
333 * @param transferType Specifies the type of primitive array used to |
|
334 * represent pixel values. |
|
335 * |
|
336 * @throws IllegalArgumentException If transferType is not one of |
|
337 * {@code DataBuffer.TYPE_BYTE}, |
|
338 * {@code DataBuffer.TYPE_USHORT}, |
|
339 * {@code DataBuffer.TYPE_INT}, |
|
340 * {@code DataBuffer.TYPE_SHORT}, |
|
341 * {@code DataBuffer.TYPE_FLOAT}, or |
|
342 * {@code DataBuffer.TYPE_DOUBLE}. |
|
343 * |
|
344 * @see ColorSpace |
|
345 * @see java.awt.Transparency |
|
346 * @since 1.4 |
|
347 */ |
|
348 public ComponentColorModel (ColorSpace colorSpace, |
|
349 boolean hasAlpha, |
|
350 boolean isAlphaPremultiplied, |
|
351 int transparency, |
|
352 int transferType) { |
|
353 this(colorSpace, null, hasAlpha, isAlphaPremultiplied, |
|
354 transparency, transferType); |
|
355 } |
|
356 |
|
357 private static int bitsHelper(int transferType, |
|
358 ColorSpace colorSpace, |
|
359 boolean hasAlpha) { |
|
360 int numBits = DataBuffer.getDataTypeSize(transferType); |
|
361 int numComponents = colorSpace.getNumComponents(); |
|
362 if (hasAlpha) { |
|
363 ++numComponents; |
|
364 } |
|
365 return numBits * numComponents; |
|
366 } |
|
367 |
|
368 private static int[] bitsArrayHelper(int[] origBits, |
|
369 int transferType, |
|
370 ColorSpace colorSpace, |
|
371 boolean hasAlpha) { |
|
372 switch(transferType) { |
|
373 case DataBuffer.TYPE_BYTE: |
|
374 case DataBuffer.TYPE_USHORT: |
|
375 case DataBuffer.TYPE_INT: |
|
376 if (origBits != null) { |
|
377 return origBits; |
|
378 } |
|
379 break; |
|
380 default: |
|
381 break; |
|
382 } |
|
383 int numBits = DataBuffer.getDataTypeSize(transferType); |
|
384 int numComponents = colorSpace.getNumComponents(); |
|
385 if (hasAlpha) { |
|
386 ++numComponents; |
|
387 } |
|
388 int[] bits = new int[numComponents]; |
|
389 for (int i = 0; i < numComponents; i++) { |
|
390 bits[i] = numBits; |
|
391 } |
|
392 return bits; |
|
393 } |
|
394 |
|
395 private void setupLUTs() { |
|
396 // REMIND: there is potential to accelerate sRGB, LinearRGB, |
|
397 // LinearGray, ICCGray, and non-ICC Gray spaces with non-standard |
|
398 // scaling, if that becomes important |
|
399 // |
|
400 // NOTE: The is_xxx_stdScale and nonStdScale booleans are provisionally |
|
401 // set here when this method is called at construction time. These |
|
402 // variables may be set again when initScale is called later. |
|
403 // When setupLUTs returns, nonStdScale is true if (the transferType |
|
404 // is not float or double) AND (some minimum ColorSpace component |
|
405 // value is not 0.0 OR some maximum ColorSpace component value |
|
406 // is not 1.0). This is correct for the calls to |
|
407 // getNormalizedComponents(Object, float[], int) from initScale(). |
|
408 // initScale() may change the value nonStdScale based on the |
|
409 // return value of getNormalizedComponents() - this will only |
|
410 // happen if getNormalizedComponents() has been overridden by a |
|
411 // subclass to make the mapping of min/max pixel sample values |
|
412 // something different from min/max color component values. |
|
413 if (is_sRGB) { |
|
414 is_sRGB_stdScale = true; |
|
415 nonStdScale = false; |
|
416 } else if (ColorModel.isLinearRGBspace(colorSpace)) { |
|
417 // Note that the built-in Linear RGB space has a normalized |
|
418 // range of 0.0 - 1.0 for each coordinate. Usage of these |
|
419 // LUTs makes that assumption. |
|
420 is_LinearRGB_stdScale = true; |
|
421 nonStdScale = false; |
|
422 if (transferType == DataBuffer.TYPE_BYTE) { |
|
423 tosRGB8LUT = ColorModel.getLinearRGB8TosRGB8LUT(); |
|
424 fromsRGB8LUT8 = ColorModel.getsRGB8ToLinearRGB8LUT(); |
|
425 } else { |
|
426 tosRGB8LUT = ColorModel.getLinearRGB16TosRGB8LUT(); |
|
427 fromsRGB8LUT16 = ColorModel.getsRGB8ToLinearRGB16LUT(); |
|
428 } |
|
429 } else if ((colorSpaceType == ColorSpace.TYPE_GRAY) && |
|
430 (colorSpace instanceof ICC_ColorSpace) && |
|
431 (colorSpace.getMinValue(0) == 0.0f) && |
|
432 (colorSpace.getMaxValue(0) == 1.0f)) { |
|
433 // Note that a normalized range of 0.0 - 1.0 for the gray |
|
434 // component is required, because usage of these LUTs makes |
|
435 // that assumption. |
|
436 ICC_ColorSpace ics = (ICC_ColorSpace) colorSpace; |
|
437 is_ICCGray_stdScale = true; |
|
438 nonStdScale = false; |
|
439 fromsRGB8LUT16 = ColorModel.getsRGB8ToLinearRGB16LUT(); |
|
440 if (ColorModel.isLinearGRAYspace(ics)) { |
|
441 is_LinearGray_stdScale = true; |
|
442 if (transferType == DataBuffer.TYPE_BYTE) { |
|
443 tosRGB8LUT = ColorModel.getGray8TosRGB8LUT(ics); |
|
444 } else { |
|
445 tosRGB8LUT = ColorModel.getGray16TosRGB8LUT(ics); |
|
446 } |
|
447 } else { |
|
448 if (transferType == DataBuffer.TYPE_BYTE) { |
|
449 tosRGB8LUT = ColorModel.getGray8TosRGB8LUT(ics); |
|
450 fromLinearGray16ToOtherGray8LUT = |
|
451 ColorModel.getLinearGray16ToOtherGray8LUT(ics); |
|
452 } else { |
|
453 tosRGB8LUT = ColorModel.getGray16TosRGB8LUT(ics); |
|
454 fromLinearGray16ToOtherGray16LUT = |
|
455 ColorModel.getLinearGray16ToOtherGray16LUT(ics); |
|
456 } |
|
457 } |
|
458 } else if (needScaleInit) { |
|
459 // if transferType is byte, ushort, int, or short and we |
|
460 // don't already know the ColorSpace has minVlaue == 0.0f and |
|
461 // maxValue == 1.0f for all components, we need to check that |
|
462 // now and setup the min[] and diffMinMax[] arrays if necessary. |
|
463 nonStdScale = false; |
|
464 for (int i = 0; i < numColorComponents; i++) { |
|
465 if ((colorSpace.getMinValue(i) != 0.0f) || |
|
466 (colorSpace.getMaxValue(i) != 1.0f)) { |
|
467 nonStdScale = true; |
|
468 break; |
|
469 } |
|
470 } |
|
471 if (nonStdScale) { |
|
472 min = new float[numColorComponents]; |
|
473 diffMinMax = new float[numColorComponents]; |
|
474 for (int i = 0; i < numColorComponents; i++) { |
|
475 min[i] = colorSpace.getMinValue(i); |
|
476 diffMinMax[i] = colorSpace.getMaxValue(i) - min[i]; |
|
477 } |
|
478 } |
|
479 } |
|
480 } |
|
481 |
|
482 private void initScale() { |
|
483 // This method is called the first time any method which uses |
|
484 // pixel sample value to color component value scaling information |
|
485 // is called if the transferType supports non-standard scaling |
|
486 // as defined above (byte, ushort, int, and short), unless the |
|
487 // method is getNormalizedComponents(Object, float[], int) (that |
|
488 // method must be overridden to use non-standard scaling). This |
|
489 // method also sets up the noUnnorm boolean variable for these |
|
490 // transferTypes. After this method is called, the nonStdScale |
|
491 // variable will be true if getNormalizedComponents() maps a |
|
492 // sample value of 0 to anything other than 0.0f OR maps a |
|
493 // sample value of 2^^n - 1 (2^^15 - 1 for short transferType) |
|
494 // to anything other than 1.0f. Note that this can be independent |
|
495 // of the colorSpace min/max component values, if the |
|
496 // getNormalizedComponents() method has been overridden for some |
|
497 // reason, e.g. to provide greater dynamic range in the sample |
|
498 // values than in the color component values. Unfortunately, |
|
499 // this method can't be called at construction time, since a |
|
500 // subclass may still have uninitialized state that would cause |
|
501 // getNormalizedComponents() to return an incorrect result. |
|
502 needScaleInit = false; // only needs to called once |
|
503 if (nonStdScale || signed) { |
|
504 // The unnormalized form is only supported for unsigned |
|
505 // transferTypes and when the ColorSpace min/max values |
|
506 // are 0.0/1.0. When this method is called nonStdScale is |
|
507 // true if the latter condition does not hold. In addition, |
|
508 // the unnormalized form requires that the full range of |
|
509 // the pixel sample values map to the full 0.0 - 1.0 range |
|
510 // of color component values. That condition is checked |
|
511 // later in this method. |
|
512 noUnnorm = true; |
|
513 } else { |
|
514 noUnnorm = false; |
|
515 } |
|
516 float[] lowVal, highVal; |
|
517 switch (transferType) { |
|
518 case DataBuffer.TYPE_BYTE: |
|
519 { |
|
520 byte[] bpixel = new byte[numComponents]; |
|
521 for (int i = 0; i < numColorComponents; i++) { |
|
522 bpixel[i] = 0; |
|
523 } |
|
524 if (supportsAlpha) { |
|
525 bpixel[numColorComponents] = |
|
526 (byte) ((1 << nBits[numColorComponents]) - 1); |
|
527 } |
|
528 lowVal = getNormalizedComponents(bpixel, null, 0); |
|
529 for (int i = 0; i < numColorComponents; i++) { |
|
530 bpixel[i] = (byte) ((1 << nBits[i]) - 1); |
|
531 } |
|
532 highVal = getNormalizedComponents(bpixel, null, 0); |
|
533 } |
|
534 break; |
|
535 case DataBuffer.TYPE_USHORT: |
|
536 { |
|
537 short[] uspixel = new short[numComponents]; |
|
538 for (int i = 0; i < numColorComponents; i++) { |
|
539 uspixel[i] = 0; |
|
540 } |
|
541 if (supportsAlpha) { |
|
542 uspixel[numColorComponents] = |
|
543 (short) ((1 << nBits[numColorComponents]) - 1); |
|
544 } |
|
545 lowVal = getNormalizedComponents(uspixel, null, 0); |
|
546 for (int i = 0; i < numColorComponents; i++) { |
|
547 uspixel[i] = (short) ((1 << nBits[i]) - 1); |
|
548 } |
|
549 highVal = getNormalizedComponents(uspixel, null, 0); |
|
550 } |
|
551 break; |
|
552 case DataBuffer.TYPE_INT: |
|
553 { |
|
554 int[] ipixel = new int[numComponents]; |
|
555 for (int i = 0; i < numColorComponents; i++) { |
|
556 ipixel[i] = 0; |
|
557 } |
|
558 if (supportsAlpha) { |
|
559 ipixel[numColorComponents] = |
|
560 ((1 << nBits[numColorComponents]) - 1); |
|
561 } |
|
562 lowVal = getNormalizedComponents(ipixel, null, 0); |
|
563 for (int i = 0; i < numColorComponents; i++) { |
|
564 ipixel[i] = ((1 << nBits[i]) - 1); |
|
565 } |
|
566 highVal = getNormalizedComponents(ipixel, null, 0); |
|
567 } |
|
568 break; |
|
569 case DataBuffer.TYPE_SHORT: |
|
570 { |
|
571 short[] spixel = new short[numComponents]; |
|
572 for (int i = 0; i < numColorComponents; i++) { |
|
573 spixel[i] = 0; |
|
574 } |
|
575 if (supportsAlpha) { |
|
576 spixel[numColorComponents] = 32767; |
|
577 } |
|
578 lowVal = getNormalizedComponents(spixel, null, 0); |
|
579 for (int i = 0; i < numColorComponents; i++) { |
|
580 spixel[i] = 32767; |
|
581 } |
|
582 highVal = getNormalizedComponents(spixel, null, 0); |
|
583 } |
|
584 break; |
|
585 default: |
|
586 lowVal = highVal = null; // to keep the compiler from complaining |
|
587 break; |
|
588 } |
|
589 nonStdScale = false; |
|
590 for (int i = 0; i < numColorComponents; i++) { |
|
591 if ((lowVal[i] != 0.0f) || (highVal[i] != 1.0f)) { |
|
592 nonStdScale = true; |
|
593 break; |
|
594 } |
|
595 } |
|
596 if (nonStdScale) { |
|
597 noUnnorm = true; |
|
598 is_sRGB_stdScale = false; |
|
599 is_LinearRGB_stdScale = false; |
|
600 is_LinearGray_stdScale = false; |
|
601 is_ICCGray_stdScale = false; |
|
602 compOffset = new float[numColorComponents]; |
|
603 compScale = new float[numColorComponents]; |
|
604 for (int i = 0; i < numColorComponents; i++) { |
|
605 compOffset[i] = lowVal[i]; |
|
606 compScale[i] = 1.0f / (highVal[i] - lowVal[i]); |
|
607 } |
|
608 } |
|
609 } |
|
610 |
|
611 private int getRGBComponent(int pixel, int idx) { |
|
612 if (numComponents > 1) { |
|
613 throw new |
|
614 IllegalArgumentException("More than one component per pixel"); |
|
615 } |
|
616 if (signed) { |
|
617 throw new |
|
618 IllegalArgumentException("Component value is signed"); |
|
619 } |
|
620 if (needScaleInit) { |
|
621 initScale(); |
|
622 } |
|
623 // Since there is only 1 component, there is no alpha |
|
624 |
|
625 // Normalize the pixel in order to convert it |
|
626 Object opixel = null; |
|
627 switch (transferType) { |
|
628 case DataBuffer.TYPE_BYTE: |
|
629 { |
|
630 byte[] bpixel = { (byte) pixel }; |
|
631 opixel = bpixel; |
|
632 } |
|
633 break; |
|
634 case DataBuffer.TYPE_USHORT: |
|
635 { |
|
636 short[] spixel = { (short) pixel }; |
|
637 opixel = spixel; |
|
638 } |
|
639 break; |
|
640 case DataBuffer.TYPE_INT: |
|
641 { |
|
642 int[] ipixel = { pixel }; |
|
643 opixel = ipixel; |
|
644 } |
|
645 break; |
|
646 } |
|
647 float[] norm = getNormalizedComponents(opixel, null, 0); |
|
648 float[] rgb = colorSpace.toRGB(norm); |
|
649 |
|
650 return (int) (rgb[idx] * 255.0f + 0.5f); |
|
651 } |
|
652 |
|
653 /** |
|
654 * Returns the red color component for the specified pixel, scaled |
|
655 * from 0 to 255 in the default RGB ColorSpace, sRGB. A color conversion |
|
656 * is done if necessary. The pixel value is specified as an int. |
|
657 * The returned value will be a non pre-multiplied value. |
|
658 * If the alpha is premultiplied, this method divides |
|
659 * it out before returning the value (if the alpha value is 0, |
|
660 * the red value will be 0). |
|
661 * |
|
662 * @param pixel The pixel from which you want to get the red color component. |
|
663 * |
|
664 * @return The red color component for the specified pixel, as an int. |
|
665 * |
|
666 * @throws IllegalArgumentException If there is more than |
|
667 * one component in this {@code ColorModel}. |
|
668 * @throws IllegalArgumentException If the component value for this |
|
669 * {@code ColorModel} is signed |
|
670 */ |
|
671 public int getRed(int pixel) { |
|
672 return getRGBComponent(pixel, 0); |
|
673 } |
|
674 |
|
675 /** |
|
676 * Returns the green color component for the specified pixel, scaled |
|
677 * from 0 to 255 in the default RGB ColorSpace, sRGB. A color conversion |
|
678 * is done if necessary. The pixel value is specified as an int. |
|
679 * The returned value will be a non |
|
680 * pre-multiplied value. If the alpha is premultiplied, this method |
|
681 * divides it out before returning the value (if the alpha value is 0, |
|
682 * the green value will be 0). |
|
683 * |
|
684 * @param pixel The pixel from which you want to get the green color component. |
|
685 * |
|
686 * @return The green color component for the specified pixel, as an int. |
|
687 * |
|
688 * @throws IllegalArgumentException If there is more than |
|
689 * one component in this {@code ColorModel}. |
|
690 * @throws IllegalArgumentException If the component value for this |
|
691 * {@code ColorModel} is signed |
|
692 */ |
|
693 public int getGreen(int pixel) { |
|
694 return getRGBComponent(pixel, 1); |
|
695 } |
|
696 |
|
697 /** |
|
698 * Returns the blue color component for the specified pixel, scaled |
|
699 * from 0 to 255 in the default RGB ColorSpace, sRGB. A color conversion |
|
700 * is done if necessary. The pixel value is specified as an int. |
|
701 * The returned value will be a non |
|
702 * pre-multiplied value. If the alpha is premultiplied, this method |
|
703 * divides it out before returning the value (if the alpha value is 0, |
|
704 * the blue value will be 0). |
|
705 * |
|
706 * @param pixel The pixel from which you want to get the blue color component. |
|
707 * |
|
708 * @return The blue color component for the specified pixel, as an int. |
|
709 * |
|
710 * @throws IllegalArgumentException If there is more than |
|
711 * one component in this {@code ColorModel}. |
|
712 * @throws IllegalArgumentException If the component value for this |
|
713 * {@code ColorModel} is signed |
|
714 */ |
|
715 public int getBlue(int pixel) { |
|
716 return getRGBComponent(pixel, 2); |
|
717 } |
|
718 |
|
719 /** |
|
720 * Returns the alpha component for the specified pixel, scaled |
|
721 * from 0 to 255. The pixel value is specified as an int. |
|
722 * |
|
723 * @param pixel The pixel from which you want to get the alpha component. |
|
724 * |
|
725 * @return The alpha component for the specified pixel, as an int. |
|
726 * |
|
727 * @throws IllegalArgumentException If there is more than |
|
728 * one component in this {@code ColorModel}. |
|
729 * @throws IllegalArgumentException If the component value for this |
|
730 * {@code ColorModel} is signed |
|
731 */ |
|
732 public int getAlpha(int pixel) { |
|
733 if (supportsAlpha == false) { |
|
734 return 255; |
|
735 } |
|
736 if (numComponents > 1) { |
|
737 throw new |
|
738 IllegalArgumentException("More than one component per pixel"); |
|
739 } |
|
740 if (signed) { |
|
741 throw new |
|
742 IllegalArgumentException("Component value is signed"); |
|
743 } |
|
744 |
|
745 return (int) ((((float) pixel) / ((1<<nBits[0])-1)) * 255.0f + 0.5f); |
|
746 } |
|
747 |
|
748 /** |
|
749 * Returns the color/alpha components of the pixel in the default |
|
750 * RGB color model format. A color conversion is done if necessary. |
|
751 * The returned value will be in a non pre-multiplied format. If |
|
752 * the alpha is premultiplied, this method divides it out of the |
|
753 * color components (if the alpha value is 0, the color values will be 0). |
|
754 * |
|
755 * @param pixel The pixel from which you want to get the color/alpha components. |
|
756 * |
|
757 * @return The color/alpha components for the specified pixel, as an int. |
|
758 * |
|
759 * @throws IllegalArgumentException If there is more than |
|
760 * one component in this {@code ColorModel}. |
|
761 * @throws IllegalArgumentException If the component value for this |
|
762 * {@code ColorModel} is signed |
|
763 */ |
|
764 public int getRGB(int pixel) { |
|
765 if (numComponents > 1) { |
|
766 throw new |
|
767 IllegalArgumentException("More than one component per pixel"); |
|
768 } |
|
769 if (signed) { |
|
770 throw new |
|
771 IllegalArgumentException("Component value is signed"); |
|
772 } |
|
773 |
|
774 return (getAlpha(pixel) << 24) |
|
775 | (getRed(pixel) << 16) |
|
776 | (getGreen(pixel) << 8) |
|
777 | (getBlue(pixel) << 0); |
|
778 } |
|
779 |
|
780 private int extractComponent(Object inData, int idx, int precision) { |
|
781 // Extract component idx from inData. The precision argument |
|
782 // should be either 8 or 16. If it's 8, this method will return |
|
783 // an 8-bit value. If it's 16, this method will return a 16-bit |
|
784 // value for transferTypes other than TYPE_BYTE. For TYPE_BYTE, |
|
785 // an 8-bit value will be returned. |
|
786 |
|
787 // This method maps the input value corresponding to a |
|
788 // normalized ColorSpace component value of 0.0 to 0, and the |
|
789 // input value corresponding to a normalized ColorSpace |
|
790 // component value of 1.0 to 2^n - 1 (where n is 8 or 16), so |
|
791 // it is appropriate only for ColorSpaces with min/max component |
|
792 // values of 0.0/1.0. This will be true for sRGB, the built-in |
|
793 // Linear RGB and Linear Gray spaces, and any other ICC grayscale |
|
794 // spaces for which we have precomputed LUTs. |
|
795 |
|
796 boolean needAlpha = (supportsAlpha && isAlphaPremultiplied); |
|
797 int alp = 0; |
|
798 int comp; |
|
799 int mask = (1 << nBits[idx]) - 1; |
|
800 |
|
801 switch (transferType) { |
|
802 // Note: we do no clamping of the pixel data here - we |
|
803 // assume that the data is scaled properly |
|
804 case DataBuffer.TYPE_SHORT: { |
|
805 short sdata[] = (short[]) inData; |
|
806 float scalefactor = (float) ((1 << precision) - 1); |
|
807 if (needAlpha) { |
|
808 short s = sdata[numColorComponents]; |
|
809 if (s != (short) 0) { |
|
810 return (int) ((((float) sdata[idx]) / |
|
811 ((float) s)) * scalefactor + 0.5f); |
|
812 } else { |
|
813 return 0; |
|
814 } |
|
815 } else { |
|
816 return (int) ((sdata[idx] / 32767.0f) * scalefactor + 0.5f); |
|
817 } |
|
818 } |
|
819 case DataBuffer.TYPE_FLOAT: { |
|
820 float fdata[] = (float[]) inData; |
|
821 float scalefactor = (float) ((1 << precision) - 1); |
|
822 if (needAlpha) { |
|
823 float f = fdata[numColorComponents]; |
|
824 if (f != 0.0f) { |
|
825 return (int) (((fdata[idx] / f) * scalefactor) + 0.5f); |
|
826 } else { |
|
827 return 0; |
|
828 } |
|
829 } else { |
|
830 return (int) (fdata[idx] * scalefactor + 0.5f); |
|
831 } |
|
832 } |
|
833 case DataBuffer.TYPE_DOUBLE: { |
|
834 double ddata[] = (double[]) inData; |
|
835 double scalefactor = (double) ((1 << precision) - 1); |
|
836 if (needAlpha) { |
|
837 double d = ddata[numColorComponents]; |
|
838 if (d != 0.0) { |
|
839 return (int) (((ddata[idx] / d) * scalefactor) + 0.5); |
|
840 } else { |
|
841 return 0; |
|
842 } |
|
843 } else { |
|
844 return (int) (ddata[idx] * scalefactor + 0.5); |
|
845 } |
|
846 } |
|
847 case DataBuffer.TYPE_BYTE: |
|
848 byte bdata[] = (byte[])inData; |
|
849 comp = bdata[idx] & mask; |
|
850 precision = 8; |
|
851 if (needAlpha) { |
|
852 alp = bdata[numColorComponents] & mask; |
|
853 } |
|
854 break; |
|
855 case DataBuffer.TYPE_USHORT: |
|
856 short usdata[] = (short[])inData; |
|
857 comp = usdata[idx] & mask; |
|
858 if (needAlpha) { |
|
859 alp = usdata[numColorComponents] & mask; |
|
860 } |
|
861 break; |
|
862 case DataBuffer.TYPE_INT: |
|
863 int idata[] = (int[])inData; |
|
864 comp = idata[idx]; |
|
865 if (needAlpha) { |
|
866 alp = idata[numColorComponents]; |
|
867 } |
|
868 break; |
|
869 default: |
|
870 throw new |
|
871 UnsupportedOperationException("This method has not "+ |
|
872 "been implemented for transferType " + transferType); |
|
873 } |
|
874 if (needAlpha) { |
|
875 if (alp != 0) { |
|
876 float scalefactor = (float) ((1 << precision) - 1); |
|
877 float fcomp = ((float) comp) / ((float)mask); |
|
878 float invalp = ((float) ((1<<nBits[numColorComponents]) - 1)) / |
|
879 ((float) alp); |
|
880 return (int) (fcomp * invalp * scalefactor + 0.5f); |
|
881 } else { |
|
882 return 0; |
|
883 } |
|
884 } else { |
|
885 if (nBits[idx] != precision) { |
|
886 float scalefactor = (float) ((1 << precision) - 1); |
|
887 float fcomp = ((float) comp) / ((float)mask); |
|
888 return (int) (fcomp * scalefactor + 0.5f); |
|
889 } |
|
890 return comp; |
|
891 } |
|
892 } |
|
893 |
|
894 private int getRGBComponent(Object inData, int idx) { |
|
895 if (needScaleInit) { |
|
896 initScale(); |
|
897 } |
|
898 if (is_sRGB_stdScale) { |
|
899 return extractComponent(inData, idx, 8); |
|
900 } else if (is_LinearRGB_stdScale) { |
|
901 int lutidx = extractComponent(inData, idx, 16); |
|
902 return tosRGB8LUT[lutidx] & 0xff; |
|
903 } else if (is_ICCGray_stdScale) { |
|
904 int lutidx = extractComponent(inData, 0, 16); |
|
905 return tosRGB8LUT[lutidx] & 0xff; |
|
906 } |
|
907 |
|
908 // Not CS_sRGB, CS_LINEAR_RGB, or any TYPE_GRAY ICC_ColorSpace |
|
909 float[] norm = getNormalizedComponents(inData, null, 0); |
|
910 // Note that getNormalizedComponents returns non-premultiplied values |
|
911 float[] rgb = colorSpace.toRGB(norm); |
|
912 return (int) (rgb[idx] * 255.0f + 0.5f); |
|
913 } |
|
914 |
|
915 /** |
|
916 * Returns the red color component for the specified pixel, scaled |
|
917 * from 0 to 255 in the default RGB ColorSpace, sRGB. A color conversion |
|
918 * is done if necessary. The {@code pixel} value is specified by an array |
|
919 * of data elements of type {@code transferType} passed in as an object |
|
920 * reference. The returned value will be a non pre-multiplied value. If the |
|
921 * alpha is premultiplied, this method divides it out before returning |
|
922 * the value (if the alpha value is 0, the red value will be 0). Since |
|
923 * {@code ComponentColorModel} can be subclassed, subclasses |
|
924 * inherit the implementation of this method and if they don't override |
|
925 * it then they throw an exception if they use an unsupported |
|
926 * {@code transferType}. |
|
927 * |
|
928 * @param inData The pixel from which you want to get the red color component, |
|
929 * specified by an array of data elements of type {@code transferType}. |
|
930 * |
|
931 * @return The red color component for the specified pixel, as an int. |
|
932 * |
|
933 * @throws ClassCastException If {@code inData} is not a primitive array |
|
934 * of type {@code transferType}. |
|
935 * @throws ArrayIndexOutOfBoundsException if {@code inData} is not |
|
936 * large enough to hold a pixel value for this |
|
937 * {@code ColorModel}. |
|
938 * @throws UnsupportedOperationException If the transfer type of |
|
939 * this {@code ComponentColorModel} |
|
940 * is not one of the supported transfer types: |
|
941 * {@code DataBuffer.TYPE_BYTE}, {@code DataBuffer.TYPE_USHORT}, |
|
942 * {@code DataBuffer.TYPE_INT}, {@code DataBuffer.TYPE_SHORT}, |
|
943 * {@code DataBuffer.TYPE_FLOAT}, or {@code DataBuffer.TYPE_DOUBLE}. |
|
944 */ |
|
945 public int getRed(Object inData) { |
|
946 return getRGBComponent(inData, 0); |
|
947 } |
|
948 |
|
949 |
|
950 /** |
|
951 * Returns the green color component for the specified pixel, scaled |
|
952 * from 0 to 255 in the default RGB {@code ColorSpace}, sRGB. |
|
953 * A color conversion is done if necessary. The {@code pixel} value |
|
954 * is specified by an array of data elements of type {@code transferType} |
|
955 * passed in as an object reference. The returned value is a non pre-multiplied |
|
956 * value. If the alpha is premultiplied, this method divides it out before |
|
957 * returning the value (if the alpha value is 0, the green value will be 0). |
|
958 * Since {@code ComponentColorModel} can be subclassed, |
|
959 * subclasses inherit the implementation of this method and if they |
|
960 * don't override it then they throw an exception if they use an |
|
961 * unsupported {@code transferType}. |
|
962 * |
|
963 * @param inData The pixel from which you want to get the green color component, |
|
964 * specified by an array of data elements of type {@code transferType}. |
|
965 * |
|
966 * @return The green color component for the specified pixel, as an int. |
|
967 * |
|
968 * @throws ClassCastException If {@code inData} is not a primitive array |
|
969 * of type {@code transferType}. |
|
970 * @throws ArrayIndexOutOfBoundsException if {@code inData} is not |
|
971 * large enough to hold a pixel value for this |
|
972 * {@code ColorModel}. |
|
973 * @throws UnsupportedOperationException If the transfer type of |
|
974 * this {@code ComponentColorModel} |
|
975 * is not one of the supported transfer types: |
|
976 * {@code DataBuffer.TYPE_BYTE}, {@code DataBuffer.TYPE_USHORT}, |
|
977 * {@code DataBuffer.TYPE_INT}, {@code DataBuffer.TYPE_SHORT}, |
|
978 * {@code DataBuffer.TYPE_FLOAT}, or {@code DataBuffer.TYPE_DOUBLE}. |
|
979 */ |
|
980 public int getGreen(Object inData) { |
|
981 return getRGBComponent(inData, 1); |
|
982 } |
|
983 |
|
984 |
|
985 /** |
|
986 * Returns the blue color component for the specified pixel, scaled |
|
987 * from 0 to 255 in the default RGB {@code ColorSpace}, sRGB. |
|
988 * A color conversion is done if necessary. The {@code pixel} value is |
|
989 * specified by an array of data elements of type {@code transferType} |
|
990 * passed in as an object reference. The returned value is a non pre-multiplied |
|
991 * value. If the alpha is premultiplied, this method divides it out before |
|
992 * returning the value (if the alpha value is 0, the blue value will be 0). |
|
993 * Since {@code ComponentColorModel} can be subclassed, |
|
994 * subclasses inherit the implementation of this method and if they |
|
995 * don't override it then they throw an exception if they use an |
|
996 * unsupported {@code transferType}. |
|
997 * |
|
998 * @param inData The pixel from which you want to get the blue color component, |
|
999 * specified by an array of data elements of type {@code transferType}. |
|
1000 * |
|
1001 * @return The blue color component for the specified pixel, as an int. |
|
1002 * |
|
1003 * @throws ClassCastException If {@code inData} is not a primitive array |
|
1004 * of type {@code transferType}. |
|
1005 * @throws ArrayIndexOutOfBoundsException if {@code inData} is not |
|
1006 * large enough to hold a pixel value for this |
|
1007 * {@code ColorModel}. |
|
1008 * @throws UnsupportedOperationException If the transfer type of |
|
1009 * this {@code ComponentColorModel} |
|
1010 * is not one of the supported transfer types: |
|
1011 * {@code DataBuffer.TYPE_BYTE}, {@code DataBuffer.TYPE_USHORT}, |
|
1012 * {@code DataBuffer.TYPE_INT}, {@code DataBuffer.TYPE_SHORT}, |
|
1013 * {@code DataBuffer.TYPE_FLOAT}, or {@code DataBuffer.TYPE_DOUBLE}. |
|
1014 */ |
|
1015 public int getBlue(Object inData) { |
|
1016 return getRGBComponent(inData, 2); |
|
1017 } |
|
1018 |
|
1019 /** |
|
1020 * Returns the alpha component for the specified pixel, scaled from |
|
1021 * 0 to 255. The pixel value is specified by an array of data |
|
1022 * elements of type {@code transferType} passed in as an |
|
1023 * object reference. Since {@code ComponentColorModel} can be |
|
1024 * subclassed, subclasses inherit the |
|
1025 * implementation of this method and if they don't override it then |
|
1026 * they throw an exception if they use an unsupported |
|
1027 * {@code transferType}. |
|
1028 * |
|
1029 * @param inData The pixel from which you want to get the alpha component, |
|
1030 * specified by an array of data elements of type {@code transferType}. |
|
1031 * |
|
1032 * @return The alpha component for the specified pixel, as an int. |
|
1033 * |
|
1034 * @throws ClassCastException If {@code inData} is not a primitive array |
|
1035 * of type {@code transferType}. |
|
1036 * @throws ArrayIndexOutOfBoundsException if {@code inData} is not |
|
1037 * large enough to hold a pixel value for this |
|
1038 * {@code ColorModel}. |
|
1039 * @throws UnsupportedOperationException If the transfer type of |
|
1040 * this {@code ComponentColorModel} |
|
1041 * is not one of the supported transfer types: |
|
1042 * {@code DataBuffer.TYPE_BYTE}, {@code DataBuffer.TYPE_USHORT}, |
|
1043 * {@code DataBuffer.TYPE_INT}, {@code DataBuffer.TYPE_SHORT}, |
|
1044 * {@code DataBuffer.TYPE_FLOAT}, or {@code DataBuffer.TYPE_DOUBLE}. |
|
1045 */ |
|
1046 public int getAlpha(Object inData) { |
|
1047 if (supportsAlpha == false) { |
|
1048 return 255; |
|
1049 } |
|
1050 |
|
1051 int alpha = 0; |
|
1052 int aIdx = numColorComponents; |
|
1053 int mask = (1 << nBits[aIdx]) - 1; |
|
1054 |
|
1055 switch (transferType) { |
|
1056 case DataBuffer.TYPE_SHORT: |
|
1057 short sdata[] = (short[])inData; |
|
1058 alpha = (int) ((sdata[aIdx] / 32767.0f) * 255.0f + 0.5f); |
|
1059 return alpha; |
|
1060 case DataBuffer.TYPE_FLOAT: |
|
1061 float fdata[] = (float[])inData; |
|
1062 alpha = (int) (fdata[aIdx] * 255.0f + 0.5f); |
|
1063 return alpha; |
|
1064 case DataBuffer.TYPE_DOUBLE: |
|
1065 double ddata[] = (double[])inData; |
|
1066 alpha = (int) (ddata[aIdx] * 255.0 + 0.5); |
|
1067 return alpha; |
|
1068 case DataBuffer.TYPE_BYTE: |
|
1069 byte bdata[] = (byte[])inData; |
|
1070 alpha = bdata[aIdx] & mask; |
|
1071 break; |
|
1072 case DataBuffer.TYPE_USHORT: |
|
1073 short usdata[] = (short[])inData; |
|
1074 alpha = usdata[aIdx] & mask; |
|
1075 break; |
|
1076 case DataBuffer.TYPE_INT: |
|
1077 int idata[] = (int[])inData; |
|
1078 alpha = idata[aIdx]; |
|
1079 break; |
|
1080 default: |
|
1081 throw new |
|
1082 UnsupportedOperationException("This method has not "+ |
|
1083 "been implemented for transferType " + transferType); |
|
1084 } |
|
1085 |
|
1086 if (nBits[aIdx] == 8) { |
|
1087 return alpha; |
|
1088 } else { |
|
1089 return (int) |
|
1090 ((((float) alpha) / ((float) ((1 << nBits[aIdx]) - 1))) * |
|
1091 255.0f + 0.5f); |
|
1092 } |
|
1093 } |
|
1094 |
|
1095 /** |
|
1096 * Returns the color/alpha components for the specified pixel in the |
|
1097 * default RGB color model format. A color conversion is done if |
|
1098 * necessary. The pixel value is specified by an |
|
1099 * array of data elements of type {@code transferType} passed |
|
1100 * in as an object reference. |
|
1101 * The returned value is in a non pre-multiplied format. If |
|
1102 * the alpha is premultiplied, this method divides it out of the |
|
1103 * color components (if the alpha value is 0, the color values will be 0). |
|
1104 * Since {@code ComponentColorModel} can be subclassed, |
|
1105 * subclasses inherit the implementation of this method and if they |
|
1106 * don't override it then they throw an exception if they use an |
|
1107 * unsupported {@code transferType}. |
|
1108 * |
|
1109 * @param inData The pixel from which you want to get the color/alpha components, |
|
1110 * specified by an array of data elements of type {@code transferType}. |
|
1111 * |
|
1112 * @return The color/alpha components for the specified pixel, as an int. |
|
1113 * |
|
1114 * @throws ClassCastException If {@code inData} is not a primitive array |
|
1115 * of type {@code transferType}. |
|
1116 * @throws ArrayIndexOutOfBoundsException if {@code inData} is not |
|
1117 * large enough to hold a pixel value for this |
|
1118 * {@code ColorModel}. |
|
1119 * @throws UnsupportedOperationException If the transfer type of |
|
1120 * this {@code ComponentColorModel} |
|
1121 * is not one of the supported transfer types: |
|
1122 * {@code DataBuffer.TYPE_BYTE}, {@code DataBuffer.TYPE_USHORT}, |
|
1123 * {@code DataBuffer.TYPE_INT}, {@code DataBuffer.TYPE_SHORT}, |
|
1124 * {@code DataBuffer.TYPE_FLOAT}, or {@code DataBuffer.TYPE_DOUBLE}. |
|
1125 * @see ColorModel#getRGBdefault |
|
1126 */ |
|
1127 public int getRGB(Object inData) { |
|
1128 if (needScaleInit) { |
|
1129 initScale(); |
|
1130 } |
|
1131 if (is_sRGB_stdScale || is_LinearRGB_stdScale) { |
|
1132 return (getAlpha(inData) << 24) |
|
1133 | (getRed(inData) << 16) |
|
1134 | (getGreen(inData) << 8) |
|
1135 | (getBlue(inData)); |
|
1136 } else if (colorSpaceType == ColorSpace.TYPE_GRAY) { |
|
1137 int gray = getRed(inData); // Red sRGB component should equal |
|
1138 // green and blue components |
|
1139 return (getAlpha(inData) << 24) |
|
1140 | (gray << 16) |
|
1141 | (gray << 8) |
|
1142 | gray; |
|
1143 } |
|
1144 float[] norm = getNormalizedComponents(inData, null, 0); |
|
1145 // Note that getNormalizedComponents returns non-premult values |
|
1146 float[] rgb = colorSpace.toRGB(norm); |
|
1147 return (getAlpha(inData) << 24) |
|
1148 | (((int) (rgb[0] * 255.0f + 0.5f)) << 16) |
|
1149 | (((int) (rgb[1] * 255.0f + 0.5f)) << 8) |
|
1150 | (((int) (rgb[2] * 255.0f + 0.5f)) << 0); |
|
1151 } |
|
1152 |
|
1153 /** |
|
1154 * Returns a data element array representation of a pixel in this |
|
1155 * {@code ColorModel}, given an integer pixel representation |
|
1156 * in the default RGB color model. |
|
1157 * This array can then be passed to the {@code setDataElements} |
|
1158 * method of a {@code WritableRaster} object. If the |
|
1159 * {@code pixel} |
|
1160 * parameter is null, a new array is allocated. Since |
|
1161 * {@code ComponentColorModel} can be subclassed, subclasses |
|
1162 * inherit the implementation of this method and if they don't |
|
1163 * override it then |
|
1164 * they throw an exception if they use an unsupported |
|
1165 * {@code transferType}. |
|
1166 * |
|
1167 * @param rgb the integer representation of the pixel in the RGB |
|
1168 * color model |
|
1169 * @param pixel the specified pixel |
|
1170 * @return The data element array representation of a pixel |
|
1171 * in this {@code ColorModel}. |
|
1172 * @throws ClassCastException If {@code pixel} is not null and |
|
1173 * is not a primitive array of type {@code transferType}. |
|
1174 * @throws ArrayIndexOutOfBoundsException If {@code pixel} is |
|
1175 * not large enough to hold a pixel value for this |
|
1176 * {@code ColorModel}. |
|
1177 * @throws UnsupportedOperationException If the transfer type of |
|
1178 * this {@code ComponentColorModel} |
|
1179 * is not one of the supported transfer types: |
|
1180 * {@code DataBuffer.TYPE_BYTE}, {@code DataBuffer.TYPE_USHORT}, |
|
1181 * {@code DataBuffer.TYPE_INT}, {@code DataBuffer.TYPE_SHORT}, |
|
1182 * {@code DataBuffer.TYPE_FLOAT}, or {@code DataBuffer.TYPE_DOUBLE}. |
|
1183 * |
|
1184 * @see WritableRaster#setDataElements |
|
1185 * @see SampleModel#setDataElements |
|
1186 */ |
|
1187 public Object getDataElements(int rgb, Object pixel) { |
|
1188 // REMIND: Use rendering hints? |
|
1189 |
|
1190 int red, grn, blu, alp; |
|
1191 red = (rgb>>16) & 0xff; |
|
1192 grn = (rgb>>8) & 0xff; |
|
1193 blu = rgb & 0xff; |
|
1194 |
|
1195 if (needScaleInit) { |
|
1196 initScale(); |
|
1197 } |
|
1198 if (signed) { |
|
1199 // Handle SHORT, FLOAT, & DOUBLE here |
|
1200 |
|
1201 switch(transferType) { |
|
1202 case DataBuffer.TYPE_SHORT: |
|
1203 { |
|
1204 short sdata[]; |
|
1205 if (pixel == null) { |
|
1206 sdata = new short[numComponents]; |
|
1207 } else { |
|
1208 sdata = (short[])pixel; |
|
1209 } |
|
1210 float factor; |
|
1211 if (is_sRGB_stdScale || is_LinearRGB_stdScale) { |
|
1212 factor = 32767.0f / 255.0f; |
|
1213 if (is_LinearRGB_stdScale) { |
|
1214 red = fromsRGB8LUT16[red] & 0xffff; |
|
1215 grn = fromsRGB8LUT16[grn] & 0xffff; |
|
1216 blu = fromsRGB8LUT16[blu] & 0xffff; |
|
1217 factor = 32767.0f / 65535.0f; |
|
1218 } |
|
1219 if (supportsAlpha) { |
|
1220 alp = (rgb>>24) & 0xff; |
|
1221 sdata[3] = |
|
1222 (short) (alp * (32767.0f / 255.0f) + 0.5f); |
|
1223 if (isAlphaPremultiplied) { |
|
1224 factor = alp * factor * (1.0f / 255.0f); |
|
1225 } |
|
1226 } |
|
1227 sdata[0] = (short) (red * factor + 0.5f); |
|
1228 sdata[1] = (short) (grn * factor + 0.5f); |
|
1229 sdata[2] = (short) (blu * factor + 0.5f); |
|
1230 } else if (is_LinearGray_stdScale) { |
|
1231 red = fromsRGB8LUT16[red] & 0xffff; |
|
1232 grn = fromsRGB8LUT16[grn] & 0xffff; |
|
1233 blu = fromsRGB8LUT16[blu] & 0xffff; |
|
1234 float gray = ((0.2125f * red) + |
|
1235 (0.7154f * grn) + |
|
1236 (0.0721f * blu)) / 65535.0f; |
|
1237 factor = 32767.0f; |
|
1238 if (supportsAlpha) { |
|
1239 alp = (rgb>>24) & 0xff; |
|
1240 sdata[1] = |
|
1241 (short) (alp * (32767.0f / 255.0f) + 0.5f); |
|
1242 if (isAlphaPremultiplied) { |
|
1243 factor = alp * factor * (1.0f / 255.0f); |
|
1244 } |
|
1245 } |
|
1246 sdata[0] = (short) (gray * factor + 0.5f); |
|
1247 } else if (is_ICCGray_stdScale) { |
|
1248 red = fromsRGB8LUT16[red] & 0xffff; |
|
1249 grn = fromsRGB8LUT16[grn] & 0xffff; |
|
1250 blu = fromsRGB8LUT16[blu] & 0xffff; |
|
1251 int gray = (int) ((0.2125f * red) + |
|
1252 (0.7154f * grn) + |
|
1253 (0.0721f * blu) + 0.5f); |
|
1254 gray = fromLinearGray16ToOtherGray16LUT[gray] & 0xffff; |
|
1255 factor = 32767.0f / 65535.0f; |
|
1256 if (supportsAlpha) { |
|
1257 alp = (rgb>>24) & 0xff; |
|
1258 sdata[1] = |
|
1259 (short) (alp * (32767.0f / 255.0f) + 0.5f); |
|
1260 if (isAlphaPremultiplied) { |
|
1261 factor = alp * factor * (1.0f / 255.0f); |
|
1262 } |
|
1263 } |
|
1264 sdata[0] = (short) (gray * factor + 0.5f); |
|
1265 } else { |
|
1266 factor = 1.0f / 255.0f; |
|
1267 float norm[] = new float[3]; |
|
1268 norm[0] = red * factor; |
|
1269 norm[1] = grn * factor; |
|
1270 norm[2] = blu * factor; |
|
1271 norm = colorSpace.fromRGB(norm); |
|
1272 if (nonStdScale) { |
|
1273 for (int i = 0; i < numColorComponents; i++) { |
|
1274 norm[i] = (norm[i] - compOffset[i]) * |
|
1275 compScale[i]; |
|
1276 // REMIND: need to analyze whether this |
|
1277 // clamping is necessary |
|
1278 if (norm[i] < 0.0f) { |
|
1279 norm[i] = 0.0f; |
|
1280 } |
|
1281 if (norm[i] > 1.0f) { |
|
1282 norm[i] = 1.0f; |
|
1283 } |
|
1284 } |
|
1285 } |
|
1286 factor = 32767.0f; |
|
1287 if (supportsAlpha) { |
|
1288 alp = (rgb>>24) & 0xff; |
|
1289 sdata[numColorComponents] = |
|
1290 (short) (alp * (32767.0f / 255.0f) + 0.5f); |
|
1291 if (isAlphaPremultiplied) { |
|
1292 factor *= alp * (1.0f / 255.0f); |
|
1293 } |
|
1294 } |
|
1295 for (int i = 0; i < numColorComponents; i++) { |
|
1296 sdata[i] = (short) (norm[i] * factor + 0.5f); |
|
1297 } |
|
1298 } |
|
1299 return sdata; |
|
1300 } |
|
1301 case DataBuffer.TYPE_FLOAT: |
|
1302 { |
|
1303 float fdata[]; |
|
1304 if (pixel == null) { |
|
1305 fdata = new float[numComponents]; |
|
1306 } else { |
|
1307 fdata = (float[])pixel; |
|
1308 } |
|
1309 float factor; |
|
1310 if (is_sRGB_stdScale || is_LinearRGB_stdScale) { |
|
1311 if (is_LinearRGB_stdScale) { |
|
1312 red = fromsRGB8LUT16[red] & 0xffff; |
|
1313 grn = fromsRGB8LUT16[grn] & 0xffff; |
|
1314 blu = fromsRGB8LUT16[blu] & 0xffff; |
|
1315 factor = 1.0f / 65535.0f; |
|
1316 } else { |
|
1317 factor = 1.0f / 255.0f; |
|
1318 } |
|
1319 if (supportsAlpha) { |
|
1320 alp = (rgb>>24) & 0xff; |
|
1321 fdata[3] = alp * (1.0f / 255.0f); |
|
1322 if (isAlphaPremultiplied) { |
|
1323 factor *= fdata[3]; |
|
1324 } |
|
1325 } |
|
1326 fdata[0] = red * factor; |
|
1327 fdata[1] = grn * factor; |
|
1328 fdata[2] = blu * factor; |
|
1329 } else if (is_LinearGray_stdScale) { |
|
1330 red = fromsRGB8LUT16[red] & 0xffff; |
|
1331 grn = fromsRGB8LUT16[grn] & 0xffff; |
|
1332 blu = fromsRGB8LUT16[blu] & 0xffff; |
|
1333 fdata[0] = ((0.2125f * red) + |
|
1334 (0.7154f * grn) + |
|
1335 (0.0721f * blu)) / 65535.0f; |
|
1336 if (supportsAlpha) { |
|
1337 alp = (rgb>>24) & 0xff; |
|
1338 fdata[1] = alp * (1.0f / 255.0f); |
|
1339 if (isAlphaPremultiplied) { |
|
1340 fdata[0] *= fdata[1]; |
|
1341 } |
|
1342 } |
|
1343 } else if (is_ICCGray_stdScale) { |
|
1344 red = fromsRGB8LUT16[red] & 0xffff; |
|
1345 grn = fromsRGB8LUT16[grn] & 0xffff; |
|
1346 blu = fromsRGB8LUT16[blu] & 0xffff; |
|
1347 int gray = (int) ((0.2125f * red) + |
|
1348 (0.7154f * grn) + |
|
1349 (0.0721f * blu) + 0.5f); |
|
1350 fdata[0] = (fromLinearGray16ToOtherGray16LUT[gray] & |
|
1351 0xffff) / 65535.0f; |
|
1352 if (supportsAlpha) { |
|
1353 alp = (rgb>>24) & 0xff; |
|
1354 fdata[1] = alp * (1.0f / 255.0f); |
|
1355 if (isAlphaPremultiplied) { |
|
1356 fdata[0] *= fdata[1]; |
|
1357 } |
|
1358 } |
|
1359 } else { |
|
1360 float norm[] = new float[3]; |
|
1361 factor = 1.0f / 255.0f; |
|
1362 norm[0] = red * factor; |
|
1363 norm[1] = grn * factor; |
|
1364 norm[2] = blu * factor; |
|
1365 norm = colorSpace.fromRGB(norm); |
|
1366 if (supportsAlpha) { |
|
1367 alp = (rgb>>24) & 0xff; |
|
1368 fdata[numColorComponents] = alp * factor; |
|
1369 if (isAlphaPremultiplied) { |
|
1370 factor *= alp; |
|
1371 for (int i = 0; i < numColorComponents; i++) { |
|
1372 norm[i] *= factor; |
|
1373 } |
|
1374 } |
|
1375 } |
|
1376 for (int i = 0; i < numColorComponents; i++) { |
|
1377 fdata[i] = norm[i]; |
|
1378 } |
|
1379 } |
|
1380 return fdata; |
|
1381 } |
|
1382 case DataBuffer.TYPE_DOUBLE: |
|
1383 { |
|
1384 double ddata[]; |
|
1385 if (pixel == null) { |
|
1386 ddata = new double[numComponents]; |
|
1387 } else { |
|
1388 ddata = (double[])pixel; |
|
1389 } |
|
1390 if (is_sRGB_stdScale || is_LinearRGB_stdScale) { |
|
1391 double factor; |
|
1392 if (is_LinearRGB_stdScale) { |
|
1393 red = fromsRGB8LUT16[red] & 0xffff; |
|
1394 grn = fromsRGB8LUT16[grn] & 0xffff; |
|
1395 blu = fromsRGB8LUT16[blu] & 0xffff; |
|
1396 factor = 1.0 / 65535.0; |
|
1397 } else { |
|
1398 factor = 1.0 / 255.0; |
|
1399 } |
|
1400 if (supportsAlpha) { |
|
1401 alp = (rgb>>24) & 0xff; |
|
1402 ddata[3] = alp * (1.0 / 255.0); |
|
1403 if (isAlphaPremultiplied) { |
|
1404 factor *= ddata[3]; |
|
1405 } |
|
1406 } |
|
1407 ddata[0] = red * factor; |
|
1408 ddata[1] = grn * factor; |
|
1409 ddata[2] = blu * factor; |
|
1410 } else if (is_LinearGray_stdScale) { |
|
1411 red = fromsRGB8LUT16[red] & 0xffff; |
|
1412 grn = fromsRGB8LUT16[grn] & 0xffff; |
|
1413 blu = fromsRGB8LUT16[blu] & 0xffff; |
|
1414 ddata[0] = ((0.2125 * red) + |
|
1415 (0.7154 * grn) + |
|
1416 (0.0721 * blu)) / 65535.0; |
|
1417 if (supportsAlpha) { |
|
1418 alp = (rgb>>24) & 0xff; |
|
1419 ddata[1] = alp * (1.0 / 255.0); |
|
1420 if (isAlphaPremultiplied) { |
|
1421 ddata[0] *= ddata[1]; |
|
1422 } |
|
1423 } |
|
1424 } else if (is_ICCGray_stdScale) { |
|
1425 red = fromsRGB8LUT16[red] & 0xffff; |
|
1426 grn = fromsRGB8LUT16[grn] & 0xffff; |
|
1427 blu = fromsRGB8LUT16[blu] & 0xffff; |
|
1428 int gray = (int) ((0.2125f * red) + |
|
1429 (0.7154f * grn) + |
|
1430 (0.0721f * blu) + 0.5f); |
|
1431 ddata[0] = (fromLinearGray16ToOtherGray16LUT[gray] & |
|
1432 0xffff) / 65535.0; |
|
1433 if (supportsAlpha) { |
|
1434 alp = (rgb>>24) & 0xff; |
|
1435 ddata[1] = alp * (1.0 / 255.0); |
|
1436 if (isAlphaPremultiplied) { |
|
1437 ddata[0] *= ddata[1]; |
|
1438 } |
|
1439 } |
|
1440 } else { |
|
1441 float factor = 1.0f / 255.0f; |
|
1442 float norm[] = new float[3]; |
|
1443 norm[0] = red * factor; |
|
1444 norm[1] = grn * factor; |
|
1445 norm[2] = blu * factor; |
|
1446 norm = colorSpace.fromRGB(norm); |
|
1447 if (supportsAlpha) { |
|
1448 alp = (rgb>>24) & 0xff; |
|
1449 ddata[numColorComponents] = alp * (1.0 / 255.0); |
|
1450 if (isAlphaPremultiplied) { |
|
1451 factor *= alp; |
|
1452 for (int i = 0; i < numColorComponents; i++) { |
|
1453 norm[i] *= factor; |
|
1454 } |
|
1455 } |
|
1456 } |
|
1457 for (int i = 0; i < numColorComponents; i++) { |
|
1458 ddata[i] = norm[i]; |
|
1459 } |
|
1460 } |
|
1461 return ddata; |
|
1462 } |
|
1463 } |
|
1464 } |
|
1465 |
|
1466 // Handle BYTE, USHORT, & INT here |
|
1467 //REMIND: maybe more efficient not to use int array for |
|
1468 //DataBuffer.TYPE_USHORT and DataBuffer.TYPE_INT |
|
1469 int intpixel[]; |
|
1470 if (transferType == DataBuffer.TYPE_INT && |
|
1471 pixel != null) { |
|
1472 intpixel = (int[])pixel; |
|
1473 } else { |
|
1474 intpixel = new int[numComponents]; |
|
1475 } |
|
1476 |
|
1477 if (is_sRGB_stdScale || is_LinearRGB_stdScale) { |
|
1478 int precision; |
|
1479 float factor; |
|
1480 if (is_LinearRGB_stdScale) { |
|
1481 if (transferType == DataBuffer.TYPE_BYTE) { |
|
1482 red = fromsRGB8LUT8[red] & 0xff; |
|
1483 grn = fromsRGB8LUT8[grn] & 0xff; |
|
1484 blu = fromsRGB8LUT8[blu] & 0xff; |
|
1485 precision = 8; |
|
1486 factor = 1.0f / 255.0f; |
|
1487 } else { |
|
1488 red = fromsRGB8LUT16[red] & 0xffff; |
|
1489 grn = fromsRGB8LUT16[grn] & 0xffff; |
|
1490 blu = fromsRGB8LUT16[blu] & 0xffff; |
|
1491 precision = 16; |
|
1492 factor = 1.0f / 65535.0f; |
|
1493 } |
|
1494 } else { |
|
1495 precision = 8; |
|
1496 factor = 1.0f / 255.0f; |
|
1497 } |
|
1498 if (supportsAlpha) { |
|
1499 alp = (rgb>>24)&0xff; |
|
1500 if (nBits[3] == 8) { |
|
1501 intpixel[3] = alp; |
|
1502 } |
|
1503 else { |
|
1504 intpixel[3] = (int) |
|
1505 (alp * (1.0f / 255.0f) * ((1<<nBits[3]) - 1) + 0.5f); |
|
1506 } |
|
1507 if (isAlphaPremultiplied) { |
|
1508 factor *= (alp * (1.0f / 255.0f)); |
|
1509 precision = -1; // force component calculations below |
|
1510 } |
|
1511 } |
|
1512 if (nBits[0] == precision) { |
|
1513 intpixel[0] = red; |
|
1514 } |
|
1515 else { |
|
1516 intpixel[0] = (int) (red * factor * ((1<<nBits[0]) - 1) + 0.5f); |
|
1517 } |
|
1518 if (nBits[1] == precision) { |
|
1519 intpixel[1] = grn; |
|
1520 } |
|
1521 else { |
|
1522 intpixel[1] = (int) (grn * factor * ((1<<nBits[1]) - 1) + 0.5f); |
|
1523 } |
|
1524 if (nBits[2] == precision) { |
|
1525 intpixel[2] = blu; |
|
1526 } |
|
1527 else { |
|
1528 intpixel[2] = (int) (blu * factor * ((1<<nBits[2]) - 1) + 0.5f); |
|
1529 } |
|
1530 } else if (is_LinearGray_stdScale) { |
|
1531 red = fromsRGB8LUT16[red] & 0xffff; |
|
1532 grn = fromsRGB8LUT16[grn] & 0xffff; |
|
1533 blu = fromsRGB8LUT16[blu] & 0xffff; |
|
1534 float gray = ((0.2125f * red) + |
|
1535 (0.7154f * grn) + |
|
1536 (0.0721f * blu)) / 65535.0f; |
|
1537 if (supportsAlpha) { |
|
1538 alp = (rgb>>24) & 0xff; |
|
1539 if (nBits[1] == 8) { |
|
1540 intpixel[1] = alp; |
|
1541 } else { |
|
1542 intpixel[1] = (int) (alp * (1.0f / 255.0f) * |
|
1543 ((1 << nBits[1]) - 1) + 0.5f); |
|
1544 } |
|
1545 if (isAlphaPremultiplied) { |
|
1546 gray *= (alp * (1.0f / 255.0f)); |
|
1547 } |
|
1548 } |
|
1549 intpixel[0] = (int) (gray * ((1 << nBits[0]) - 1) + 0.5f); |
|
1550 } else if (is_ICCGray_stdScale) { |
|
1551 red = fromsRGB8LUT16[red] & 0xffff; |
|
1552 grn = fromsRGB8LUT16[grn] & 0xffff; |
|
1553 blu = fromsRGB8LUT16[blu] & 0xffff; |
|
1554 int gray16 = (int) ((0.2125f * red) + |
|
1555 (0.7154f * grn) + |
|
1556 (0.0721f * blu) + 0.5f); |
|
1557 float gray = (fromLinearGray16ToOtherGray16LUT[gray16] & |
|
1558 0xffff) / 65535.0f; |
|
1559 if (supportsAlpha) { |
|
1560 alp = (rgb>>24) & 0xff; |
|
1561 if (nBits[1] == 8) { |
|
1562 intpixel[1] = alp; |
|
1563 } else { |
|
1564 intpixel[1] = (int) (alp * (1.0f / 255.0f) * |
|
1565 ((1 << nBits[1]) - 1) + 0.5f); |
|
1566 } |
|
1567 if (isAlphaPremultiplied) { |
|
1568 gray *= (alp * (1.0f / 255.0f)); |
|
1569 } |
|
1570 } |
|
1571 intpixel[0] = (int) (gray * ((1 << nBits[0]) - 1) + 0.5f); |
|
1572 } else { |
|
1573 // Need to convert the color |
|
1574 float[] norm = new float[3]; |
|
1575 float factor = 1.0f / 255.0f; |
|
1576 norm[0] = red * factor; |
|
1577 norm[1] = grn * factor; |
|
1578 norm[2] = blu * factor; |
|
1579 norm = colorSpace.fromRGB(norm); |
|
1580 if (nonStdScale) { |
|
1581 for (int i = 0; i < numColorComponents; i++) { |
|
1582 norm[i] = (norm[i] - compOffset[i]) * |
|
1583 compScale[i]; |
|
1584 // REMIND: need to analyze whether this |
|
1585 // clamping is necessary |
|
1586 if (norm[i] < 0.0f) { |
|
1587 norm[i] = 0.0f; |
|
1588 } |
|
1589 if (norm[i] > 1.0f) { |
|
1590 norm[i] = 1.0f; |
|
1591 } |
|
1592 } |
|
1593 } |
|
1594 if (supportsAlpha) { |
|
1595 alp = (rgb>>24) & 0xff; |
|
1596 if (nBits[numColorComponents] == 8) { |
|
1597 intpixel[numColorComponents] = alp; |
|
1598 } |
|
1599 else { |
|
1600 intpixel[numColorComponents] = |
|
1601 (int) (alp * factor * |
|
1602 ((1<<nBits[numColorComponents]) - 1) + 0.5f); |
|
1603 } |
|
1604 if (isAlphaPremultiplied) { |
|
1605 factor *= alp; |
|
1606 for (int i = 0; i < numColorComponents; i++) { |
|
1607 norm[i] *= factor; |
|
1608 } |
|
1609 } |
|
1610 } |
|
1611 for (int i = 0; i < numColorComponents; i++) { |
|
1612 intpixel[i] = (int) (norm[i] * ((1<<nBits[i]) - 1) + 0.5f); |
|
1613 } |
|
1614 } |
|
1615 |
|
1616 switch (transferType) { |
|
1617 case DataBuffer.TYPE_BYTE: { |
|
1618 byte bdata[]; |
|
1619 if (pixel == null) { |
|
1620 bdata = new byte[numComponents]; |
|
1621 } else { |
|
1622 bdata = (byte[])pixel; |
|
1623 } |
|
1624 for (int i = 0; i < numComponents; i++) { |
|
1625 bdata[i] = (byte)(0xff&intpixel[i]); |
|
1626 } |
|
1627 return bdata; |
|
1628 } |
|
1629 case DataBuffer.TYPE_USHORT:{ |
|
1630 short sdata[]; |
|
1631 if (pixel == null) { |
|
1632 sdata = new short[numComponents]; |
|
1633 } else { |
|
1634 sdata = (short[])pixel; |
|
1635 } |
|
1636 for (int i = 0; i < numComponents; i++) { |
|
1637 sdata[i] = (short)(intpixel[i]&0xffff); |
|
1638 } |
|
1639 return sdata; |
|
1640 } |
|
1641 case DataBuffer.TYPE_INT: |
|
1642 if (maxBits > 23) { |
|
1643 // fix 4412670 - for components of 24 or more bits |
|
1644 // some calculations done above with float precision |
|
1645 // may lose enough precision that the integer result |
|
1646 // overflows nBits, so we need to clamp. |
|
1647 for (int i = 0; i < numComponents; i++) { |
|
1648 if (intpixel[i] > ((1<<nBits[i]) - 1)) { |
|
1649 intpixel[i] = (1<<nBits[i]) - 1; |
|
1650 } |
|
1651 } |
|
1652 } |
|
1653 return intpixel; |
|
1654 } |
|
1655 throw new IllegalArgumentException("This method has not been "+ |
|
1656 "implemented for transferType " + transferType); |
|
1657 } |
|
1658 |
|
1659 /** Returns an array of unnormalized color/alpha components given a pixel |
|
1660 * in this {@code ColorModel}. |
|
1661 * An IllegalArgumentException is thrown if the component value for this |
|
1662 * {@code ColorModel} is not conveniently representable in the |
|
1663 * unnormalized form. Color/alpha components are stored |
|
1664 * in the {@code components} array starting at {@code offset} |
|
1665 * (even if the array is allocated by this method). |
|
1666 * |
|
1667 * @param pixel The pixel value specified as an integer. |
|
1668 * @param components An integer array in which to store the unnormalized |
|
1669 * color/alpha components. If the {@code components} array is null, |
|
1670 * a new array is allocated. |
|
1671 * @param offset An offset into the {@code components} array. |
|
1672 * |
|
1673 * @return The components array. |
|
1674 * |
|
1675 * @throws IllegalArgumentException If there is more than one |
|
1676 * component in this {@code ColorModel}. |
|
1677 * @throws IllegalArgumentException If this |
|
1678 * {@code ColorModel} does not support the unnormalized form |
|
1679 * @throws ArrayIndexOutOfBoundsException If the {@code components} |
|
1680 * array is not null and is not large enough to hold all the color and |
|
1681 * alpha components (starting at offset). |
|
1682 */ |
|
1683 public int[] getComponents(int pixel, int[] components, int offset) { |
|
1684 if (numComponents > 1) { |
|
1685 throw new |
|
1686 IllegalArgumentException("More than one component per pixel"); |
|
1687 } |
|
1688 if (needScaleInit) { |
|
1689 initScale(); |
|
1690 } |
|
1691 if (noUnnorm) { |
|
1692 throw new |
|
1693 IllegalArgumentException( |
|
1694 "This ColorModel does not support the unnormalized form"); |
|
1695 } |
|
1696 if (components == null) { |
|
1697 components = new int[offset+1]; |
|
1698 } |
|
1699 |
|
1700 components[offset+0] = (pixel & ((1<<nBits[0]) - 1)); |
|
1701 return components; |
|
1702 } |
|
1703 |
|
1704 /** |
|
1705 * Returns an array of unnormalized color/alpha components given a pixel |
|
1706 * in this {@code ColorModel}. The pixel value is specified by an |
|
1707 * array of data elements of type {@code transferType} passed in as |
|
1708 * an object reference. |
|
1709 * An IllegalArgumentException is thrown if the component values for this |
|
1710 * {@code ColorModel} are not conveniently representable in the |
|
1711 * unnormalized form. |
|
1712 * Color/alpha components are stored in the {@code components} array |
|
1713 * starting at {@code offset} (even if the array is allocated by |
|
1714 * this method). Since {@code ComponentColorModel} can be |
|
1715 * subclassed, subclasses inherit the |
|
1716 * implementation of this method and if they don't override it then |
|
1717 * this method might throw an exception if they use an unsupported |
|
1718 * {@code transferType}. |
|
1719 * |
|
1720 * @param pixel A pixel value specified by an array of data elements of |
|
1721 * type {@code transferType}. |
|
1722 * @param components An integer array in which to store the unnormalized |
|
1723 * color/alpha components. If the {@code components} array is null, |
|
1724 * a new array is allocated. |
|
1725 * @param offset An offset into the {@code components} array. |
|
1726 * |
|
1727 * @return The {@code components} array. |
|
1728 * |
|
1729 * @throws IllegalArgumentException If this |
|
1730 * {@code ComponentColorModel} does not support the unnormalized form |
|
1731 * @throws UnsupportedOperationException in some cases iff the |
|
1732 * transfer type of this {@code ComponentColorModel} |
|
1733 * is not one of the following transfer types: |
|
1734 * {@code DataBuffer.TYPE_BYTE}, {@code DataBuffer.TYPE_USHORT}, |
|
1735 * or {@code DataBuffer.TYPE_INT}. |
|
1736 * @throws ClassCastException If {@code pixel} is not a primitive |
|
1737 * array of type {@code transferType}. |
|
1738 * @throws IllegalArgumentException If the {@code components} array is |
|
1739 * not null and is not large enough to hold all the color and alpha |
|
1740 * components (starting at offset), or if {@code pixel} is not large |
|
1741 * enough to hold a pixel value for this ColorModel. |
|
1742 */ |
|
1743 public int[] getComponents(Object pixel, int[] components, int offset) { |
|
1744 int intpixel[]; |
|
1745 if (needScaleInit) { |
|
1746 initScale(); |
|
1747 } |
|
1748 if (noUnnorm) { |
|
1749 throw new |
|
1750 IllegalArgumentException( |
|
1751 "This ColorModel does not support the unnormalized form"); |
|
1752 } |
|
1753 if (pixel instanceof int[]) { |
|
1754 intpixel = (int[])pixel; |
|
1755 } else { |
|
1756 intpixel = DataBuffer.toIntArray(pixel); |
|
1757 if (intpixel == null) { |
|
1758 throw new UnsupportedOperationException("This method has not been "+ |
|
1759 "implemented for transferType " + transferType); |
|
1760 } |
|
1761 } |
|
1762 if (intpixel.length < numComponents) { |
|
1763 throw new IllegalArgumentException |
|
1764 ("Length of pixel array < number of components in model"); |
|
1765 } |
|
1766 if (components == null) { |
|
1767 components = new int[offset+numComponents]; |
|
1768 } |
|
1769 else if ((components.length-offset) < numComponents) { |
|
1770 throw new IllegalArgumentException |
|
1771 ("Length of components array < number of components in model"); |
|
1772 } |
|
1773 System.arraycopy(intpixel, 0, components, offset, numComponents); |
|
1774 |
|
1775 return components; |
|
1776 } |
|
1777 |
|
1778 /** |
|
1779 * Returns an array of all of the color/alpha components in unnormalized |
|
1780 * form, given a normalized component array. Unnormalized components |
|
1781 * are unsigned integral values between 0 and 2<sup>n</sup> - 1, where |
|
1782 * n is the number of bits for a particular component. Normalized |
|
1783 * components are float values between a per component minimum and |
|
1784 * maximum specified by the {@code ColorSpace} object for this |
|
1785 * {@code ColorModel}. An {@code IllegalArgumentException} |
|
1786 * will be thrown if color component values for this |
|
1787 * {@code ColorModel} are not conveniently representable in the |
|
1788 * unnormalized form. If the |
|
1789 * {@code components} array is {@code null}, a new array |
|
1790 * will be allocated. The {@code components} array will |
|
1791 * be returned. Color/alpha components are stored in the |
|
1792 * {@code components} array starting at {@code offset} (even |
|
1793 * if the array is allocated by this method). An |
|
1794 * {@code ArrayIndexOutOfBoundsException} is thrown if the |
|
1795 * {@code components} array is not {@code null} and is not |
|
1796 * large enough to hold all the color and alpha |
|
1797 * components (starting at {@code offset}). An |
|
1798 * {@code IllegalArgumentException} is thrown if the |
|
1799 * {@code normComponents} array is not large enough to hold |
|
1800 * all the color and alpha components starting at |
|
1801 * {@code normOffset}. |
|
1802 * @param normComponents an array containing normalized components |
|
1803 * @param normOffset the offset into the {@code normComponents} |
|
1804 * array at which to start retrieving normalized components |
|
1805 * @param components an array that receives the components from |
|
1806 * {@code normComponents} |
|
1807 * @param offset the index into {@code components} at which to |
|
1808 * begin storing normalized components from |
|
1809 * {@code normComponents} |
|
1810 * @return an array containing unnormalized color and alpha |
|
1811 * components. |
|
1812 * @throws IllegalArgumentException If this |
|
1813 * {@code ComponentColorModel} does not support the unnormalized form |
|
1814 * @throws IllegalArgumentException if the length of |
|
1815 * {@code normComponents} minus {@code normOffset} |
|
1816 * is less than {@code numComponents} |
|
1817 */ |
|
1818 public int[] getUnnormalizedComponents(float[] normComponents, |
|
1819 int normOffset, |
|
1820 int[] components, int offset) { |
|
1821 if (needScaleInit) { |
|
1822 initScale(); |
|
1823 } |
|
1824 if (noUnnorm) { |
|
1825 throw new |
|
1826 IllegalArgumentException( |
|
1827 "This ColorModel does not support the unnormalized form"); |
|
1828 } |
|
1829 return super.getUnnormalizedComponents(normComponents, normOffset, |
|
1830 components, offset); |
|
1831 } |
|
1832 |
|
1833 /** |
|
1834 * Returns an array of all of the color/alpha components in normalized |
|
1835 * form, given an unnormalized component array. Unnormalized components |
|
1836 * are unsigned integral values between 0 and 2<sup>n</sup> - 1, where |
|
1837 * n is the number of bits for a particular component. Normalized |
|
1838 * components are float values between a per component minimum and |
|
1839 * maximum specified by the {@code ColorSpace} object for this |
|
1840 * {@code ColorModel}. An {@code IllegalArgumentException} |
|
1841 * will be thrown if color component values for this |
|
1842 * {@code ColorModel} are not conveniently representable in the |
|
1843 * unnormalized form. If the |
|
1844 * {@code normComponents} array is {@code null}, a new array |
|
1845 * will be allocated. The {@code normComponents} array |
|
1846 * will be returned. Color/alpha components are stored in the |
|
1847 * {@code normComponents} array starting at |
|
1848 * {@code normOffset} (even if the array is allocated by this |
|
1849 * method). An {@code ArrayIndexOutOfBoundsException} is thrown |
|
1850 * if the {@code normComponents} array is not {@code null} |
|
1851 * and is not large enough to hold all the color and alpha components |
|
1852 * (starting at {@code normOffset}). An |
|
1853 * {@code IllegalArgumentException} is thrown if the |
|
1854 * {@code components} array is not large enough to hold all the |
|
1855 * color and alpha components starting at {@code offset}. |
|
1856 * @param components an array containing unnormalized components |
|
1857 * @param offset the offset into the {@code components} array at |
|
1858 * which to start retrieving unnormalized components |
|
1859 * @param normComponents an array that receives the normalized components |
|
1860 * @param normOffset the index into {@code normComponents} at |
|
1861 * which to begin storing normalized components |
|
1862 * @return an array containing normalized color and alpha |
|
1863 * components. |
|
1864 * @throws IllegalArgumentException If this |
|
1865 * {@code ComponentColorModel} does not support the unnormalized form |
|
1866 */ |
|
1867 public float[] getNormalizedComponents(int[] components, int offset, |
|
1868 float[] normComponents, |
|
1869 int normOffset) { |
|
1870 if (needScaleInit) { |
|
1871 initScale(); |
|
1872 } |
|
1873 if (noUnnorm) { |
|
1874 throw new |
|
1875 IllegalArgumentException( |
|
1876 "This ColorModel does not support the unnormalized form"); |
|
1877 } |
|
1878 return super.getNormalizedComponents(components, offset, |
|
1879 normComponents, normOffset); |
|
1880 } |
|
1881 |
|
1882 /** |
|
1883 * Returns a pixel value represented as an int in this {@code ColorModel}, |
|
1884 * given an array of unnormalized color/alpha components. |
|
1885 * |
|
1886 * @param components An array of unnormalized color/alpha components. |
|
1887 * @param offset An offset into the {@code components} array. |
|
1888 * |
|
1889 * @return A pixel value represented as an int. |
|
1890 * |
|
1891 * @throws IllegalArgumentException If there is more than one component |
|
1892 * in this {@code ColorModel}. |
|
1893 * @throws IllegalArgumentException If this |
|
1894 * {@code ComponentColorModel} does not support the unnormalized form |
|
1895 */ |
|
1896 public int getDataElement(int[] components, int offset) { |
|
1897 if (needScaleInit) { |
|
1898 initScale(); |
|
1899 } |
|
1900 if (numComponents == 1) { |
|
1901 if (noUnnorm) { |
|
1902 throw new |
|
1903 IllegalArgumentException( |
|
1904 "This ColorModel does not support the unnormalized form"); |
|
1905 } |
|
1906 return components[offset+0]; |
|
1907 } |
|
1908 throw new IllegalArgumentException("This model returns "+ |
|
1909 numComponents+ |
|
1910 " elements in the pixel array."); |
|
1911 } |
|
1912 |
|
1913 /** |
|
1914 * Returns a data element array representation of a pixel in this |
|
1915 * {@code ColorModel}, given an array of unnormalized color/alpha |
|
1916 * components. This array can then be passed to the {@code setDataElements} |
|
1917 * method of a {@code WritableRaster} object. |
|
1918 * |
|
1919 * @param components An array of unnormalized color/alpha components. |
|
1920 * @param offset The integer offset into the {@code components} array. |
|
1921 * @param obj The object in which to store the data element array |
|
1922 * representation of the pixel. If {@code obj} variable is null, |
|
1923 * a new array is allocated. If {@code obj} is not null, it must |
|
1924 * be a primitive array of type {@code transferType}. An |
|
1925 * {@code ArrayIndexOutOfBoundsException} is thrown if |
|
1926 * {@code obj} is not large enough to hold a pixel value |
|
1927 * for this {@code ColorModel}. Since |
|
1928 * {@code ComponentColorModel} can be subclassed, subclasses |
|
1929 * inherit the implementation of this method and if they don't |
|
1930 * override it then they throw an exception if they use an |
|
1931 * unsupported {@code transferType}. |
|
1932 * |
|
1933 * @return The data element array representation of a pixel |
|
1934 * in this {@code ColorModel}. |
|
1935 * |
|
1936 * @throws IllegalArgumentException If the components array |
|
1937 * is not large enough to hold all the color and alpha components |
|
1938 * (starting at offset). |
|
1939 * @throws ClassCastException If {@code obj} is not null and is not a |
|
1940 * primitive array of type {@code transferType}. |
|
1941 * @throws ArrayIndexOutOfBoundsException If {@code obj} is not large |
|
1942 * enough to hold a pixel value for this {@code ColorModel}. |
|
1943 * @throws IllegalArgumentException If this |
|
1944 * {@code ComponentColorModel} does not support the unnormalized form |
|
1945 * @throws UnsupportedOperationException If the transfer type of |
|
1946 * this {@code ComponentColorModel} |
|
1947 * is not one of the following transfer types: |
|
1948 * {@code DataBuffer.TYPE_BYTE}, {@code DataBuffer.TYPE_USHORT}, |
|
1949 * or {@code DataBuffer.TYPE_INT}. |
|
1950 * |
|
1951 * @see WritableRaster#setDataElements |
|
1952 * @see SampleModel#setDataElements |
|
1953 */ |
|
1954 public Object getDataElements(int[] components, int offset, Object obj) { |
|
1955 if (needScaleInit) { |
|
1956 initScale(); |
|
1957 } |
|
1958 if (noUnnorm) { |
|
1959 throw new |
|
1960 IllegalArgumentException( |
|
1961 "This ColorModel does not support the unnormalized form"); |
|
1962 } |
|
1963 if ((components.length-offset) < numComponents) { |
|
1964 throw new IllegalArgumentException("Component array too small"+ |
|
1965 " (should be "+numComponents); |
|
1966 } |
|
1967 switch(transferType) { |
|
1968 case DataBuffer.TYPE_INT: |
|
1969 { |
|
1970 int[] pixel; |
|
1971 if (obj == null) { |
|
1972 pixel = new int[numComponents]; |
|
1973 } |
|
1974 else { |
|
1975 pixel = (int[]) obj; |
|
1976 } |
|
1977 System.arraycopy(components, offset, pixel, 0, |
|
1978 numComponents); |
|
1979 return pixel; |
|
1980 } |
|
1981 |
|
1982 case DataBuffer.TYPE_BYTE: |
|
1983 { |
|
1984 byte[] pixel; |
|
1985 if (obj == null) { |
|
1986 pixel = new byte[numComponents]; |
|
1987 } |
|
1988 else { |
|
1989 pixel = (byte[]) obj; |
|
1990 } |
|
1991 for (int i=0; i < numComponents; i++) { |
|
1992 pixel[i] = (byte) (components[offset+i]&0xff); |
|
1993 } |
|
1994 return pixel; |
|
1995 } |
|
1996 |
|
1997 case DataBuffer.TYPE_USHORT: |
|
1998 { |
|
1999 short[] pixel; |
|
2000 if (obj == null) { |
|
2001 pixel = new short[numComponents]; |
|
2002 } |
|
2003 else { |
|
2004 pixel = (short[]) obj; |
|
2005 } |
|
2006 for (int i=0; i < numComponents; i++) { |
|
2007 pixel[i] = (short) (components[offset+i]&0xffff); |
|
2008 } |
|
2009 return pixel; |
|
2010 } |
|
2011 |
|
2012 default: |
|
2013 throw new UnsupportedOperationException("This method has not been "+ |
|
2014 "implemented for transferType " + |
|
2015 transferType); |
|
2016 } |
|
2017 } |
|
2018 |
|
2019 /** |
|
2020 * Returns a pixel value represented as an {@code int} in this |
|
2021 * {@code ColorModel}, given an array of normalized color/alpha |
|
2022 * components. This method will throw an |
|
2023 * {@code IllegalArgumentException} if pixel values for this |
|
2024 * {@code ColorModel} are not conveniently representable as a |
|
2025 * single {@code int}. An |
|
2026 * {@code ArrayIndexOutOfBoundsException} is thrown if the |
|
2027 * {@code normComponents} array is not large enough to hold all the |
|
2028 * color and alpha components (starting at {@code normOffset}). |
|
2029 * @param normComponents an array of normalized color and alpha |
|
2030 * components |
|
2031 * @param normOffset the index into {@code normComponents} at which to |
|
2032 * begin retrieving the color and alpha components |
|
2033 * @return an {@code int} pixel value in this |
|
2034 * {@code ColorModel} corresponding to the specified components. |
|
2035 * @throws IllegalArgumentException if |
|
2036 * pixel values for this {@code ColorModel} are not |
|
2037 * conveniently representable as a single {@code int} |
|
2038 * @throws ArrayIndexOutOfBoundsException if |
|
2039 * the {@code normComponents} array is not large enough to |
|
2040 * hold all of the color and alpha components starting at |
|
2041 * {@code normOffset} |
|
2042 * @since 1.4 |
|
2043 */ |
|
2044 public int getDataElement(float[] normComponents, int normOffset) { |
|
2045 if (numComponents > 1) { |
|
2046 throw new |
|
2047 IllegalArgumentException("More than one component per pixel"); |
|
2048 } |
|
2049 if (signed) { |
|
2050 throw new |
|
2051 IllegalArgumentException("Component value is signed"); |
|
2052 } |
|
2053 if (needScaleInit) { |
|
2054 initScale(); |
|
2055 } |
|
2056 Object pixel = getDataElements(normComponents, normOffset, null); |
|
2057 switch (transferType) { |
|
2058 case DataBuffer.TYPE_BYTE: |
|
2059 { |
|
2060 byte bpixel[] = (byte[]) pixel; |
|
2061 return bpixel[0] & 0xff; |
|
2062 } |
|
2063 case DataBuffer.TYPE_USHORT: |
|
2064 { |
|
2065 short[] uspixel = (short[]) pixel; |
|
2066 return uspixel[0] & 0xffff; |
|
2067 } |
|
2068 case DataBuffer.TYPE_INT: |
|
2069 { |
|
2070 int[] ipixel = (int[]) pixel; |
|
2071 return ipixel[0]; |
|
2072 } |
|
2073 default: |
|
2074 throw new UnsupportedOperationException("This method has not been " |
|
2075 + "implemented for transferType " + transferType); |
|
2076 } |
|
2077 } |
|
2078 |
|
2079 /** |
|
2080 * Returns a data element array representation of a pixel in this |
|
2081 * {@code ColorModel}, given an array of normalized color/alpha |
|
2082 * components. This array can then be passed to the |
|
2083 * {@code setDataElements} method of a {@code WritableRaster} |
|
2084 * object. An {@code ArrayIndexOutOfBoundsException} is thrown |
|
2085 * if the {@code normComponents} array is not large enough to hold |
|
2086 * all the color and alpha components (starting at |
|
2087 * {@code normOffset}). If the {@code obj} variable is |
|
2088 * {@code null}, a new array will be allocated. If |
|
2089 * {@code obj} is not {@code null}, it must be a primitive |
|
2090 * array of type transferType; otherwise, a |
|
2091 * {@code ClassCastException} is thrown. An |
|
2092 * {@code ArrayIndexOutOfBoundsException} is thrown if |
|
2093 * {@code obj} is not large enough to hold a pixel value for this |
|
2094 * {@code ColorModel}. |
|
2095 * @param normComponents an array of normalized color and alpha |
|
2096 * components |
|
2097 * @param normOffset the index into {@code normComponents} at which to |
|
2098 * begin retrieving color and alpha components |
|
2099 * @param obj a primitive data array to hold the returned pixel |
|
2100 * @return an {@code Object} which is a primitive data array |
|
2101 * representation of a pixel |
|
2102 * @throws ClassCastException if {@code obj} |
|
2103 * is not a primitive array of type {@code transferType} |
|
2104 * @throws ArrayIndexOutOfBoundsException if |
|
2105 * {@code obj} is not large enough to hold a pixel value |
|
2106 * for this {@code ColorModel} or the {@code normComponents} |
|
2107 * array is not large enough to hold all of the color and alpha |
|
2108 * components starting at {@code normOffset} |
|
2109 * @see WritableRaster#setDataElements |
|
2110 * @see SampleModel#setDataElements |
|
2111 * @since 1.4 |
|
2112 */ |
|
2113 public Object getDataElements(float[] normComponents, int normOffset, |
|
2114 Object obj) { |
|
2115 boolean needAlpha = supportsAlpha && isAlphaPremultiplied; |
|
2116 float[] stdNormComponents; |
|
2117 if (needScaleInit) { |
|
2118 initScale(); |
|
2119 } |
|
2120 if (nonStdScale) { |
|
2121 stdNormComponents = new float[numComponents]; |
|
2122 for (int c = 0, nc = normOffset; c < numColorComponents; |
|
2123 c++, nc++) { |
|
2124 stdNormComponents[c] = (normComponents[nc] - compOffset[c]) * |
|
2125 compScale[c]; |
|
2126 // REMIND: need to analyze whether this |
|
2127 // clamping is necessary |
|
2128 if (stdNormComponents[c] < 0.0f) { |
|
2129 stdNormComponents[c] = 0.0f; |
|
2130 } |
|
2131 if (stdNormComponents[c] > 1.0f) { |
|
2132 stdNormComponents[c] = 1.0f; |
|
2133 } |
|
2134 } |
|
2135 if (supportsAlpha) { |
|
2136 stdNormComponents[numColorComponents] = |
|
2137 normComponents[numColorComponents + normOffset]; |
|
2138 } |
|
2139 normOffset = 0; |
|
2140 } else { |
|
2141 stdNormComponents = normComponents; |
|
2142 } |
|
2143 switch (transferType) { |
|
2144 case DataBuffer.TYPE_BYTE: |
|
2145 byte[] bpixel; |
|
2146 if (obj == null) { |
|
2147 bpixel = new byte[numComponents]; |
|
2148 } else { |
|
2149 bpixel = (byte[]) obj; |
|
2150 } |
|
2151 if (needAlpha) { |
|
2152 float alpha = |
|
2153 stdNormComponents[numColorComponents + normOffset]; |
|
2154 for (int c = 0, nc = normOffset; c < numColorComponents; |
|
2155 c++, nc++) { |
|
2156 bpixel[c] = (byte) ((stdNormComponents[nc] * alpha) * |
|
2157 ((float) ((1 << nBits[c]) - 1)) + 0.5f); |
|
2158 } |
|
2159 bpixel[numColorComponents] = |
|
2160 (byte) (alpha * |
|
2161 ((float) ((1 << nBits[numColorComponents]) - 1)) + |
|
2162 0.5f); |
|
2163 } else { |
|
2164 for (int c = 0, nc = normOffset; c < numComponents; |
|
2165 c++, nc++) { |
|
2166 bpixel[c] = (byte) (stdNormComponents[nc] * |
|
2167 ((float) ((1 << nBits[c]) - 1)) + 0.5f); |
|
2168 } |
|
2169 } |
|
2170 return bpixel; |
|
2171 case DataBuffer.TYPE_USHORT: |
|
2172 short[] uspixel; |
|
2173 if (obj == null) { |
|
2174 uspixel = new short[numComponents]; |
|
2175 } else { |
|
2176 uspixel = (short[]) obj; |
|
2177 } |
|
2178 if (needAlpha) { |
|
2179 float alpha = |
|
2180 stdNormComponents[numColorComponents + normOffset]; |
|
2181 for (int c = 0, nc = normOffset; c < numColorComponents; |
|
2182 c++, nc++) { |
|
2183 uspixel[c] = (short) ((stdNormComponents[nc] * alpha) * |
|
2184 ((float) ((1 << nBits[c]) - 1)) + |
|
2185 0.5f); |
|
2186 } |
|
2187 uspixel[numColorComponents] = |
|
2188 (short) (alpha * |
|
2189 ((float) ((1 << nBits[numColorComponents]) - 1)) + |
|
2190 0.5f); |
|
2191 } else { |
|
2192 for (int c = 0, nc = normOffset; c < numComponents; |
|
2193 c++, nc++) { |
|
2194 uspixel[c] = (short) (stdNormComponents[nc] * |
|
2195 ((float) ((1 << nBits[c]) - 1)) + |
|
2196 0.5f); |
|
2197 } |
|
2198 } |
|
2199 return uspixel; |
|
2200 case DataBuffer.TYPE_INT: |
|
2201 int[] ipixel; |
|
2202 if (obj == null) { |
|
2203 ipixel = new int[numComponents]; |
|
2204 } else { |
|
2205 ipixel = (int[]) obj; |
|
2206 } |
|
2207 if (needAlpha) { |
|
2208 float alpha = |
|
2209 stdNormComponents[numColorComponents + normOffset]; |
|
2210 for (int c = 0, nc = normOffset; c < numColorComponents; |
|
2211 c++, nc++) { |
|
2212 ipixel[c] = (int) ((stdNormComponents[nc] * alpha) * |
|
2213 ((float) ((1 << nBits[c]) - 1)) + 0.5f); |
|
2214 } |
|
2215 ipixel[numColorComponents] = |
|
2216 (int) (alpha * |
|
2217 ((float) ((1 << nBits[numColorComponents]) - 1)) + |
|
2218 0.5f); |
|
2219 } else { |
|
2220 for (int c = 0, nc = normOffset; c < numComponents; |
|
2221 c++, nc++) { |
|
2222 ipixel[c] = (int) (stdNormComponents[nc] * |
|
2223 ((float) ((1 << nBits[c]) - 1)) + 0.5f); |
|
2224 } |
|
2225 } |
|
2226 return ipixel; |
|
2227 case DataBuffer.TYPE_SHORT: |
|
2228 short[] spixel; |
|
2229 if (obj == null) { |
|
2230 spixel = new short[numComponents]; |
|
2231 } else { |
|
2232 spixel = (short[]) obj; |
|
2233 } |
|
2234 if (needAlpha) { |
|
2235 float alpha = |
|
2236 stdNormComponents[numColorComponents + normOffset]; |
|
2237 for (int c = 0, nc = normOffset; c < numColorComponents; |
|
2238 c++, nc++) { |
|
2239 spixel[c] = (short) |
|
2240 (stdNormComponents[nc] * alpha * 32767.0f + 0.5f); |
|
2241 } |
|
2242 spixel[numColorComponents] = (short) (alpha * 32767.0f + 0.5f); |
|
2243 } else { |
|
2244 for (int c = 0, nc = normOffset; c < numComponents; |
|
2245 c++, nc++) { |
|
2246 spixel[c] = (short) |
|
2247 (stdNormComponents[nc] * 32767.0f + 0.5f); |
|
2248 } |
|
2249 } |
|
2250 return spixel; |
|
2251 case DataBuffer.TYPE_FLOAT: |
|
2252 float[] fpixel; |
|
2253 if (obj == null) { |
|
2254 fpixel = new float[numComponents]; |
|
2255 } else { |
|
2256 fpixel = (float[]) obj; |
|
2257 } |
|
2258 if (needAlpha) { |
|
2259 float alpha = normComponents[numColorComponents + normOffset]; |
|
2260 for (int c = 0, nc = normOffset; c < numColorComponents; |
|
2261 c++, nc++) { |
|
2262 fpixel[c] = normComponents[nc] * alpha; |
|
2263 } |
|
2264 fpixel[numColorComponents] = alpha; |
|
2265 } else { |
|
2266 for (int c = 0, nc = normOffset; c < numComponents; |
|
2267 c++, nc++) { |
|
2268 fpixel[c] = normComponents[nc]; |
|
2269 } |
|
2270 } |
|
2271 return fpixel; |
|
2272 case DataBuffer.TYPE_DOUBLE: |
|
2273 double[] dpixel; |
|
2274 if (obj == null) { |
|
2275 dpixel = new double[numComponents]; |
|
2276 } else { |
|
2277 dpixel = (double[]) obj; |
|
2278 } |
|
2279 if (needAlpha) { |
|
2280 double alpha = |
|
2281 (double) (normComponents[numColorComponents + normOffset]); |
|
2282 for (int c = 0, nc = normOffset; c < numColorComponents; |
|
2283 c++, nc++) { |
|
2284 dpixel[c] = normComponents[nc] * alpha; |
|
2285 } |
|
2286 dpixel[numColorComponents] = alpha; |
|
2287 } else { |
|
2288 for (int c = 0, nc = normOffset; c < numComponents; |
|
2289 c++, nc++) { |
|
2290 dpixel[c] = (double) normComponents[nc]; |
|
2291 } |
|
2292 } |
|
2293 return dpixel; |
|
2294 default: |
|
2295 throw new UnsupportedOperationException("This method has not been "+ |
|
2296 "implemented for transferType " + |
|
2297 transferType); |
|
2298 } |
|
2299 } |
|
2300 |
|
2301 /** |
|
2302 * Returns an array of all of the color/alpha components in normalized |
|
2303 * form, given a pixel in this {@code ColorModel}. The pixel |
|
2304 * value is specified by an array of data elements of type transferType |
|
2305 * passed in as an object reference. If pixel is not a primitive array |
|
2306 * of type transferType, a {@code ClassCastException} is thrown. |
|
2307 * An {@code ArrayIndexOutOfBoundsException} is thrown if |
|
2308 * {@code pixel} is not large enough to hold a pixel value for this |
|
2309 * {@code ColorModel}. |
|
2310 * Normalized components are float values between a per component minimum |
|
2311 * and maximum specified by the {@code ColorSpace} object for this |
|
2312 * {@code ColorModel}. If the |
|
2313 * {@code normComponents} array is {@code null}, a new array |
|
2314 * will be allocated. The {@code normComponents} array |
|
2315 * will be returned. Color/alpha components are stored in the |
|
2316 * {@code normComponents} array starting at |
|
2317 * {@code normOffset} (even if the array is allocated by this |
|
2318 * method). An {@code ArrayIndexOutOfBoundsException} is thrown |
|
2319 * if the {@code normComponents} array is not {@code null} |
|
2320 * and is not large enough to hold all the color and alpha components |
|
2321 * (starting at {@code normOffset}). |
|
2322 * <p> |
|
2323 * This method must be overridden by a subclass if that subclass |
|
2324 * is designed to translate pixel sample values to color component values |
|
2325 * in a non-default way. The default translations implemented by this |
|
2326 * class is described in the class comments. Any subclass implementing |
|
2327 * a non-default translation must follow the constraints on allowable |
|
2328 * translations defined there. |
|
2329 * @param pixel the specified pixel |
|
2330 * @param normComponents an array to receive the normalized components |
|
2331 * @param normOffset the offset into the {@code normComponents} |
|
2332 * array at which to start storing normalized components |
|
2333 * @return an array containing normalized color and alpha |
|
2334 * components. |
|
2335 * @throws ClassCastException if {@code pixel} is not a primitive |
|
2336 * array of type transferType |
|
2337 * @throws ArrayIndexOutOfBoundsException if |
|
2338 * {@code normComponents} is not large enough to hold all |
|
2339 * color and alpha components starting at {@code normOffset} |
|
2340 * @throws ArrayIndexOutOfBoundsException if |
|
2341 * {@code pixel} is not large enough to hold a pixel |
|
2342 * value for this {@code ColorModel}. |
|
2343 * @since 1.4 |
|
2344 */ |
|
2345 public float[] getNormalizedComponents(Object pixel, |
|
2346 float[] normComponents, |
|
2347 int normOffset) { |
|
2348 if (normComponents == null) { |
|
2349 normComponents = new float[numComponents+normOffset]; |
|
2350 } |
|
2351 switch (transferType) { |
|
2352 case DataBuffer.TYPE_BYTE: |
|
2353 byte[] bpixel = (byte[]) pixel; |
|
2354 for (int c = 0, nc = normOffset; c < numComponents; c++, nc++) { |
|
2355 normComponents[nc] = ((float) (bpixel[c] & 0xff)) / |
|
2356 ((float) ((1 << nBits[c]) - 1)); |
|
2357 } |
|
2358 break; |
|
2359 case DataBuffer.TYPE_USHORT: |
|
2360 short[] uspixel = (short[]) pixel; |
|
2361 for (int c = 0, nc = normOffset; c < numComponents; c++, nc++) { |
|
2362 normComponents[nc] = ((float) (uspixel[c] & 0xffff)) / |
|
2363 ((float) ((1 << nBits[c]) - 1)); |
|
2364 } |
|
2365 break; |
|
2366 case DataBuffer.TYPE_INT: |
|
2367 int[] ipixel = (int[]) pixel; |
|
2368 for (int c = 0, nc = normOffset; c < numComponents; c++, nc++) { |
|
2369 normComponents[nc] = ((float) ipixel[c]) / |
|
2370 ((float) ((1 << nBits[c]) - 1)); |
|
2371 } |
|
2372 break; |
|
2373 case DataBuffer.TYPE_SHORT: |
|
2374 short[] spixel = (short[]) pixel; |
|
2375 for (int c = 0, nc = normOffset; c < numComponents; c++, nc++) { |
|
2376 normComponents[nc] = ((float) spixel[c]) / 32767.0f; |
|
2377 } |
|
2378 break; |
|
2379 case DataBuffer.TYPE_FLOAT: |
|
2380 float[] fpixel = (float[]) pixel; |
|
2381 for (int c = 0, nc = normOffset; c < numComponents; c++, nc++) { |
|
2382 normComponents[nc] = fpixel[c]; |
|
2383 } |
|
2384 break; |
|
2385 case DataBuffer.TYPE_DOUBLE: |
|
2386 double[] dpixel = (double[]) pixel; |
|
2387 for (int c = 0, nc = normOffset; c < numComponents; c++, nc++) { |
|
2388 normComponents[nc] = (float) dpixel[c]; |
|
2389 } |
|
2390 break; |
|
2391 default: |
|
2392 throw new UnsupportedOperationException("This method has not been "+ |
|
2393 "implemented for transferType " + |
|
2394 transferType); |
|
2395 } |
|
2396 |
|
2397 if (supportsAlpha && isAlphaPremultiplied) { |
|
2398 float alpha = normComponents[numColorComponents + normOffset]; |
|
2399 if (alpha != 0.0f) { |
|
2400 float invAlpha = 1.0f / alpha; |
|
2401 for (int c = normOffset; c < numColorComponents + normOffset; |
|
2402 c++) { |
|
2403 normComponents[c] *= invAlpha; |
|
2404 } |
|
2405 } |
|
2406 } |
|
2407 if (min != null) { |
|
2408 // Normally (i.e. when this class is not subclassed to override |
|
2409 // this method), the test (min != null) will be equivalent to |
|
2410 // the test (nonStdScale). However, there is an unlikely, but |
|
2411 // possible case, in which this method is overridden, nonStdScale |
|
2412 // is set true by initScale(), the subclass method for some |
|
2413 // reason calls this superclass method, but the min and |
|
2414 // diffMinMax arrays were never initialized by setupLUTs(). In |
|
2415 // that case, the right thing to do is follow the intended |
|
2416 // semantics of this method, and rescale the color components |
|
2417 // only if the ColorSpace min/max were detected to be other |
|
2418 // than 0.0/1.0 by setupLUTs(). Note that this implies the |
|
2419 // transferType is byte, ushort, int, or short - i.e. components |
|
2420 // derived from float and double pixel data are never rescaled. |
|
2421 for (int c = 0; c < numColorComponents; c++) { |
|
2422 normComponents[c + normOffset] = min[c] + |
|
2423 diffMinMax[c] * normComponents[c + normOffset]; |
|
2424 } |
|
2425 } |
|
2426 return normComponents; |
|
2427 } |
|
2428 |
|
2429 /** |
|
2430 * Forces the raster data to match the state specified in the |
|
2431 * {@code isAlphaPremultiplied} variable, assuming the data |
|
2432 * is currently correctly described by this {@code ColorModel}. |
|
2433 * It may multiply or divide the color raster data by alpha, or |
|
2434 * do nothing if the data is in the correct state. If the data needs |
|
2435 * to be coerced, this method also returns an instance of |
|
2436 * this {@code ColorModel} with |
|
2437 * the {@code isAlphaPremultiplied} flag set appropriately. |
|
2438 * Since {@code ColorModel} can be subclassed, subclasses inherit |
|
2439 * the implementation of this method and if they don't override it |
|
2440 * then they throw an exception if they use an unsupported |
|
2441 * {@code transferType}. |
|
2442 * |
|
2443 * @throws NullPointerException if {@code raster} is |
|
2444 * {@code null} and data coercion is required. |
|
2445 * @throws UnsupportedOperationException if the transfer type of |
|
2446 * this {@code ComponentColorModel} |
|
2447 * is not one of the supported transfer types: |
|
2448 * {@code DataBuffer.TYPE_BYTE}, {@code DataBuffer.TYPE_USHORT}, |
|
2449 * {@code DataBuffer.TYPE_INT}, {@code DataBuffer.TYPE_SHORT}, |
|
2450 * {@code DataBuffer.TYPE_FLOAT}, or {@code DataBuffer.TYPE_DOUBLE}. |
|
2451 */ |
|
2452 public ColorModel coerceData (WritableRaster raster, |
|
2453 boolean isAlphaPremultiplied) { |
|
2454 if ((supportsAlpha == false) || |
|
2455 (this.isAlphaPremultiplied == isAlphaPremultiplied)) |
|
2456 { |
|
2457 // Nothing to do |
|
2458 return this; |
|
2459 } |
|
2460 |
|
2461 int w = raster.getWidth(); |
|
2462 int h = raster.getHeight(); |
|
2463 int aIdx = raster.getNumBands() - 1; |
|
2464 float normAlpha; |
|
2465 int rminX = raster.getMinX(); |
|
2466 int rY = raster.getMinY(); |
|
2467 int rX; |
|
2468 if (isAlphaPremultiplied) { |
|
2469 switch (transferType) { |
|
2470 case DataBuffer.TYPE_BYTE: { |
|
2471 byte pixel[] = null; |
|
2472 byte zpixel[] = null; |
|
2473 float alphaScale = 1.0f / ((float) ((1<<nBits[aIdx]) - 1)); |
|
2474 for (int y = 0; y < h; y++, rY++) { |
|
2475 rX = rminX; |
|
2476 for (int x = 0; x < w; x++, rX++) { |
|
2477 pixel = (byte[])raster.getDataElements(rX, rY, |
|
2478 pixel); |
|
2479 normAlpha = (pixel[aIdx] & 0xff) * alphaScale; |
|
2480 if (normAlpha != 0.0f) { |
|
2481 for (int c=0; c < aIdx; c++) { |
|
2482 pixel[c] = (byte)((pixel[c] & 0xff) * |
|
2483 normAlpha + 0.5f); |
|
2484 } |
|
2485 raster.setDataElements(rX, rY, pixel); |
|
2486 } else { |
|
2487 if (zpixel == null) { |
|
2488 zpixel = new byte[numComponents]; |
|
2489 java.util.Arrays.fill(zpixel, (byte) 0); |
|
2490 } |
|
2491 raster.setDataElements(rX, rY, zpixel); |
|
2492 } |
|
2493 } |
|
2494 } |
|
2495 } |
|
2496 break; |
|
2497 case DataBuffer.TYPE_USHORT: { |
|
2498 short pixel[] = null; |
|
2499 short zpixel[] = null; |
|
2500 float alphaScale = 1.0f / ((float) ((1<<nBits[aIdx]) - 1)); |
|
2501 for (int y = 0; y < h; y++, rY++) { |
|
2502 rX = rminX; |
|
2503 for (int x = 0; x < w; x++, rX++) { |
|
2504 pixel = (short[])raster.getDataElements(rX, rY, |
|
2505 pixel); |
|
2506 normAlpha = (pixel[aIdx] & 0xffff) * alphaScale; |
|
2507 if (normAlpha != 0.0f) { |
|
2508 for (int c=0; c < aIdx; c++) { |
|
2509 pixel[c] = (short) |
|
2510 ((pixel[c] & 0xffff) * normAlpha + |
|
2511 0.5f); |
|
2512 } |
|
2513 raster.setDataElements(rX, rY, pixel); |
|
2514 } else { |
|
2515 if (zpixel == null) { |
|
2516 zpixel = new short[numComponents]; |
|
2517 java.util.Arrays.fill(zpixel, (short) 0); |
|
2518 } |
|
2519 raster.setDataElements(rX, rY, zpixel); |
|
2520 } |
|
2521 } |
|
2522 } |
|
2523 } |
|
2524 break; |
|
2525 case DataBuffer.TYPE_INT: { |
|
2526 int pixel[] = null; |
|
2527 int zpixel[] = null; |
|
2528 float alphaScale = 1.0f / ((float) ((1<<nBits[aIdx]) - 1)); |
|
2529 for (int y = 0; y < h; y++, rY++) { |
|
2530 rX = rminX; |
|
2531 for (int x = 0; x < w; x++, rX++) { |
|
2532 pixel = (int[])raster.getDataElements(rX, rY, |
|
2533 pixel); |
|
2534 normAlpha = pixel[aIdx] * alphaScale; |
|
2535 if (normAlpha != 0.0f) { |
|
2536 for (int c=0; c < aIdx; c++) { |
|
2537 pixel[c] = (int) (pixel[c] * normAlpha + |
|
2538 0.5f); |
|
2539 } |
|
2540 raster.setDataElements(rX, rY, pixel); |
|
2541 } else { |
|
2542 if (zpixel == null) { |
|
2543 zpixel = new int[numComponents]; |
|
2544 java.util.Arrays.fill(zpixel, 0); |
|
2545 } |
|
2546 raster.setDataElements(rX, rY, zpixel); |
|
2547 } |
|
2548 } |
|
2549 } |
|
2550 } |
|
2551 break; |
|
2552 case DataBuffer.TYPE_SHORT: { |
|
2553 short pixel[] = null; |
|
2554 short zpixel[] = null; |
|
2555 float alphaScale = 1.0f / 32767.0f; |
|
2556 for (int y = 0; y < h; y++, rY++) { |
|
2557 rX = rminX; |
|
2558 for (int x = 0; x < w; x++, rX++) { |
|
2559 pixel = (short[]) raster.getDataElements(rX, rY, |
|
2560 pixel); |
|
2561 normAlpha = pixel[aIdx] * alphaScale; |
|
2562 if (normAlpha != 0.0f) { |
|
2563 for (int c=0; c < aIdx; c++) { |
|
2564 pixel[c] = (short) (pixel[c] * normAlpha + |
|
2565 0.5f); |
|
2566 } |
|
2567 raster.setDataElements(rX, rY, pixel); |
|
2568 } else { |
|
2569 if (zpixel == null) { |
|
2570 zpixel = new short[numComponents]; |
|
2571 java.util.Arrays.fill(zpixel, (short) 0); |
|
2572 } |
|
2573 raster.setDataElements(rX, rY, zpixel); |
|
2574 } |
|
2575 } |
|
2576 } |
|
2577 } |
|
2578 break; |
|
2579 case DataBuffer.TYPE_FLOAT: { |
|
2580 float pixel[] = null; |
|
2581 float zpixel[] = null; |
|
2582 for (int y = 0; y < h; y++, rY++) { |
|
2583 rX = rminX; |
|
2584 for (int x = 0; x < w; x++, rX++) { |
|
2585 pixel = (float[]) raster.getDataElements(rX, rY, |
|
2586 pixel); |
|
2587 normAlpha = pixel[aIdx]; |
|
2588 if (normAlpha != 0.0f) { |
|
2589 for (int c=0; c < aIdx; c++) { |
|
2590 pixel[c] *= normAlpha; |
|
2591 } |
|
2592 raster.setDataElements(rX, rY, pixel); |
|
2593 } else { |
|
2594 if (zpixel == null) { |
|
2595 zpixel = new float[numComponents]; |
|
2596 java.util.Arrays.fill(zpixel, 0.0f); |
|
2597 } |
|
2598 raster.setDataElements(rX, rY, zpixel); |
|
2599 } |
|
2600 } |
|
2601 } |
|
2602 } |
|
2603 break; |
|
2604 case DataBuffer.TYPE_DOUBLE: { |
|
2605 double pixel[] = null; |
|
2606 double zpixel[] = null; |
|
2607 for (int y = 0; y < h; y++, rY++) { |
|
2608 rX = rminX; |
|
2609 for (int x = 0; x < w; x++, rX++) { |
|
2610 pixel = (double[]) raster.getDataElements(rX, rY, |
|
2611 pixel); |
|
2612 double dnormAlpha = pixel[aIdx]; |
|
2613 if (dnormAlpha != 0.0) { |
|
2614 for (int c=0; c < aIdx; c++) { |
|
2615 pixel[c] *= dnormAlpha; |
|
2616 } |
|
2617 raster.setDataElements(rX, rY, pixel); |
|
2618 } else { |
|
2619 if (zpixel == null) { |
|
2620 zpixel = new double[numComponents]; |
|
2621 java.util.Arrays.fill(zpixel, 0.0); |
|
2622 } |
|
2623 raster.setDataElements(rX, rY, zpixel); |
|
2624 } |
|
2625 } |
|
2626 } |
|
2627 } |
|
2628 break; |
|
2629 default: |
|
2630 throw new UnsupportedOperationException("This method has not been "+ |
|
2631 "implemented for transferType " + transferType); |
|
2632 } |
|
2633 } |
|
2634 else { |
|
2635 // We are premultiplied and want to divide it out |
|
2636 switch (transferType) { |
|
2637 case DataBuffer.TYPE_BYTE: { |
|
2638 byte pixel[] = null; |
|
2639 float alphaScale = 1.0f / ((float) ((1<<nBits[aIdx]) - 1)); |
|
2640 for (int y = 0; y < h; y++, rY++) { |
|
2641 rX = rminX; |
|
2642 for (int x = 0; x < w; x++, rX++) { |
|
2643 pixel = (byte[])raster.getDataElements(rX, rY, |
|
2644 pixel); |
|
2645 normAlpha = (pixel[aIdx] & 0xff) * alphaScale; |
|
2646 if (normAlpha != 0.0f) { |
|
2647 float invAlpha = 1.0f / normAlpha; |
|
2648 for (int c=0; c < aIdx; c++) { |
|
2649 pixel[c] = (byte) |
|
2650 ((pixel[c] & 0xff) * invAlpha + 0.5f); |
|
2651 } |
|
2652 raster.setDataElements(rX, rY, pixel); |
|
2653 } |
|
2654 } |
|
2655 } |
|
2656 } |
|
2657 break; |
|
2658 case DataBuffer.TYPE_USHORT: { |
|
2659 short pixel[] = null; |
|
2660 float alphaScale = 1.0f / ((float) ((1<<nBits[aIdx]) - 1)); |
|
2661 for (int y = 0; y < h; y++, rY++) { |
|
2662 rX = rminX; |
|
2663 for (int x = 0; x < w; x++, rX++) { |
|
2664 pixel = (short[])raster.getDataElements(rX, rY, |
|
2665 pixel); |
|
2666 normAlpha = (pixel[aIdx] & 0xffff) * alphaScale; |
|
2667 if (normAlpha != 0.0f) { |
|
2668 float invAlpha = 1.0f / normAlpha; |
|
2669 for (int c=0; c < aIdx; c++) { |
|
2670 pixel[c] = (short) |
|
2671 ((pixel[c] & 0xffff) * invAlpha + 0.5f); |
|
2672 } |
|
2673 raster.setDataElements(rX, rY, pixel); |
|
2674 } |
|
2675 } |
|
2676 } |
|
2677 } |
|
2678 break; |
|
2679 case DataBuffer.TYPE_INT: { |
|
2680 int pixel[] = null; |
|
2681 float alphaScale = 1.0f / ((float) ((1<<nBits[aIdx]) - 1)); |
|
2682 for (int y = 0; y < h; y++, rY++) { |
|
2683 rX = rminX; |
|
2684 for (int x = 0; x < w; x++, rX++) { |
|
2685 pixel = (int[])raster.getDataElements(rX, rY, |
|
2686 pixel); |
|
2687 normAlpha = pixel[aIdx] * alphaScale; |
|
2688 if (normAlpha != 0.0f) { |
|
2689 float invAlpha = 1.0f / normAlpha; |
|
2690 for (int c=0; c < aIdx; c++) { |
|
2691 pixel[c] = (int) |
|
2692 (pixel[c] * invAlpha + 0.5f); |
|
2693 } |
|
2694 raster.setDataElements(rX, rY, pixel); |
|
2695 } |
|
2696 } |
|
2697 } |
|
2698 } |
|
2699 break; |
|
2700 case DataBuffer.TYPE_SHORT: { |
|
2701 short pixel[] = null; |
|
2702 float alphaScale = 1.0f / 32767.0f; |
|
2703 for (int y = 0; y < h; y++, rY++) { |
|
2704 rX = rminX; |
|
2705 for (int x = 0; x < w; x++, rX++) { |
|
2706 pixel = (short[])raster.getDataElements(rX, rY, |
|
2707 pixel); |
|
2708 normAlpha = pixel[aIdx] * alphaScale; |
|
2709 if (normAlpha != 0.0f) { |
|
2710 float invAlpha = 1.0f / normAlpha; |
|
2711 for (int c=0; c < aIdx; c++) { |
|
2712 pixel[c] = (short) |
|
2713 (pixel[c] * invAlpha + 0.5f); |
|
2714 } |
|
2715 raster.setDataElements(rX, rY, pixel); |
|
2716 } |
|
2717 } |
|
2718 } |
|
2719 } |
|
2720 break; |
|
2721 case DataBuffer.TYPE_FLOAT: { |
|
2722 float pixel[] = null; |
|
2723 for (int y = 0; y < h; y++, rY++) { |
|
2724 rX = rminX; |
|
2725 for (int x = 0; x < w; x++, rX++) { |
|
2726 pixel = (float[])raster.getDataElements(rX, rY, |
|
2727 pixel); |
|
2728 normAlpha = pixel[aIdx]; |
|
2729 if (normAlpha != 0.0f) { |
|
2730 float invAlpha = 1.0f / normAlpha; |
|
2731 for (int c=0; c < aIdx; c++) { |
|
2732 pixel[c] *= invAlpha; |
|
2733 } |
|
2734 raster.setDataElements(rX, rY, pixel); |
|
2735 } |
|
2736 } |
|
2737 } |
|
2738 } |
|
2739 break; |
|
2740 case DataBuffer.TYPE_DOUBLE: { |
|
2741 double pixel[] = null; |
|
2742 for (int y = 0; y < h; y++, rY++) { |
|
2743 rX = rminX; |
|
2744 for (int x = 0; x < w; x++, rX++) { |
|
2745 pixel = (double[])raster.getDataElements(rX, rY, |
|
2746 pixel); |
|
2747 double dnormAlpha = pixel[aIdx]; |
|
2748 if (dnormAlpha != 0.0) { |
|
2749 double invAlpha = 1.0 / dnormAlpha; |
|
2750 for (int c=0; c < aIdx; c++) { |
|
2751 pixel[c] *= invAlpha; |
|
2752 } |
|
2753 raster.setDataElements(rX, rY, pixel); |
|
2754 } |
|
2755 } |
|
2756 } |
|
2757 } |
|
2758 break; |
|
2759 default: |
|
2760 throw new UnsupportedOperationException("This method has not been "+ |
|
2761 "implemented for transferType " + transferType); |
|
2762 } |
|
2763 } |
|
2764 |
|
2765 // Return a new color model |
|
2766 if (!signed) { |
|
2767 return new ComponentColorModel(colorSpace, nBits, supportsAlpha, |
|
2768 isAlphaPremultiplied, transparency, |
|
2769 transferType); |
|
2770 } else { |
|
2771 return new ComponentColorModel(colorSpace, supportsAlpha, |
|
2772 isAlphaPremultiplied, transparency, |
|
2773 transferType); |
|
2774 } |
|
2775 |
|
2776 } |
|
2777 |
|
2778 /** |
|
2779 * Returns true if {@code raster} is compatible with this |
|
2780 * {@code ColorModel}; false if it is not. |
|
2781 * |
|
2782 * @param raster The {@code Raster} object to test for compatibility. |
|
2783 * |
|
2784 * @return {@code true} if {@code raster} is compatible with this |
|
2785 * {@code ColorModel}, {@code false} if it is not. |
|
2786 */ |
|
2787 public boolean isCompatibleRaster(Raster raster) { |
|
2788 |
|
2789 SampleModel sm = raster.getSampleModel(); |
|
2790 |
|
2791 if (sm instanceof ComponentSampleModel) { |
|
2792 if (sm.getNumBands() != getNumComponents()) { |
|
2793 return false; |
|
2794 } |
|
2795 for (int i=0; i<nBits.length; i++) { |
|
2796 if (sm.getSampleSize(i) < nBits[i]) { |
|
2797 return false; |
|
2798 } |
|
2799 } |
|
2800 return (raster.getTransferType() == transferType); |
|
2801 } |
|
2802 else { |
|
2803 return false; |
|
2804 } |
|
2805 } |
|
2806 |
|
2807 /** |
|
2808 * Creates a {@code WritableRaster} with the specified width and height, |
|
2809 * that has a data layout ({@code SampleModel}) compatible with |
|
2810 * this {@code ColorModel}. |
|
2811 * |
|
2812 * @param w The width of the {@code WritableRaster} you want to create. |
|
2813 * @param h The height of the {@code WritableRaster} you want to create. |
|
2814 * |
|
2815 * @return A {@code WritableRaster} that is compatible with |
|
2816 * this {@code ColorModel}. |
|
2817 * @see WritableRaster |
|
2818 * @see SampleModel |
|
2819 */ |
|
2820 public WritableRaster createCompatibleWritableRaster (int w, int h) { |
|
2821 int dataSize = w*h*numComponents; |
|
2822 WritableRaster raster = null; |
|
2823 |
|
2824 switch (transferType) { |
|
2825 case DataBuffer.TYPE_BYTE: |
|
2826 case DataBuffer.TYPE_USHORT: |
|
2827 raster = Raster.createInterleavedRaster(transferType, |
|
2828 w, h, |
|
2829 numComponents, null); |
|
2830 break; |
|
2831 default: |
|
2832 SampleModel sm = createCompatibleSampleModel(w, h); |
|
2833 DataBuffer db = sm.createDataBuffer(); |
|
2834 raster = Raster.createWritableRaster(sm, db, null); |
|
2835 } |
|
2836 |
|
2837 return raster; |
|
2838 } |
|
2839 |
|
2840 /** |
|
2841 * Creates a {@code SampleModel} with the specified width and height, |
|
2842 * that has a data layout compatible with this {@code ColorModel}. |
|
2843 * |
|
2844 * @param w The width of the {@code SampleModel} you want to create. |
|
2845 * @param h The height of the {@code SampleModel} you want to create. |
|
2846 * |
|
2847 * @return A {@code SampleModel} that is compatible with this |
|
2848 * {@code ColorModel}. |
|
2849 * |
|
2850 * @see SampleModel |
|
2851 */ |
|
2852 public SampleModel createCompatibleSampleModel(int w, int h) { |
|
2853 int[] bandOffsets = new int[numComponents]; |
|
2854 for (int i=0; i < numComponents; i++) { |
|
2855 bandOffsets[i] = i; |
|
2856 } |
|
2857 switch (transferType) { |
|
2858 case DataBuffer.TYPE_BYTE: |
|
2859 case DataBuffer.TYPE_USHORT: |
|
2860 return new PixelInterleavedSampleModel(transferType, w, h, |
|
2861 numComponents, |
|
2862 w*numComponents, |
|
2863 bandOffsets); |
|
2864 default: |
|
2865 return new ComponentSampleModel(transferType, w, h, |
|
2866 numComponents, |
|
2867 w*numComponents, |
|
2868 bandOffsets); |
|
2869 } |
|
2870 } |
|
2871 |
|
2872 /** |
|
2873 * Checks whether or not the specified {@code SampleModel} |
|
2874 * is compatible with this {@code ColorModel}. |
|
2875 * |
|
2876 * @param sm The {@code SampleModel} to test for compatibility. |
|
2877 * |
|
2878 * @return {@code true} if the {@code SampleModel} is |
|
2879 * compatible with this {@code ColorModel}, {@code false} |
|
2880 * if it is not. |
|
2881 * |
|
2882 * @see SampleModel |
|
2883 */ |
|
2884 public boolean isCompatibleSampleModel(SampleModel sm) { |
|
2885 if (!(sm instanceof ComponentSampleModel)) { |
|
2886 return false; |
|
2887 } |
|
2888 |
|
2889 // Must have the same number of components |
|
2890 if (numComponents != sm.getNumBands()) { |
|
2891 return false; |
|
2892 } |
|
2893 |
|
2894 if (sm.getTransferType() != transferType) { |
|
2895 return false; |
|
2896 } |
|
2897 |
|
2898 return true; |
|
2899 } |
|
2900 |
|
2901 /** |
|
2902 * Returns a {@code Raster} representing the alpha channel of an image, |
|
2903 * extracted from the input {@code Raster}. |
|
2904 * This method assumes that {@code Raster} objects associated with |
|
2905 * this {@code ColorModel} store the alpha band, if present, as |
|
2906 * the last band of image data. Returns null if there is no separate spatial |
|
2907 * alpha channel associated with this {@code ColorModel}. |
|
2908 * This method creates a new {@code Raster}, but will share the data |
|
2909 * array. |
|
2910 * |
|
2911 * @param raster The {@code WritableRaster} from which to extract the |
|
2912 * alpha channel. |
|
2913 * |
|
2914 * @return A {@code WritableRaster} containing the image's alpha channel. |
|
2915 * |
|
2916 */ |
|
2917 public WritableRaster getAlphaRaster(WritableRaster raster) { |
|
2918 if (hasAlpha() == false) { |
|
2919 return null; |
|
2920 } |
|
2921 |
|
2922 int x = raster.getMinX(); |
|
2923 int y = raster.getMinY(); |
|
2924 int[] band = new int[1]; |
|
2925 band[0] = raster.getNumBands() - 1; |
|
2926 return raster.createWritableChild(x, y, raster.getWidth(), |
|
2927 raster.getHeight(), x, y, |
|
2928 band); |
|
2929 } |
|
2930 |
|
2931 /** |
|
2932 * Tests if the specified {@code Object} is an instance |
|
2933 * of {@code ComponentColorModel} and equals this |
|
2934 * {@code ComponentColorModel}. |
|
2935 * @param obj the {@code Object} to test for equality |
|
2936 * @return {@code true} if the specified {@code Object} |
|
2937 * is an instance of {@code ComponentColorModel} and equals this |
|
2938 * {@code ComponentColorModel}; {@code false} otherwise. |
|
2939 */ |
|
2940 @Override |
|
2941 public boolean equals(Object obj) { |
|
2942 if (!(obj instanceof ComponentColorModel)) { |
|
2943 return false; |
|
2944 } |
|
2945 |
|
2946 ComponentColorModel cm = (ComponentColorModel) obj; |
|
2947 if (supportsAlpha != cm.hasAlpha() || |
|
2948 isAlphaPremultiplied != cm.isAlphaPremultiplied() || |
|
2949 pixel_bits != cm.getPixelSize() || |
|
2950 transparency != cm.getTransparency() || |
|
2951 numComponents != cm.getNumComponents() || |
|
2952 (!(colorSpace.equals(cm.colorSpace))) || |
|
2953 transferType != cm.transferType) |
|
2954 { |
|
2955 return false; |
|
2956 } |
|
2957 |
|
2958 if (!(Arrays.equals(nBits, cm.getComponentSize()))) { |
|
2959 return false; |
|
2960 } |
|
2961 |
|
2962 return true; |
|
2963 } |
|
2964 |
|
2965 /** |
|
2966 * Returns the hash code for this ComponentColorModel. |
|
2967 * |
|
2968 * @return a hash code for this ComponentColorModel. |
|
2969 */ |
|
2970 @Override |
|
2971 public int hashCode() { |
|
2972 int result = hashCode; |
|
2973 if (result == 0) { |
|
2974 result = 7; |
|
2975 result = 89 * result + this.pixel_bits; |
|
2976 result = 89 * result + Arrays.hashCode(this.nBits); |
|
2977 result = 89 * result + this.transparency; |
|
2978 result = 89 * result + (this.supportsAlpha ? 1 : 0); |
|
2979 result = 89 * result + (this.isAlphaPremultiplied ? 1 : 0); |
|
2980 result = 89 * result + this.numComponents; |
|
2981 result = 89 * result + this.colorSpace.hashCode(); |
|
2982 result = 89 * result + this.transferType; |
|
2983 hashCode = result; |
|
2984 } |
|
2985 return result; |
|
2986 } |
|
2987 } |