001: /*
002: * $RCSfile: ColorCube.java,v $
003: *
004: * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Use is subject to license terms.
007: *
008: * $Revision: 1.1 $
009: * $Date: 2005/02/11 04:57:06 $
010: * $State: Exp $
011: */
012: package javax.media.jai;
013:
014: import java.awt.image.DataBuffer;
015: import javax.media.jai.LookupTableJAI;
016:
017: /**
018: * A subclass of <code>LookupTableJAI</code> which represents a lookup
019: * table which is a color cube. A color cube provides a fixed,
020: * invertible mapping between table indices and sample values.
021: * This allows the <code>findNearestEntry</code> method to be implemented
022: * more efficiently than in the general case.
023: *
024: * <p> All constructors are protected. The correct way to create a
025: * <code>ColorCube</code> is to use one of the static
026: * <code>create</code> methods defined in this class.
027: *
028: * @see javax.media.jai.LookupTableJAI
029: *
030: */
031: public class ColorCube extends LookupTableJAI {
032: /**
033: * A <code>ColorCube</code> for dithering RGB byte data into 216 colors.
034: * The offset of this <code>ColorCube</code> is 38.
035: */
036: public static final ColorCube BYTE_496 = ColorCube.createColorCube(
037: DataBuffer.TYPE_BYTE, 38, new int[] { 4, 9, 6 });
038:
039: /**
040: * A <code>ColorCube</code> for dithering YCC byte data into 200 colors.
041: * The offset of this <code>ColorCube</code> is 54.
042: */
043: public static final ColorCube BYTE_855 = ColorCube.createColorCube(
044: DataBuffer.TYPE_BYTE, 54, new int[] { 8, 5, 5 });
045:
046: /** The signed array of sizes used to create the <code>ColorCube</code>. */
047: private int[] dimension;
048:
049: /**
050: * An array of positive values each of whose elements is one less than the
051: * absolute value of the corresponding element of the dimension array.
052: */
053: private int[] dimsLessOne;
054:
055: /**
056: * An array of multipliers.
057: *
058: * <p> The magnitudes of the elements of the multiplier array are
059: * defined as <code>multipliers[0] = 1</code> and
060: * <code>multipliers[i] =
061: * multipliers[i-1]*Math.abs(dimension[i-1])</code> where <code>i
062: * > 0</code>. The elements are subsequently assigned the same
063: * sign (positive or negative) as the corresponding elements of
064: * the dimension array.
065: */
066: private int[] multipliers;
067:
068: /**
069: * An offset into the lookup table, accounting for negative dimensions.
070: */
071: private int adjustedOffset;
072:
073: /**
074: * The data type cached to accelerate findNearestEntry().
075: */
076: private int dataType;
077:
078: /**
079: * The number of bands cached to accelerate findNearestEntry().
080: */
081: private int numBands;
082:
083: /**
084: * Returns a multi-banded <code>ColorCube</code> of a specified data type.
085: *
086: * @param dataType The data type of the <code>ColorCube</code>,
087: * one of <code>DataBuffer.TYPE_BYTE</code>,
088: * <code>TYPE_SHORT</code>,
089: * <code>TYPE_USHORT</code>,
090: * <code>TYPE_INT</code>,
091: * <code>TYPE_FLOAT</code>,
092: * or <code>TYPE_DOUBLE</code>.
093: * @param offset The common offset for all bands.
094: * @param dimension The signed dimension of each band.
095: *
096: * @throws RuntimeExceptions for unsupported data types
097: * @return An appropriate <code>ColorCube</code>.
098: */
099: public static ColorCube createColorCube(int dataType, int offset,
100: int dimension[]) {
101: ColorCube colorCube;
102:
103: switch (dataType) {
104: case DataBuffer.TYPE_BYTE:
105: colorCube = createColorCubeByte(offset, dimension);
106: break;
107: case DataBuffer.TYPE_SHORT:
108: colorCube = createColorCubeShort(offset, dimension);
109: break;
110: case DataBuffer.TYPE_USHORT:
111: colorCube = createColorCubeUShort(offset, dimension);
112: break;
113: case DataBuffer.TYPE_INT:
114: colorCube = createColorCubeInt(offset, dimension);
115: break;
116: case DataBuffer.TYPE_FLOAT:
117: colorCube = createColorCubeFloat(offset, dimension);
118: break;
119: case DataBuffer.TYPE_DOUBLE:
120: colorCube = createColorCubeDouble(offset, dimension);
121: break;
122: default:
123: throw new RuntimeException(JaiI18N.getString("ColorCube0"));
124: }
125:
126: return colorCube;
127: }
128:
129: /**
130: * Returns a multi-banded <code>ColorCube</code> of a specified
131: * data type with zero offset for all bands.
132: *
133: * @param dataType The data type of the <code>ColorCube</code>.
134: * @param dimension The signed dimension of each band.
135: *
136: * @throws IllegalArgumentException if dimension is null.
137: * @return An appropriate <code>ColorCube</code>.
138: */
139: public static ColorCube createColorCube(int dataType,
140: int dimension[]) {
141:
142: if (dimension == null) {
143: throw new IllegalArgumentException(JaiI18N
144: .getString("Generic0"));
145: }
146:
147: return createColorCube(dataType, 0, dimension);
148: }
149:
150: /**
151: * Returns a multi-banded byte <code>ColorCube</code> with an index
152: * offset common to all bands.
153: *
154: * @param offset The common offset for all bands.
155: * @param dimension An array of signed sizes of each side of the color
156: * cube. The color ramp in each dimension will be increasing or decreasing
157: * according to whether the sign of the corresponding element of the
158: * <code>dimension</code> array is positive or negative, respectively.
159: *
160: * @return A multi-banded byte <code>ColorCube</code> with offset.
161: */
162: private static ColorCube createColorCubeByte(int offset,
163: int dimension[]) {
164: ColorCube colorCube = new ColorCube(createDataArrayByte(offset,
165: dimension), offset);
166: colorCube.initFields(offset, dimension);
167: return colorCube;
168: }
169:
170: /**
171: * Returns a multi-banded short <code>ColorCube</code> with an index
172: * offset common to all bands.
173: *
174: * @param offset The common offset for all bands.
175: * @param dimension An array of signed sizes of each side of the color
176: * cube. The color ramp in each dimension will be increasing or decreasing
177: * according to whether the sign of the corresponding element of the
178: * <code>dimension</code> array is positive or negative, respectively.
179: *
180: * @return A multi-banded short <code>ColorCube</code> with offset.
181: */
182: private static ColorCube createColorCubeShort(int offset,
183: int dimension[]) {
184: ColorCube colorCube = new ColorCube(createDataArrayShort(
185: offset, dimension), offset, false);
186: colorCube.initFields(offset, dimension);
187: return colorCube;
188: }
189:
190: /**
191: * Returns a multi-banded unsigned short <code>ColorCube</code> with an
192: * index offset common to all bands.
193: *
194: * @param offset The common offset for all bands.
195: * @param dimension An array of signed sizes of each side of the color
196: * cube. The color ramp in each dimension will be increasing or decreasing
197: * according to whether the sign of the corresponding element of the
198: * <code>dimension</code> array is positive or negative, respectively.
199: *
200: * @return A multi-banded unsigned short <code>ColorCube</code> with
201: * offset.
202: */
203: private static ColorCube createColorCubeUShort(int offset,
204: int dimension[]) {
205: ColorCube colorCube = new ColorCube(createDataArrayUShort(
206: offset, dimension), offset, true);
207: colorCube.initFields(offset, dimension);
208: return colorCube;
209: }
210:
211: /**
212: * Returns a multi-banded int <code>ColorCube</code> with an index
213: * offset common to all bands.
214: *
215: * @param offset The common offset for all bands.
216: * @param dimension An array of signed sizes of each side of the color
217: * cube. The color ramp in each dimension will be increasing or decreasing
218: * according to whether the sign of the corresponding element of the
219: * <code>dimension</code> array is positive or negative, respectively.
220: *
221: * @return A multi-banded int <code>ColorCube</code> with offset.
222: */
223: private static ColorCube createColorCubeInt(int offset,
224: int dimension[]) {
225: ColorCube colorCube = new ColorCube(createDataArrayInt(offset,
226: dimension), offset);
227: colorCube.initFields(offset, dimension);
228: return colorCube;
229: }
230:
231: /**
232: * Returns a multi-banded float <code>ColorCube</code> with an index
233: * offset common to all bands.
234: *
235: * @param offset The common offset for all bands.
236: * @param dimension An array of signed sizes of each side of the color
237: * cube. The color ramp in each dimension will be increasing or decreasing
238: * according to whether the sign of the corresponding element of the
239: * <code>dimension</code> array is positive or negative, respectively.
240: *
241: * @return A multi-banded float <code>ColorCube</code> with offset.
242: */
243: private static ColorCube createColorCubeFloat(int offset,
244: int dimension[]) {
245: ColorCube colorCube = new ColorCube(createDataArrayFloat(
246: offset, dimension), offset);
247: colorCube.initFields(offset, dimension);
248: return colorCube;
249: }
250:
251: /**
252: * Returns a multi-banded double <code>ColorCube</code> with an index
253: * offset common to all bands.
254: *
255: * @param offset The common offset for all bands.
256: * @param dimension An array of signed sizes of each side of the color
257: * cube. The color ramp in each dimension will be increasing or decreasing
258: * according to whether the sign of the corresponding element of the
259: * <code>dimension</code> array is positive or negative, respectively.
260: *
261: * @return A multi-banded double <code>ColorCube</code>.
262: */
263: private static ColorCube createColorCubeDouble(int offset,
264: int dimension[]) {
265: ColorCube colorCube = new ColorCube(createDataArrayDouble(
266: offset, dimension), offset);
267: colorCube.initFields(offset, dimension);
268: return colorCube;
269: }
270:
271: /**
272: * Constructs a two-dimensional array of the requested data type which
273: * represents the contents of a color cube.
274: *
275: * @param dataType The data type as defined by the static TYPE fields of
276: * <code>DataBuffer</code>, e.g., <code>DataBuffer.TYPE_BYTE</code>.
277: * @param offset The initial offset into the data array.
278: * @param dimension An array of signed sizes of each side of the color
279: * cube. The color ramp in each dimension will be increasing or decreasing
280: * according to whether the sign of the corresponding element of the
281: * <code>dimension</code> array is positive or negative, respectively.
282: *
283: * @return A two-dimensional array of the requested data type laid
284: * out in color cube format.
285: *
286: * @throws RuntimeException for data types other than
287: * DataBuffer.TYPE_BYTE DataBuffer.TYPE_USHORT
288: * DataBuffer.TYPE_SHORT DataBuffer.TYPE_INT
289: * DataBuffer.TYPE_FLOAT DataBuffer.TYPE_DOUBLE
290: * @see java.awt.image.DataBuffer
291: */
292: private static Object createDataArray(int dataType, int offset,
293: int dimension[]) {
294: // Make sure that the dimension array has non-zero length.
295: int nbands = dimension.length;
296: if (nbands == 0) {
297: throw new RuntimeException(JaiI18N.getString("ColorCube1"));
298: }
299:
300: // Ascertain that all dimension are non-zero.
301: for (int band = 0; band < nbands; band++) {
302: if (dimension[band] == 0) {
303: throw new RuntimeException(JaiI18N
304: .getString("ColorCube2"));
305: }
306: }
307:
308: // Copy the dimension into an array of dimension magnitudes.
309: int[] dimensionAbs = new int[nbands];
310: for (int band = 0; band < nbands; band++) {
311: dimensionAbs[band] = Math.abs(dimension[band]);
312: }
313:
314: // Check that the color cube is not too large for the machine.
315: double floatSize = dimensionAbs[0];
316: for (int band = 1; band < nbands; band++) {
317: floatSize *= (double) dimensionAbs[band];
318: }
319: if (floatSize > (double) Integer.MAX_VALUE) {
320: //
321: // Color cube is too large for 32 bit addressability
322: //
323: throw new RuntimeException(JaiI18N.getString("ColorCube3"));
324: }
325: int size = (int) floatSize;
326:
327: // Initialize the data array and extrema for this data type.
328: double dataMin;
329: double dataMax;
330: Object dataArray;
331: switch (dataType) {
332: case DataBuffer.TYPE_BYTE:
333: dataMin = 0.0;
334: dataMax = 255.0;
335: dataArray = (Object) new byte[nbands][size];
336: break;
337: case DataBuffer.TYPE_SHORT:
338: dataMin = Short.MIN_VALUE;
339: dataMax = Short.MAX_VALUE;
340: dataArray = (Object) new short[nbands][size];
341: break;
342: case DataBuffer.TYPE_USHORT:
343: dataMin = 0;
344: dataMax = 65535;
345: dataArray = (Object) new short[nbands][size];
346: break;
347: case DataBuffer.TYPE_INT:
348: dataMin = Integer.MIN_VALUE;
349: dataMax = Integer.MAX_VALUE;
350: dataArray = (Object) new int[nbands][size];
351: break;
352: case DataBuffer.TYPE_FLOAT:
353: dataMin = -Float.MAX_VALUE;
354: dataMax = Float.MAX_VALUE;
355: dataArray = (Object) new float[nbands][size];
356: break;
357: case DataBuffer.TYPE_DOUBLE:
358: dataMin = -Double.MAX_VALUE;
359: dataMax = Double.MAX_VALUE;
360: dataArray = (Object) new double[nbands][size];
361: break;
362: default:
363: throw new RuntimeException(JaiI18N.getString("ColorCube7"));
364: }
365:
366: // Ensure that the parameters don't go out of range.
367: if ((double) (size + offset) > dataMax) {
368: throw new RuntimeException(JaiI18N.getString("ColorCube4"));
369: }
370:
371: // Initialize the multipliers
372: int[] multipliers = new int[nbands];
373: multipliers[0] = 1;
374: for (int band = 1; band < nbands; band++) {
375: multipliers[band] = multipliers[band - 1]
376: * dimensionAbs[band - 1];
377: }
378:
379: // Populate each band of the lookup table data.
380: for (int band = 0; band < nbands; band++) {
381: // Determine the step size for this band.
382: int idimension = dimensionAbs[band];
383: double delta;
384: if (idimension == 1) {
385: // A dimension of one means all entries will be the same
386: delta = 0.0;
387: } else if (dataType == DataBuffer.TYPE_FLOAT
388: || dataType == DataBuffer.TYPE_DOUBLE) {
389: delta = 1.0 / (idimension - 1);
390: } else {
391: delta = (dataMax - dataMin) / (idimension - 1);
392: }
393:
394: // Set the starting value and index step.
395: double start;
396: if (dimension[band] < 0) {
397: delta = -delta;
398: start = dataMax;
399: } else {
400: start = dataMin;
401: }
402: int repeatCount = multipliers[band];
403:
404: // Load the actual lookup table values for this band
405: int index;
406: switch (dataType) {
407: case DataBuffer.TYPE_BYTE:
408: byte[][] byteData = (byte[][]) dataArray;
409: index = 0;
410: while (index < size) {
411: double val = start;
412: for (int i = 0; i < idimension; i++) {
413: for (int j = 0; j < repeatCount; j++) {
414: byteData[band][index] = (byte) ((int) (val + 0.5) & 0x000000ff);
415: index++;
416: }
417: val += delta;
418: }
419: }
420: break;
421:
422: case DataBuffer.TYPE_SHORT:
423: case DataBuffer.TYPE_USHORT:
424: short[][] shortData = (short[][]) dataArray;
425: index = 0;
426: while (index < size) {
427: double val = start;
428: for (int i = 0; i < idimension; i++) {
429: for (int j = 0; j < repeatCount; j++) {
430: shortData[band][index] = (short) (val + 0.5);
431: index++;
432: }
433: val += delta;
434: }
435: }
436: break;
437:
438: case DataBuffer.TYPE_INT:
439: int[][] intData = (int[][]) dataArray;
440: index = 0;
441: while (index < size) {
442: double val = start;
443: for (int i = 0; i < idimension; i++) {
444: for (int j = 0; j < repeatCount; j++) {
445: intData[band][index] = (int) (val + 0.5);
446: index++;
447: }
448: val += delta;
449: }
450: }
451: break;
452:
453: case DataBuffer.TYPE_FLOAT:
454: float[][] floatData = (float[][]) dataArray;
455: index = 0;
456: while (index < size) {
457: double val = start;
458: for (int i = 0; i < idimension; i++) {
459: for (int j = 0; j < repeatCount; j++) {
460: floatData[band][index] = (float) val;
461: index++;
462: }
463: val += delta;
464: }
465: }
466: break;
467:
468: case DataBuffer.TYPE_DOUBLE:
469: double[][] doubleData = (double[][]) dataArray;
470: index = 0;
471: while (index < size) {
472: double val = start;
473: for (int i = 0; i < idimension; i++) {
474: for (int j = 0; j < repeatCount; j++) {
475: doubleData[band][index] = val;
476: index++;
477: }
478: val += delta;
479: }
480: }
481: break;
482: default:
483: throw new RuntimeException(JaiI18N
484: .getString("ColorCube5"));
485: }
486: }
487:
488: return dataArray;
489: }
490:
491: /**
492: * Constructs a two-dimensional array of byte data which represent the
493: * contents of a color cube.
494: *
495: * @param offset The initial offset into the data array.
496: * @param dimension An array of signed sizes of each side of the color
497: * cube. The color ramp in each dimension will be increasing or decreasing
498: * according to whether the sign of the corresponding element of the
499: * <code>dimension</code> array is positive or negative, respectively.
500: *
501: * @return A two-dimensional byte array of color cube data.
502: */
503: private static byte[][] createDataArrayByte(int offset,
504: int dimension[]) {
505: return (byte[][]) createDataArray(DataBuffer.TYPE_BYTE, offset,
506: dimension);
507: }
508:
509: /**
510: * Constructs a two-dimensional array of short data which represent the
511: * contents of a color cube.
512: *
513: * @param offset The initial offset into the data array.
514: * @param dimension an array of signed sizes of each side of the color
515: * cube. The color ramp in each dimension will be increasing or decreasing
516: * according to whether the sign of the corresponding element of the
517: * <code>dimension</code> array is positive or negative, respectively.
518: *
519: * @return A two-dimensional short array of color cube data.
520: */
521: private static short[][] createDataArrayShort(int offset,
522: int dimension[]) {
523: return (short[][]) createDataArray(DataBuffer.TYPE_SHORT,
524: offset, dimension);
525: }
526:
527: /**
528: * Constructs a two-dimensional array of unsigned short data which
529: * represent the contents of a color cube.
530: *
531: * @param offset The initial offset into the data array.
532: * @param dimension an array of signed sizes of each side of the color
533: * cube. The color ramp in each dimension will be increasing or decreasing
534: * according to whether the sign of the corresponding element of the
535: * <code>dimension</code> array is positive or negative, respectively.
536: *
537: * @return A two-dimensional short array of color cube data.
538: */
539: private static short[][] createDataArrayUShort(int offset,
540: int dimension[]) {
541: return (short[][]) createDataArray(DataBuffer.TYPE_USHORT,
542: offset, dimension);
543: }
544:
545: /**
546: * Constructs a two-dimensional array of int data which represent the
547: * contents of a color cube.
548: *
549: * @param offset The initial offset into the data array.
550: * @param dimension an array of signed sizes of each side of the color
551: * cube. The color ramp in each dimension will be increasing or decreasing
552: * according to whether the sign of the corresponding element of the
553: * <code>dimension</code> array is positive or negative, respectively.
554: *
555: * @return A two-dimensional int array of color cube data.
556: */
557: private static int[][] createDataArrayInt(int offset,
558: int dimension[]) {
559: return (int[][]) createDataArray(DataBuffer.TYPE_INT, offset,
560: dimension);
561: }
562:
563: /**
564: * Constructs a two-dimensional array of float data which represent the
565: * contents of a color cube.
566: *
567: * @param offset The initial offset into the data array.
568: * @param dimension an array of signed sizes of each side of the color
569: * cube. The color ramp in each dimension will be increasing or decreasing
570: * according to whether the sign of the corresponding element of the
571: * <code>dimension</code> array is positive or negative, respectively.
572: *
573: * @return A two-dimensional float array of color cube data.
574: */
575: private static float[][] createDataArrayFloat(int offset,
576: int dimension[]) {
577: return (float[][]) createDataArray(DataBuffer.TYPE_FLOAT,
578: offset, dimension);
579: }
580:
581: /**
582: * Constructs a two-dimensional array of double data which represent the
583: * contents of a color cube.
584: *
585: * @param offset The initial offset into the data array.
586: * @param dimension an array of signed sizes of each side of the color
587: * cube. The color ramp in each dimension will be increasing or decreasing
588: * according to whether the sign of the corresponding element of the
589: * <code>dimension</code> array is positive or negative, respectively.
590: *
591: * @return A two-dimensional double array of color cube data.
592: */
593: private static double[][] createDataArrayDouble(int offset,
594: int dimension[]) {
595: return (double[][]) createDataArray(DataBuffer.TYPE_DOUBLE,
596: offset, dimension);
597: }
598:
599: /**
600: * Returns a multi-banded byte <code>ColorCube</code> with an index
601: * offset common to all bands.
602: *
603: * @param data The multi-banded byte data in [band][index] format.
604: * @param offset The common offset for all bands.
605: *
606: * @throws IllegalArgumentException if data is null.
607: */
608: protected ColorCube(byte data[][], int offset) {
609: super (data, offset);
610: }
611:
612: /**
613: * Returns a multi-banded short or unsigned short <code>ColorCube</code>
614: * with an index offset common to all bands.
615: *
616: * @param data The multi-banded short data in [band][index] format.
617: * @param offset The common offset for all bands.
618: * @param isUShort True if data type is DataBuffer.TYPE_USHORT;
619: * false if data type is DataBuffer.TYPE_SHORT.
620: *
621: * @throws IllegalArgumentException if data is null.
622: */
623: protected ColorCube(short data[][], int offset, boolean isUShort) {
624: super (data, offset, isUShort);
625: }
626:
627: /**
628: * Returns a multi-banded int <code>ColorCube</code> with an index
629: * offset common to all bands.
630: *
631: * @param data The multi-banded int data in [band][index] format.
632: * @param offset The common offset for all bands.
633: *
634: * @throws IllegalArgumentException if data is null.
635: */
636: protected ColorCube(int data[][], int offset) {
637: super (data, offset);
638: }
639:
640: /**
641: * Returns a multi-banded float <code>ColorCube</code> with an index
642: * offset common to all bands.
643: *
644: * @param data The multi-banded float data in [band][index] format.
645: * @param offset The common offset for all bands.
646: *
647: * @throws IllegalArgumentException if data is null.
648: */
649: protected ColorCube(float data[][], int offset) {
650: super (data, offset);
651: }
652:
653: /**
654: * Returns a multi-banded double <code>ColorCube</code> with an index
655: * offset common to all bands.
656: *
657: * @param data The multi-banded double data in [band][index] format.
658: * @param offset The common offset for all bands.
659: *
660: * @throws IllegalArgumentException if data is null.
661: */
662: protected ColorCube(double data[][], int offset) {
663: super (data, offset);
664: }
665:
666: /**
667: * Initialize the fields of a <code>ColorCube</code>.
668: *
669: * @param offset The common offset for all bands.
670: * @param dimension The signed dimension for each band.
671: */
672: private void initFields(int offset, int[] dimension) {
673: // Save a reference to the dimension array.
674: this .dimension = dimension;
675:
676: // Allocate memory
677: multipliers = new int[dimension.length];
678: dimsLessOne = new int[dimension.length];
679:
680: // Calculate multiplier magnitudes.
681: multipliers[0] = 1;
682: for (int i = 1; i < multipliers.length; i++) {
683: multipliers[i] = multipliers[i - 1]
684: * Math.abs(dimension[i - 1]);
685: }
686:
687: // Set multiplier signs and initialize dimsLessOne.
688: for (int i = 0; i < multipliers.length; i++) {
689: if (dimension[i] < 0) {
690: multipliers[i] = -multipliers[i];
691: }
692: dimsLessOne[i] = Math.abs(dimension[i]) - 1;
693: }
694:
695: // Calculate adjusted offset.
696: adjustedOffset = offset;
697: for (int i = 0; i < dimension.length; i++) {
698: if (dimension[i] > 1 && multipliers[i] < 0) {
699: adjustedOffset += Math.abs(multipliers[i])
700: * dimsLessOne[i];
701: }
702: }
703:
704: // Cache the data type and number of bands to avoid repetitive calls
705: // in findNearestEntry().
706: dataType = getDataType();
707: numBands = getNumBands();
708: }
709:
710: /**
711: * Returns the array of signed dimensions used to construct the
712: * <code>ColorCube</code>.
713: *
714: */
715: public int[] getDimension() {
716: return dimension;
717: }
718:
719: /**
720: * Returns an array containing the signed dimensions, less one.
721: *
722: */
723: public int[] getDimsLessOne() {
724: return dimsLessOne;
725: }
726:
727: /**
728: * Returns the multipliers as an array.
729: *
730: */
731: public int[] getMultipliers() {
732: return multipliers;
733: }
734:
735: /**
736: * Returns the adjusted offset into the lookup table, accounting for
737: * negative dimensions.
738: *
739: */
740: public int getAdjustedOffset() {
741: return adjustedOffset;
742: }
743:
744: /**
745: * Finds the index of the nearest color in the color map to the
746: * pixel value argument.
747: *
748: * @param pixel a float array of all samples of a pixel.
749: * @return the index of the nearest color.
750: *
751: * @throws RuntimeException for dataTypes other than
752: * DataBuffer.TYPE_BYTE DataBuffer.TYPE_USHORT
753: * DataBuffer.TYPE_SHORT DataBuffer.TYPE_INT
754: * DataBuffer.TYPE_FLOAT DataBuffer.TYPE_DOUBLE
755: */
756: public int findNearestEntry(float[] pixel) {
757: int index = -1;
758:
759: index = adjustedOffset;
760:
761: switch (dataType) {
762: case DataBuffer.TYPE_BYTE:
763: for (int band = 0; band < numBands; band++) {
764: int tmp = (int) (pixel[band] * dimsLessOne[band]);
765:
766: if ((tmp & 0xFF) > 127) {
767: tmp += (int) 0x100;
768: }
769:
770: index += (tmp >> 8) * multipliers[band];
771: }
772: break;
773: case DataBuffer.TYPE_SHORT:
774: for (int band = 0; band < numBands; band++) {
775: int tmp = (int) (pixel[band] - Short.MIN_VALUE)
776: * dimsLessOne[band];
777:
778: if ((tmp & 0xFFFF) > Short.MAX_VALUE) {
779: tmp += (int) 0x10000;
780: }
781:
782: index += (tmp >> 16) * multipliers[band];
783: }
784: break;
785: case DataBuffer.TYPE_USHORT:
786: for (int band = 0; band < numBands; band++) {
787: int tmp = (int) (pixel[band] * dimsLessOne[band]);
788:
789: if ((tmp & 0xFFFF) > Short.MAX_VALUE) {
790: tmp += (int) 0x10000;
791: }
792:
793: index += (tmp >> 16) * multipliers[band];
794: }
795: break;
796: case DataBuffer.TYPE_INT:
797: for (int band = 0; band < numBands; band++) {
798: long tmp = (long) ((pixel[band] - Integer.MIN_VALUE) * dimsLessOne[band]);
799:
800: if (tmp > Integer.MAX_VALUE) {
801: tmp += ((long) 0xffffffff + 1L);
802: }
803:
804: index += ((int) (tmp >> 32)) * multipliers[band];
805: }
806: break;
807: case DataBuffer.TYPE_FLOAT:
808: for (int band = 0; band < numBands; band++) {
809: float ftmp = pixel[band] * dimsLessOne[band];
810: int itmp = (int) ftmp;
811:
812: if ((ftmp - itmp) >= 0.5F) {
813: itmp++;
814: }
815:
816: index += itmp * multipliers[band];
817: }
818: break;
819: case DataBuffer.TYPE_DOUBLE:
820: for (int band = 0; band < numBands; band++) {
821: double ftmp = pixel[band] * dimsLessOne[band];
822: int itmp = (int) ftmp;
823:
824: if ((ftmp - itmp) >= 0.5) {
825: itmp++;
826: }
827:
828: index += itmp * multipliers[band];
829: }
830: break;
831: default:
832: throw new RuntimeException(JaiI18N.getString("ColorCube6"));
833: }
834:
835: return index;
836: }
837: }
|