001: package org.libtiff.jai.codec;
002:
003: import java.io.IOException;
004: import java.awt.image.RenderedImage;
005: import java.awt.Rectangle;
006: import java.awt.Point;
007: import java.awt.image.Raster;
008: import java.awt.image.WritableRaster;
009: import java.awt.image.DataBuffer;
010: import java.awt.image.DataBufferByte;
011: import java.awt.image.DataBufferShort;
012: import java.awt.image.DataBufferUShort;
013: import java.awt.image.SampleModel;
014: import java.awt.image.renderable.ParameterBlock;
015:
016: import javax.media.jai.JAI;
017: import javax.media.jai.RasterFactory;
018:
019: import org.libtiff.jai.util.JaiI18N;
020:
021: /**
022: * Provides a base class for writing TIFF tile codecs, to
023: * be registered with the XTIFFDirectory. This codec allows
024: * for both decoding and (optionally) encoding of tiles, and
025: * also handles the colorspace conversion in decoding.
026: * <p>
027: * At the minimum you will need to implement the two methods
028: * decodeTilePixels() for byte and short data, as well as
029: * the methods register() and create(). If your decoder
030: * requires additional parameters from the tags, set them up in
031: * initializeDecoding(), and initializeEncoding() for encoding.
032: * <p>
033: * To implement encoding, you must override the canEncode() method
034: * to return true, and implement encodeTilePixels().
035: *
036: * @author Niles Ritter
037: * @see XTIFFTileCodec
038: */
039: public abstract class XTIFFTileCodecImpl implements XTIFFTileCodec {
040:
041: //////////////////////////////////////////////////////
042: //// Implementation Section
043: //// Override or implement methods here
044: //////////////////////////////////////////////////////
045:
046: /**
047: * Registration method. Must be implemented by the
048: * extended class to register itself with the
049: * XTIFFDirectory for all compression codes it
050: * supports (e.g Fax codec supports 3 codes).
051: *
052: * @see XTIFFDirectory
053: */
054: public abstract void register();
055:
056: /**
057: * Implement this to return the corresponding empty
058: * codec object.
059: */
060: public abstract XTIFFTileCodec create();
061:
062: /**
063: * Indicate whether this codec can encode data.
064: * Override to return true only if your codec implments encoding.
065: */
066: public boolean canEncode() {
067: return false;
068: }
069:
070: /**
071: * The initialization method particular to decoding.
072: * Extend for whatever compression-specific information
073: * or parameters is needed. The decoding parameter has
074: * already been assigned at this point, as well as the
075: * XTIFFDirectory parsed from the input stream, and so
076: * all XTIFFFields are available.
077: */
078: public void initializeDecoding() {
079: }
080:
081: /**
082: * The initialization method particular to encoding.
083: * Extend for whatever compression-specific information
084: * or parameters is needed. The decoding parameter has
085: * already been assigned at this point, as well as the
086: * XTIFFDirectory parsed from the input stream, and so
087: * all XTIFFFields are available.
088: */
089: public void initializeEncoding() {
090: }
091:
092: /**
093: * decode bpixel byte array of data into pixels, packed
094: * for 1,2,4 8 bit pixels. Must implment this.
095: * @param bpixels the byte array of compressed input data
096: * @param rect the rectangular shape of the target pixels
097: * @param pixels the target decompressed pixels.
098: */
099: public abstract void decodeTilePixels(byte[] bpixels,
100: Rectangle rect, byte[] pixels);
101:
102: /**
103: * decode bpixel byte array of data into pixels, packed
104: * for 16 bit pixels. Must implment this.
105: * @param bpixels the byte array of compressed input data
106: * @param rect the rectangular shape of the target pixels
107: * @param pixels the target decompressed pixels.
108: */
109: public abstract void decodeTilePixels(byte[] bpixels,
110: Rectangle rect, short[] pixels);
111:
112: /**
113: * encode the tile in pixels into bpixels and return the byte
114: * size of the compressed data.
115: * Override this method if canEncode() = true;
116: * @param pixels input pixels
117: * @param rect the array dimensions of samples
118: * @param bpixels the target array of compressed byte data
119: */
120:
121: public int encodeTilePixels(int[] pixels, Rectangle rect,
122: byte[] bpixels) {
123: return 0;
124: }
125:
126: //////////////////////////////////////////////////////
127: //// Common Section
128: //////////////////////////////////////////////////////
129:
130: protected XTIFFDirectory directory = null;
131: protected RenderedImage image = null;
132: protected int minY;
133: protected int minX;
134: protected int width;
135: protected int length;
136: protected int numBands;
137: protected int tileLength;
138: protected int tileWidth;
139: protected int compression;
140: protected SampleModel sampleModel;
141: protected int[] sampleSize;
142: protected char[] bitsPerSample;
143: protected char[] colormap = null;
144:
145: /**
146: * The empty constructor.
147: */
148: public XTIFFTileCodecImpl() {
149: }
150:
151: /**
152: * The method for initializing information common
153: * to both encoder and decoder.
154: */
155: public void initialize() {
156: width = (int) getLongField(XTIFF.TIFFTAG_IMAGE_WIDTH);
157: length = (int) getLongField(XTIFF.TIFFTAG_IMAGE_LENGTH);
158: isTiled = directory.isTiled();
159: if (isTiled) {
160: tileWidth = (int) getLongField(XTIFF.TIFFTAG_TILE_WIDTH);
161: tileLength = (int) getLongField(XTIFF.TIFFTAG_TILE_LENGTH);
162: } else {
163: tileWidth = width;
164: tileLength = (int) getLongField(XTIFF.TIFFTAG_ROWS_PER_STRIP);
165: }
166: // Figure out what compression if any, is being used.
167: XTIFFField compField = directory
168: .getField(XTIFF.TIFFTAG_COMPRESSION);
169: if (compField != null) {
170: compression = compField.getAsInt(0);
171: } else {
172: compression = XTIFF.COMPRESSION_NONE;
173: }
174: XTIFFField cfield = directory.getField(XTIFF.TIFFTAG_COLORMAP);
175: if (cfield != null)
176: colormap = cfield.getAsChars();
177:
178: // Read the TIFFTAG_BITS_PER_SAMPLE field
179: XTIFFField bitsField = directory
180: .getField(XTIFF.TIFFTAG_BITS_PER_SAMPLE);
181:
182: if (bitsField == null) {
183: // Default
184: bitsPerSample = new char[1];
185: bitsPerSample[0] = 1;
186: } else {
187: bitsPerSample = bitsField.getAsChars();
188: }
189: image_type = directory.getImageType();
190: }
191:
192: /**
193: * A common utility method for accessing the XTIFFFields
194: * in the current image directory.
195: */
196: protected long getLongField(int fld) {
197: XTIFFField field = directory.getField(fld);
198: if (field == null)
199: return 0;
200: else
201: return field.getAsLong(0);
202: }
203:
204: /**
205: * This method may be used by the implementations register()
206: * method to register itself with the XTIFFDirectory.
207: * @see XTIFFDirectory
208: */
209: public void register(int comp) {
210: XTIFFDirectory.registerTileCodec(comp, this );
211: }
212:
213: /**
214: * One-time common image parameter setup
215: * @param img the source image that will be
216: * encoded into a TIFF formatted stream, or
217: * the TIFF image from which Raster tiles
218: * will be decoded.
219: */
220: protected void setupSourceImage(RenderedImage img) {
221: image = img;
222:
223: // Get raster parameters
224: minY = image.getMinY();
225: minX = image.getMinX();
226: sampleModel = image.getSampleModel();
227: numBands = sampleModel.getNumBands();
228: sampleSize = sampleModel.getSampleSize();
229:
230: }
231:
232: /**
233: * Returns the TIFF compression type
234: */
235: public int getCompression() {
236: return compression;
237: }
238:
239: //////////////////////////////////////////////////////
240: //// Encoding Section
241: //////////////////////////////////////////////////////
242:
243: protected XTIFFEncodeParam encodeParam = null;
244: private int _pixels[];
245: protected boolean isTiled;
246:
247: /**
248: * The method for creating an encoder from
249: * the XTIFFEncodeParam information.
250: */
251: public XTIFFTileCodec create(XTIFFEncodeParam param)
252: throws IOException {
253: XTIFFTileCodecImpl codec = (XTIFFTileCodecImpl) create();
254: codec.initialize(param);
255: return codec;
256: }
257:
258: protected void initialize(XTIFFEncodeParam param)
259: throws IOException {
260: if (!canEncode())
261: throw new IOException("encoding not supported");
262: encodeParam = param;
263: directory = param.getDirectory();
264: initialize();
265: initializeEncoding();
266: }
267:
268: /**
269: * Encode the data into buffer and return byte count
270: * Normally you will not need to override this method,
271: * but instead implement the <code>encodeTilePixels()</code> method.
272: */
273: public int encode(RenderedImage img, Rectangle rect, byte[] bpixels) {
274: if (image == null) {
275: setupSourceImage(img);
276: setupBufferForEncoding();
277: }
278:
279: // Fill tile buffer, padding right with zeroes.
280: getTilePixels(rect);
281:
282: // encode and return number of bytes compressed
283: return encodeTilePixels(_pixels, rect, bpixels);
284: }
285:
286: /**
287: * One-time setup for encoding
288: */
289: protected void setupBufferForEncoding() {
290: // Set up input tile/strip buffer
291: _pixels = new int[tileWidth * tileLength * numBands];
292:
293: // if padding necessary do it now.
294: int padRight = (tileWidth - (width % tileWidth)) % tileWidth;
295: int padBottom = (tileLength - (length % tileLength))
296: % tileLength;
297: if (!isTiled)
298: padBottom = 0;
299: if (padRight > 0 || padBottom > 0) {
300: ParameterBlock pb = new ParameterBlock();
301: pb.addSource(image);
302: pb.add(null).add(padRight).add(null).add(padBottom).add(
303: null).add(null);
304: image = JAI.create("border", pb);
305: }
306: }
307:
308: /**
309: * Get the portion of tile fitting into buffer.
310: * You probably won't need to override this.
311: * @param rect the region to extract from image.
312: */
313:
314: protected void getTilePixels(Rectangle rect) {
315: // Grab the pixels
316: Raster src = image.getData(rect);
317: int col = (int) rect.getX();
318: int row = (int) rect.getY();
319: int rows = (int) rect.getHeight();
320: int cols = (int) rect.getWidth();
321: src.getPixels(col, row, cols, rows, _pixels);
322: }
323:
324: /**
325: * If derived classes can make a better estimate
326: * for the maximum size of a compressed tile,
327: * they should override this, which assumes
328: * conservatively that it won't be worse than
329: * twice the original size.
330: * @param im the rendered image containing the image data
331: */
332: public int getCompressedTileSize(RenderedImage im) {
333: sampleModel = im.getSampleModel();
334: numBands = sampleModel.getNumBands();
335: sampleSize = sampleModel.getSampleSize();
336: return (int) Math.ceil(2 * tileWidth * tileLength * numBands
337: * (sampleSize[0] / 8.0));
338: }
339:
340: //////////////////////////////////////////////////////
341: //// Decoding Section
342: //////////////////////////////////////////////////////
343:
344: protected XTIFFDecodeParam decodeParam = null;
345: protected boolean decodePaletteAsShorts = false;
346: protected int unitsInThisTile;
347: protected byte _bdata[] = null;
348: protected short _sdata[] = null;
349: protected byte[] bpixvals = null;
350: protected short[] spixvals = null;
351: protected DataBuffer buffer = null;
352: protected int dataType;
353: protected int image_type;
354:
355: /**
356: * The standard decoder creation method
357: */
358: public XTIFFTileCodec create(XTIFFDecodeParam param)
359: throws IOException {
360: XTIFFTileCodecImpl codec = (XTIFFTileCodecImpl) create();
361: codec.initialize(param);
362: return codec;
363: }
364:
365: protected void initialize(XTIFFDecodeParam param)
366: throws IOException {
367: decodeParam = param;
368: decodePaletteAsShorts = param.getDecodePaletteAsShorts();
369: directory = param.getDirectory();
370: initialize();
371: initializeDecoding();
372: }
373:
374: /**
375: * One-time setup for encoding. Some configurations
376: * require a temp array for unpacking 16-bit palette data.
377: */
378: protected void setupBufferForDecoding() {
379:
380: int length;
381: buffer = sampleModel.createDataBuffer();
382: dataType = sampleModel.getDataType();
383:
384: if (dataType == DataBuffer.TYPE_BYTE) {
385: _bdata = ((DataBufferByte) buffer).getData();
386: bpixvals = _bdata;
387: } else if (dataType == DataBuffer.TYPE_USHORT) {
388: _sdata = ((DataBufferUShort) buffer).getData();
389: if (!decodePaletteAsShorts)
390: spixvals = _sdata;
391: } else if (dataType == DataBuffer.TYPE_SHORT) {
392: _sdata = ((DataBufferShort) buffer).getData();
393: if (!decodePaletteAsShorts)
394: spixvals = _sdata;
395: }
396: if (decodePaletteAsShorts) {
397: int len = _sdata.length;
398: if (bitsPerSample[0] == 16)
399: spixvals = new short[len];
400: else
401: bpixvals = new byte[len];
402: }
403: }
404:
405: /**
406: * Decode a rectangle of data stored in bpixels
407: * into a raster tile. Usually you will not need
408: * to override this, but instead implement the
409: * decodeTilePixels methods.
410: */
411: public WritableRaster decode(RenderedImage img, Rectangle newRect,
412: byte[] bpixels) {
413: if (image == null) {
414: setupSourceImage(img);
415: }
416:
417: setupBufferForDecoding(); //set up every time
418:
419: unitsInThisTile = newRect.width * newRect.height * numBands;
420:
421: // uncompress data
422: decodeTilePixels(bpixels, newRect);
423:
424: // post-processing of color data
425: decodeColor(newRect);
426:
427: // put buffer into a tile
428: return setTilePixels(newRect);
429: }
430:
431: /**
432: * Postprocess the uncompressed color data into
433: * the appropriate display color model. This implementation
434: * Does a number of things:
435: * <ul>
436: * <li> For RGB color, reverse to BGR which apparently
437: * is faster for Java 2D display
438: * <li> For one-bit WHITE_IS_ZERO data, flip the values
439: * so that they will look correct
440: * <li> If the decodePaletteAsShorts flag is true then
441: * unpack the bits and apply the lookup table, as
442: * 16-bit lookup is not supported in JAI.
443: * </ul>
444: * Override this if you have other color types.
445: * @see XTIFFDecodeParam
446: */
447: protected void decodeColor(Rectangle newRect) {
448: switch (dataType) {
449: case DataBuffer.TYPE_BYTE:
450: decodeColor(bpixvals, _bdata, newRect);
451: break;
452: case DataBuffer.TYPE_SHORT:
453: case DataBuffer.TYPE_USHORT:
454: if (bpixvals != null)
455: decodeColor(bpixvals, _sdata, newRect);
456: else
457: decodeColor(spixvals, _sdata, newRect);
458: }
459: }
460:
461: /**
462: * Decode a tile of data into either byte or short pixel buffers.
463: * Override this if you have other buffer types (e.g. int)
464: */
465: protected void decodeTilePixels(byte[] bpixels, Rectangle newRect) {
466:
467: // decodeTilePixels into the appropriate buffer
468: if (bpixvals != null)
469: decodeTilePixels(bpixels, newRect, bpixvals);
470: else
471: decodeTilePixels(bpixels, newRect, spixvals);
472: }
473:
474: /**
475: * Take the values from the buffer and store them in
476: * a WritableRaster object.
477: */
478: protected WritableRaster setTilePixels(Rectangle rect) {
479: return (WritableRaster) RasterFactory.createWritableRaster(
480: sampleModel, buffer, new Point((int) rect.getX(),
481: (int) rect.getY()));
482: }
483:
484: /**
485: * A useful Method to interpret a byte array as shorts. Method depends on
486: * whether the bytes are stored in a big endian or little endian format.
487: */
488:
489: protected void unpackShorts(byte byteArray[], short output[],
490: int shortCount) {
491:
492: int j;
493: int firstByte, secondByte;
494:
495: if (directory.isBigEndian()) {
496:
497: for (int i = 0; i < shortCount; i++) {
498: j = 2 * i;
499: firstByte = byteArray[j] & 0xff;
500: secondByte = byteArray[j + 1] & 0xff;
501: output[i] = (short) ((firstByte << 8) + secondByte);
502: }
503:
504: } else {
505:
506: for (int i = 0; i < shortCount; i++) {
507: j = 2 * i;
508: firstByte = byteArray[j] & 0xff;
509: secondByte = byteArray[j + 1] & 0xff;
510: output[i] = (short) ((secondByte << 8) + firstByte);
511: }
512: }
513: }
514:
515: //////////////////////////////////////////////////////////////////////////
516: ///// Color decoding section
517: //////////////////////////////////////////////////////////////////////////
518:
519: /**
520: * Decode short pixel data, or interpret palette data
521: * as short from byte.
522: */
523: protected void decodeColor(byte[] bpix, short[] sdata,
524: Rectangle newRect) {
525: short sswap;
526:
527: switch (image_type) {
528: case XTIFF.TYPE_PALETTE:
529: if (bitsPerSample[0] == 8) {
530:
531: // At this point the data is 1 banded and will
532: // become 3 banded only after we've done the palette
533: // lookup, since unitsInThisTile was calculated with
534: // 3 bands, we need to divide this by 3.
535: int unitsBeforeLookup = unitsInThisTile / 3;
536:
537: // Expand the palette image into an rgb image with ushort
538: // data type.
539: int cmapValue;
540: int count = 0, lookup, len = colormap.length / 3;
541: int len2 = len * 2;
542: for (int i = 0; i < unitsBeforeLookup; i++) {
543: // Get the index into the colormap
544: lookup = bpix[i] & 0xff;
545: // Get the blue value
546: cmapValue = colormap[lookup + len2];
547: sdata[count++] = (short) (cmapValue & 0xffff);
548: // Get the green value
549: cmapValue = colormap[lookup + len];
550: sdata[count++] = (short) (cmapValue & 0xffff);
551: // Get the red value
552: cmapValue = colormap[lookup];
553: sdata[count++] = (short) (cmapValue & 0xffff);
554: }
555:
556: } else if (bitsPerSample[0] == 4) {
557:
558: int padding = newRect.width % 2;
559: int bytesPostDecoding = ((newRect.width + 1) / 2)
560: * newRect.height;
561:
562: int bytes = unitsInThisTile / 3;
563:
564: // Unpack the 2 pixels packed into each byte.
565: byte[] data = new byte[bytes];
566:
567: int srcCount = 0, dstCount = 0;
568: for (int j = 0; j < newRect.height; j++) {
569: for (int i = 0; i < newRect.width / 2; i++) {
570: data[dstCount++] = (byte) ((bpix[srcCount] & 0xf0) >> 4);
571: data[dstCount++] = (byte) (bpix[srcCount++] & 0x0f);
572: }
573:
574: if (padding == 1) {
575: data[dstCount++] = (byte) ((bpix[srcCount++] & 0xf0) >> 4);
576: }
577: }
578:
579: int len = colormap.length / 3;
580: int len2 = len * 2;
581: int cmapValue, lookup;
582: int count = 0;
583: for (int i = 0; i < bytes; i++) {
584: lookup = data[i] & 0xff;
585: cmapValue = colormap[lookup + len2];
586: sdata[count++] = (short) (cmapValue & 0xffff);
587: cmapValue = colormap[lookup + len];
588: sdata[count++] = (short) (cmapValue & 0xffff);
589: cmapValue = colormap[lookup];
590: sdata[count++] = (short) (cmapValue & 0xffff);
591: }
592: } else {
593: throw new RuntimeException(JaiI18N
594: .getString("XTIFFImageDecoder7"));
595: }
596: break;
597: }
598: }
599:
600: /**
601: * Decode short color data, or interpret palette data
602: * as short.
603: */
604: protected void decodeColor(short[] spix, short[] sdata,
605: Rectangle newRect) {
606: short sswap;
607:
608: switch (image_type) {
609: case XTIFF.TYPE_GREYSCALE_WHITE_IS_ZERO:
610: case XTIFF.TYPE_GREYSCALE_BLACK_IS_ZERO:
611: // Since we are using a ComponentColorModel with this image,
612: // we need to change the WhiteIsZero data to BlackIsZero data
613: // so it will display properly.
614: if (image_type == XTIFF.TYPE_GREYSCALE_WHITE_IS_ZERO) {
615:
616: if (dataType == DataBuffer.TYPE_USHORT) {
617:
618: for (int l = 0; l < sdata.length; l++) {
619: sdata[l] = (short) (65535 - spix[l]);
620: }
621:
622: } else if (dataType == DataBuffer.TYPE_SHORT) {
623:
624: for (int l = 0; l < sdata.length; l++) {
625: sdata[l] = (short) (~spix[l]);
626: }
627: }
628: }
629:
630: break;
631:
632: case XTIFF.TYPE_RGB:
633: // Change to BGR order, as Java2D displays that faster
634: for (int i = 0; i < unitsInThisTile; i += 3) {
635: sswap = spix[i];
636: sdata[i] = spix[i + 2];
637: sdata[i + 2] = sswap;
638: }
639: break;
640:
641: case XTIFF.TYPE_ORGB:
642: case XTIFF.TYPE_ARGB_PRE:
643: case XTIFF.TYPE_ARGB:
644: // Change from RGBA to ABGR for Java2D's faster special cases
645: for (int i = 0; i < unitsInThisTile; i += 4) {
646: // Swap R and A
647: sswap = spix[i];
648: sdata[i] = spix[i + 3];
649: sdata[i + 3] = sswap;
650:
651: // Swap G and B
652: sswap = spix[i + 1];
653: sdata[i + 1] = spix[i + 2];
654: sdata[i + 2] = sswap;
655: }
656: break;
657:
658: case XTIFF.TYPE_RGB_EXTRA:
659: break;
660:
661: case XTIFF.TYPE_PALETTE:
662: if (decodePaletteAsShorts) {
663:
664: // At this point the data is 1 banded and will
665: // become 3 banded only after we've done the palette
666: // lookup, since unitsInThisTile was calculated with
667: // 3 bands, we need to divide this by 3.
668: int unitsBeforeLookup = unitsInThisTile / 3;
669:
670: // Since unitsBeforeLookup is the number of shorts,
671: // but we do our decompression in terms of bytes, we
672: // need to multiply it by 2 in order to figure out
673: // how many bytes we'll get after decompression.
674: int entries = unitsBeforeLookup * 2;
675:
676: if (dataType == DataBuffer.TYPE_USHORT) {
677:
678: // Expand the palette image into an rgb image with ushort
679: // data type.
680: int cmapValue;
681: int count = 0, lookup, len = colormap.length / 3;
682: int len2 = len * 2;
683: for (int i = 0; i < unitsBeforeLookup; i++) {
684: // Get the index into the colormap
685: lookup = spix[i] & 0xffff;
686: // Get the blue value
687: cmapValue = colormap[lookup + len2];
688: sdata[count++] = (short) (cmapValue & 0xffff);
689: // Get the green value
690: cmapValue = colormap[lookup + len];
691: sdata[count++] = (short) (cmapValue & 0xffff);
692: // Get the red value
693: cmapValue = colormap[lookup];
694: sdata[count++] = (short) (cmapValue & 0xffff);
695: }
696:
697: } else if (dataType == DataBuffer.TYPE_SHORT) {
698:
699: // Expand the palette image into an rgb image with
700: // short data type.
701: int cmapValue;
702: int count = 0, lookup, len = colormap.length / 3;
703: int len2 = len * 2;
704: for (int i = 0; i < unitsBeforeLookup; i++) {
705: // Get the index into the colormap
706: lookup = spix[i] & 0xffff;
707: // Get the blue value
708: cmapValue = colormap[lookup + len2];
709: sdata[count++] = (short) cmapValue;
710: // Get the green value
711: cmapValue = colormap[lookup + len];
712: sdata[count++] = (short) cmapValue;
713: // Get the red value
714: cmapValue = colormap[lookup];
715: sdata[count++] = (short) cmapValue;
716: }
717: }//dataType
718: }//decodePaletteAsShorts
719: break;
720:
721: case XTIFF.TYPE_TRANS:
722: break;
723: }
724: }
725:
726: /**
727: * Decode byte color data
728: */
729: protected void decodeColor(byte[] bpix, byte[] bdata,
730: Rectangle newRect) {
731: byte bswap;
732:
733: switch (image_type) {
734: case XTIFF.TYPE_BILEVEL_WHITE_IS_ZERO:
735: case XTIFF.TYPE_BILEVEL_BLACK_IS_ZERO:
736: case XTIFF.TYPE_GREYSCALE_WHITE_IS_ZERO:
737: case XTIFF.TYPE_GREYSCALE_BLACK_IS_ZERO:
738: case XTIFF.TYPE_RGB_EXTRA:
739: case XTIFF.TYPE_TRANS:
740: //nothing
741: break;
742:
743: case XTIFF.TYPE_RGB:
744: if (bitsPerSample[0] == 8) {
745:
746: // Change to BGR order, as Java2D displays that faster
747: for (int i = 0; i < unitsInThisTile; i += 3) {
748: bswap = bpix[i];
749: bdata[i] = bpix[i + 2];
750: bdata[i + 2] = bswap;
751: }
752:
753: }
754: break;
755:
756: case XTIFF.TYPE_ORGB:
757: case XTIFF.TYPE_ARGB_PRE:
758: case XTIFF.TYPE_ARGB:
759: if (bitsPerSample[0] == 8) {
760: // Convert from RGBA to ABGR for Java2D
761: for (int i = 0; i < unitsInThisTile; i += 4) {
762: // Swap R and A
763: bswap = bpix[i];
764: bdata[i] = bpix[i + 3];
765: bdata[i + 3] = bswap;
766:
767: // Swap G and B
768: bswap = bpix[i + 1];
769: bdata[i + 1] = bpix[i + 2];
770: bdata[i + 2] = bswap;
771: }
772: }
773: break;
774:
775: case XTIFF.TYPE_PALETTE:
776: //
777: break;
778:
779: }//switch
780: }//decodeColor
781:
782: }
|