001: /*******************************************************************************
002: * Copyright (c) 2000, 2005 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.swt.internal.image;
011:
012: import org.eclipse.swt.*;
013: import org.eclipse.swt.graphics.*;
014: import java.io.*;
015:
016: final class TIFFDirectory {
017:
018: TIFFRandomFileAccess file;
019: boolean isLittleEndian;
020: ImageLoader loader;
021: int depth;
022:
023: /* Directory fields */
024: int imageWidth;
025: int imageLength;
026: int[] bitsPerSample;
027: int compression;
028: int photometricInterpretation;
029: int[] stripOffsets;
030: int samplesPerPixel;
031: int rowsPerStrip;
032: int[] stripByteCounts;
033: int t4Options;
034: int colorMapOffset;
035:
036: /* Encoder fields */
037: ImageData image;
038: LEDataOutputStream out;
039:
040: static final int NO_VALUE = -1;
041:
042: static final short TAG_ImageWidth = 256;
043: static final short TAG_ImageLength = 257;
044: static final short TAG_BitsPerSample = 258;
045: static final short TAG_Compression = 259;
046: static final short TAG_PhotometricInterpretation = 262;
047: static final short TAG_StripOffsets = 273;
048: static final short TAG_SamplesPerPixel = 277;
049: static final short TAG_RowsPerStrip = 278;
050: static final short TAG_StripByteCounts = 279;
051: static final short TAG_XResolution = 282;
052: static final short TAG_YResolution = 283;
053: static final short TAG_T4Options = 292;
054: static final short TAG_ResolutionUnit = 296;
055: static final short TAG_ColorMap = 320;
056:
057: static final int TYPE_BYTE = 1;
058: static final int TYPE_ASCII = 2;
059: static final int TYPE_SHORT = 3;
060: static final int TYPE_LONG = 4;
061: static final int TYPE_RATIONAL = 5;
062:
063: /* Different compression schemes */
064: static final int COMPRESSION_NONE = 1;
065: static final int COMPRESSION_CCITT_3_1 = 2;
066: static final int COMPRESSION_PACKBITS = 32773;
067:
068: static final int IFD_ENTRY_SIZE = 12;
069:
070: public TIFFDirectory(TIFFRandomFileAccess file,
071: boolean isLittleEndian, ImageLoader loader) {
072: this .file = file;
073: this .isLittleEndian = isLittleEndian;
074: this .loader = loader;
075: }
076:
077: public TIFFDirectory(ImageData image) {
078: this .image = image;
079: }
080:
081: /* PackBits decoder */
082: int decodePackBits(byte[] src, byte[] dest, int offsetDest) {
083: int destIndex = offsetDest;
084: int srcIndex = 0;
085: while (srcIndex < src.length) {
086: byte n = src[srcIndex];
087: if (0 <= n && n <= 127) {
088: /* Copy next n+1 bytes literally */
089: System.arraycopy(src, ++srcIndex, dest, destIndex,
090: n + 1);
091: srcIndex += n + 1;
092: destIndex += n + 1;
093: } else if (-127 <= n && n <= -1) {
094: /* Copy next byte -n+1 times */
095: byte value = src[++srcIndex];
096: for (int j = 0; j < -n + 1; j++) {
097: dest[destIndex++] = value;
098: }
099: srcIndex++;
100: } else {
101: /* Noop when n == -128 */
102: srcIndex++;
103: }
104: }
105: /* Number of bytes copied */
106: return destIndex - offsetDest;
107: }
108:
109: int getEntryValue(int type, byte[] buffer, int index) {
110: return toInt(buffer, index + 8, type);
111: }
112:
113: void getEntryValue(int type, byte[] buffer, int index, int[] values)
114: throws IOException {
115: int start = index + 8;
116: int size;
117: int offset = toInt(buffer, start, TYPE_LONG);
118: switch (type) {
119: case TYPE_SHORT:
120: size = 2;
121: break;
122: case TYPE_LONG:
123: size = 4;
124: break;
125: case TYPE_RATIONAL:
126: size = 8;
127: break;
128: case TYPE_ASCII:
129: case TYPE_BYTE:
130: size = 1;
131: break;
132: default:
133: SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT);
134: return;
135: }
136: if (values.length * size > 4) {
137: buffer = new byte[values.length * size];
138: file.seek(offset);
139: file.read(buffer);
140: start = 0;
141: }
142: for (int i = 0; i < values.length; i++) {
143: values[i] = toInt(buffer, start + i * size, type);
144: }
145: }
146:
147: void decodePixels(ImageData image) throws IOException {
148: /* Each row is byte aligned */
149: byte[] imageData = new byte[(imageWidth * depth + 7) / 8
150: * imageLength];
151: image.data = imageData;
152: int destIndex = 0;
153: int length = stripOffsets.length;
154: for (int i = 0; i < length; i++) {
155: /* Read a strip */
156: byte[] data = new byte[stripByteCounts[i]];
157: file.seek(stripOffsets[i]);
158: file.read(data);
159: if (compression == COMPRESSION_NONE) {
160: System.arraycopy(data, 0, imageData, destIndex,
161: data.length);
162: destIndex += data.length;
163: } else if (compression == COMPRESSION_PACKBITS) {
164: destIndex += decodePackBits(data, imageData, destIndex);
165: } else if (compression == COMPRESSION_CCITT_3_1
166: || compression == 3) {
167: TIFFModifiedHuffmanCodec codec = new TIFFModifiedHuffmanCodec();
168: int nRows = rowsPerStrip;
169: if (i == length - 1) {
170: int n = imageLength % rowsPerStrip;
171: if (n != 0)
172: nRows = n;
173: }
174: destIndex += codec.decode(data, imageData, destIndex,
175: imageWidth, nRows);
176: }
177: if (loader.hasListeners()) {
178: loader.notifyListeners(new ImageLoaderEvent(loader,
179: image, i, i == length - 1));
180: }
181: }
182: }
183:
184: PaletteData getColorMap() throws IOException {
185: int numColors = 1 << bitsPerSample[0];
186: /* R, G, B entries are 16 bit wide (2 bytes) */
187: int numBytes = 3 * 2 * numColors;
188: byte[] buffer = new byte[numBytes];
189: file.seek(colorMapOffset);
190: file.read(buffer);
191: RGB[] colors = new RGB[numColors];
192: /**
193: * SWT does not support 16-bit depth color formats.
194: * Convert the 16-bit data to 8-bit data.
195: * The correct way to do this is to multiply each
196: * 16 bit value by the value:
197: * (2^8 - 1) / (2^16 - 1).
198: * The fast way to do this is just to drop the low
199: * byte of the 16-bit value.
200: */
201: int offset = isLittleEndian ? 1 : 0;
202: int startG = 2 * numColors;
203: int startB = startG + 2 * numColors;
204: for (int i = 0; i < numColors; i++) {
205: int r = buffer[offset] & 0xFF;
206: int g = buffer[startG + offset] & 0xFF;
207: int b = buffer[startB + offset] & 0xFF;
208: colors[i] = new RGB(r, g, b);
209: offset += 2;
210: }
211: return new PaletteData(colors);
212: }
213:
214: PaletteData getGrayPalette() {
215: int numColors = 1 << bitsPerSample[0];
216: RGB[] rgbs = new RGB[numColors];
217: for (int i = 0; i < numColors; i++) {
218: int value = i * 0xFF / (numColors - 1);
219: if (photometricInterpretation == 0)
220: value = 0xFF - value;
221: rgbs[i] = new RGB(value, value, value);
222: }
223: return new PaletteData(rgbs);
224: }
225:
226: PaletteData getRGBPalette(int bitsR, int bitsG, int bitsB) {
227: int blueMask = 0;
228: for (int i = 0; i < bitsB; i++) {
229: blueMask |= 1 << i;
230: }
231: int greenMask = 0;
232: for (int i = bitsB; i < bitsB + bitsG; i++) {
233: greenMask |= 1 << i;
234: }
235: int redMask = 0;
236: for (int i = bitsB + bitsG; i < bitsB + bitsG + bitsR; i++) {
237: redMask |= 1 << i;
238: }
239: return new PaletteData(redMask, greenMask, blueMask);
240: }
241:
242: int formatStrips(int rowByteSize, int nbrRows, byte[] data,
243: int maxStripByteSize, int offsetPostIFD, int extraBytes,
244: int[][] strips) {
245: /*
246: * Calculate the nbr of required strips given the following requirements:
247: * - each strip should, if possible, not be greater than maxStripByteSize
248: * - each strip should contain 1 or more entire rows
249: *
250: * Format the strip fields arrays so that the image data is stored in one
251: * contiguous block. This block is stored after the IFD and after any tag
252: * info described in the IFD.
253: */
254: int n, nbrRowsPerStrip;
255: if (rowByteSize > maxStripByteSize) {
256: /* Each strip contains 1 row */
257: n = data.length / rowByteSize;
258: nbrRowsPerStrip = 1;
259: } else {
260: int nbr = (data.length + maxStripByteSize - 1)
261: / maxStripByteSize;
262: nbrRowsPerStrip = nbrRows / nbr;
263: n = (nbrRows + nbrRowsPerStrip - 1) / nbrRowsPerStrip;
264: }
265: int stripByteSize = rowByteSize * nbrRowsPerStrip;
266:
267: int[] offsets = new int[n];
268: int[] counts = new int[n];
269: /*
270: * Nbr of bytes between the end of the IFD directory and the start of
271: * the image data. Keep space for at least the offsets and counts
272: * data, each field being TYPE_LONG (4 bytes). If other tags require
273: * space between the IFD and the image block, use the extraBytes
274: * parameter.
275: * If there is only one strip, the offsets and counts data is stored
276: * directly in the IFD and we need not reserve space for it.
277: */
278: int postIFDData = n == 1 ? 0 : n * 2 * 4;
279: int startOffset = offsetPostIFD + extraBytes + postIFDData; /* offset of image data */
280:
281: int offset = startOffset;
282: for (int i = 0; i < n; i++) {
283: /*
284: * Store all strips sequentially to allow us
285: * to copy all pixels in one contiguous area.
286: */
287: offsets[i] = offset;
288: counts[i] = stripByteSize;
289: offset += stripByteSize;
290: }
291: /* The last strip may contain fewer rows */
292: int mod = data.length % stripByteSize;
293: if (mod != 0)
294: counts[counts.length - 1] = mod;
295:
296: strips[0] = offsets;
297: strips[1] = counts;
298: return nbrRowsPerStrip;
299: }
300:
301: int[] formatColorMap(RGB[] rgbs) {
302: /*
303: * In a TIFF ColorMap, all red come first, followed by
304: * green and blue. All values must be converted from
305: * 8 bit to 16 bit.
306: */
307: int[] colorMap = new int[rgbs.length * 3];
308: int offsetGreen = rgbs.length;
309: int offsetBlue = rgbs.length * 2;
310: for (int i = 0; i < rgbs.length; i++) {
311: colorMap[i] = rgbs[i].red << 8 | rgbs[i].red;
312: colorMap[i + offsetGreen] = rgbs[i].green << 8
313: | rgbs[i].green;
314: colorMap[i + offsetBlue] = rgbs[i].blue << 8 | rgbs[i].blue;
315: }
316: return colorMap;
317: }
318:
319: void parseEntries(byte[] buffer) throws IOException {
320: for (int offset = 0; offset < buffer.length; offset += IFD_ENTRY_SIZE) {
321: int tag = toInt(buffer, offset, TYPE_SHORT);
322: int type = toInt(buffer, offset + 2, TYPE_SHORT);
323: int count = toInt(buffer, offset + 4, TYPE_LONG);
324: switch (tag) {
325: case TAG_ImageWidth: {
326: imageWidth = getEntryValue(type, buffer, offset);
327: break;
328: }
329: case TAG_ImageLength: {
330: imageLength = getEntryValue(type, buffer, offset);
331: break;
332: }
333: case TAG_BitsPerSample: {
334: if (type != TYPE_SHORT)
335: SWT.error(SWT.ERROR_INVALID_IMAGE);
336: bitsPerSample = new int[count];
337: getEntryValue(type, buffer, offset, bitsPerSample);
338: break;
339: }
340: case TAG_Compression: {
341: compression = getEntryValue(type, buffer, offset);
342: break;
343: }
344: case TAG_PhotometricInterpretation: {
345: photometricInterpretation = getEntryValue(type, buffer,
346: offset);
347: break;
348: }
349: case TAG_StripOffsets: {
350: if (type != TYPE_LONG && type != TYPE_SHORT)
351: SWT.error(SWT.ERROR_INVALID_IMAGE);
352: stripOffsets = new int[count];
353: getEntryValue(type, buffer, offset, stripOffsets);
354: break;
355: }
356: case TAG_SamplesPerPixel: {
357: if (type != TYPE_SHORT)
358: SWT.error(SWT.ERROR_INVALID_IMAGE);
359: samplesPerPixel = getEntryValue(type, buffer, offset);
360: /* Only the basic 1 and 3 values are supported */
361: if (samplesPerPixel != 1 && samplesPerPixel != 3)
362: SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
363: break;
364: }
365: case TAG_RowsPerStrip: {
366: rowsPerStrip = getEntryValue(type, buffer, offset);
367: break;
368: }
369: case TAG_StripByteCounts: {
370: stripByteCounts = new int[count];
371: getEntryValue(type, buffer, offset, stripByteCounts);
372: break;
373: }
374: case TAG_XResolution: {
375: /* Ignored */
376: break;
377: }
378: case TAG_YResolution: {
379: /* Ignored */
380: break;
381: }
382: case TAG_T4Options: {
383: if (type != TYPE_LONG)
384: SWT.error(SWT.ERROR_INVALID_IMAGE);
385: t4Options = getEntryValue(type, buffer, offset);
386: if ((t4Options & 0x1) == 1) {
387: /* 2-dimensional coding is not supported */
388: SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT);
389: }
390: break;
391: }
392: case TAG_ResolutionUnit: {
393: /* Ignored */
394: break;
395: }
396: case TAG_ColorMap: {
397: if (type != TYPE_SHORT)
398: SWT.error(SWT.ERROR_INVALID_IMAGE);
399: /* Get the offset of the colorMap (use TYPE_LONG) */
400: colorMapOffset = getEntryValue(TYPE_LONG, buffer,
401: offset);
402: break;
403: }
404: }
405: }
406: }
407:
408: public ImageData read() throws IOException {
409: /* Set TIFF default values */
410: bitsPerSample = new int[] { 1 };
411: colorMapOffset = NO_VALUE;
412: compression = 1;
413: imageLength = NO_VALUE;
414: imageWidth = NO_VALUE;
415: photometricInterpretation = NO_VALUE;
416: rowsPerStrip = Integer.MAX_VALUE;
417: samplesPerPixel = 1;
418: stripByteCounts = null;
419: stripOffsets = null;
420:
421: byte[] buffer = new byte[2];
422: file.read(buffer);
423: int numberEntries = toInt(buffer, 0, TYPE_SHORT);
424: buffer = new byte[IFD_ENTRY_SIZE * numberEntries];
425: file.read(buffer);
426: parseEntries(buffer);
427:
428: PaletteData palette = null;
429: depth = 0;
430: switch (photometricInterpretation) {
431: case 0:
432: case 1: {
433: /* Bilevel or Grayscale image */
434: palette = getGrayPalette();
435: depth = bitsPerSample[0];
436: break;
437: }
438: case 2: {
439: /* RGB image */
440: if (colorMapOffset != NO_VALUE)
441: SWT.error(SWT.ERROR_INVALID_IMAGE);
442: /* SamplesPerPixel 3 is the only value supported */
443: palette = getRGBPalette(bitsPerSample[0], bitsPerSample[1],
444: bitsPerSample[2]);
445: depth = bitsPerSample[0] + bitsPerSample[1]
446: + bitsPerSample[2];
447: break;
448: }
449: case 3: {
450: /* Palette Color image */
451: if (colorMapOffset == NO_VALUE)
452: SWT.error(SWT.ERROR_INVALID_IMAGE);
453: palette = getColorMap();
454: depth = bitsPerSample[0];
455: break;
456: }
457: default: {
458: SWT.error(SWT.ERROR_INVALID_IMAGE);
459: }
460: }
461:
462: ImageData image = ImageData.internal_new(imageWidth,
463: imageLength, depth, palette, 1, null, 0, null, null,
464: -1, -1, SWT.IMAGE_TIFF, 0, 0, 0, 0);
465: decodePixels(image);
466: return image;
467: }
468:
469: int toInt(byte[] buffer, int i, int type) {
470: if (type == TYPE_LONG) {
471: return isLittleEndian ? (buffer[i] & 0xFF)
472: | ((buffer[i + 1] & 0xFF) << 8)
473: | ((buffer[i + 2] & 0xFF) << 16)
474: | ((buffer[i + 3] & 0xFF) << 24)
475: : (buffer[i + 3] & 0xFF)
476: | ((buffer[i + 2] & 0xFF) << 8)
477: | ((buffer[i + 1] & 0xFF) << 16)
478: | ((buffer[i] & 0xFF) << 24);
479: }
480: if (type == TYPE_SHORT) {
481: return isLittleEndian ? (buffer[i] & 0xFF)
482: | ((buffer[i + 1] & 0xFF) << 8)
483: : (buffer[i + 1] & 0xFF)
484: | ((buffer[i] & 0xFF) << 8);
485: }
486: /* Invalid type */
487: SWT.error(SWT.ERROR_INVALID_IMAGE);
488: return -1;
489: }
490:
491: void write(int photometricInterpretation) throws IOException {
492: boolean isRGB = photometricInterpretation == 2;
493: boolean isColorMap = photometricInterpretation == 3;
494: boolean isBiLevel = photometricInterpretation == 0
495: || photometricInterpretation == 1;
496:
497: int imageWidth = image.width;
498: int imageLength = image.height;
499: int rowByteSize = image.bytesPerLine;
500:
501: int numberEntries = isBiLevel ? 9 : 11;
502: int lengthDirectory = 2 + 12 * numberEntries + 4;
503: /* Offset following the header and the directory */
504: int nextOffset = 8 + lengthDirectory;
505:
506: /* Extra space used by XResolution and YResolution values */
507: int extraBytes = 16;
508:
509: int[] colorMap = null;
510: if (isColorMap) {
511: PaletteData palette = image.palette;
512: RGB[] rgbs = palette.getRGBs();
513: colorMap = formatColorMap(rgbs);
514: /* The number of entries of the Color Map must match the bitsPerSample field */
515: if (colorMap.length != 3 * 1 << image.depth)
516: SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT);
517: /* Extra space used by ColorMap values */
518: extraBytes += colorMap.length * 2;
519: }
520: if (isRGB) {
521: /* Extra space used by BitsPerSample values */
522: extraBytes += 6;
523: }
524: /* TIFF recommends storing the data in strips of no more than 8 Ko */
525: byte[] data = image.data;
526: int[][] strips = new int[2][];
527: int nbrRowsPerStrip = formatStrips(rowByteSize, imageLength,
528: data, 8192, nextOffset, extraBytes, strips);
529: int[] stripOffsets = strips[0];
530: int[] stripByteCounts = strips[1];
531:
532: int bitsPerSampleOffset = NO_VALUE;
533: if (isRGB) {
534: bitsPerSampleOffset = nextOffset;
535: nextOffset += 6;
536: }
537: int stripOffsetsOffset = NO_VALUE, stripByteCountsOffset = NO_VALUE;
538: int xResolutionOffset, yResolutionOffset, colorMapOffset = NO_VALUE;
539: int cnt = stripOffsets.length;
540: if (cnt > 1) {
541: stripOffsetsOffset = nextOffset;
542: nextOffset += 4 * cnt;
543: stripByteCountsOffset = nextOffset;
544: nextOffset += 4 * cnt;
545: }
546: xResolutionOffset = nextOffset;
547: nextOffset += 8;
548: yResolutionOffset = nextOffset;
549: nextOffset += 8;
550: if (isColorMap) {
551: colorMapOffset = nextOffset;
552: nextOffset += colorMap.length * 2;
553: }
554: /* TIFF header */
555: writeHeader();
556:
557: /* Image File Directory */
558: out.writeShort(numberEntries);
559: writeEntry(TAG_ImageWidth, TYPE_LONG, 1, imageWidth);
560: writeEntry(TAG_ImageLength, TYPE_LONG, 1, imageLength);
561: if (isColorMap)
562: writeEntry(TAG_BitsPerSample, TYPE_SHORT, 1, image.depth);
563: if (isRGB)
564: writeEntry(TAG_BitsPerSample, TYPE_SHORT, 3,
565: bitsPerSampleOffset);
566: writeEntry(TAG_Compression, TYPE_SHORT, 1, COMPRESSION_NONE);
567: writeEntry(TAG_PhotometricInterpretation, TYPE_SHORT, 1,
568: photometricInterpretation);
569: writeEntry(TAG_StripOffsets, TYPE_LONG, cnt,
570: cnt > 1 ? stripOffsetsOffset : stripOffsets[0]);
571: if (isRGB)
572: writeEntry(TAG_SamplesPerPixel, TYPE_SHORT, 1, 3);
573: writeEntry(TAG_RowsPerStrip, TYPE_LONG, 1, nbrRowsPerStrip);
574: writeEntry(TAG_StripByteCounts, TYPE_LONG, cnt,
575: cnt > 1 ? stripByteCountsOffset : stripByteCounts[0]);
576: writeEntry(TAG_XResolution, TYPE_RATIONAL, 1, xResolutionOffset);
577: writeEntry(TAG_YResolution, TYPE_RATIONAL, 1, yResolutionOffset);
578: if (isColorMap)
579: writeEntry(TAG_ColorMap, TYPE_SHORT, colorMap.length,
580: colorMapOffset);
581: /* Offset of next IFD (0 for last IFD) */
582: out.writeInt(0);
583:
584: /* Values longer than 4 bytes Section */
585:
586: /* BitsPerSample 8,8,8 */
587: if (isRGB)
588: for (int i = 0; i < 3; i++)
589: out.writeShort(8);
590: if (cnt > 1) {
591: for (int i = 0; i < cnt; i++)
592: out.writeInt(stripOffsets[i]);
593: for (int i = 0; i < cnt; i++)
594: out.writeInt(stripByteCounts[i]);
595: }
596: /* XResolution and YResolution set to 300 dpi */
597: for (int i = 0; i < 2; i++) {
598: out.writeInt(300);
599: out.writeInt(1);
600: }
601: /* ColorMap */
602: if (isColorMap)
603: for (int i = 0; i < colorMap.length; i++)
604: out.writeShort(colorMap[i]);
605:
606: /* Image Data */
607: out.write(data);
608: }
609:
610: void writeEntry(short tag, int type, int count, int value)
611: throws IOException {
612: out.writeShort(tag);
613: out.writeShort(type);
614: out.writeInt(count);
615: out.writeInt(value);
616: }
617:
618: void writeHeader() throws IOException {
619: /* little endian */
620: out.write(0x49);
621: out.write(0x49);
622:
623: /* TIFF identifier */
624: out.writeShort(42);
625: /*
626: * Offset of the first IFD is chosen to be 8.
627: * It is word aligned and immediately after this header.
628: */
629: out.writeInt(8);
630: }
631:
632: void writeToStream(LEDataOutputStream byteStream)
633: throws IOException {
634: out = byteStream;
635: int photometricInterpretation = -1;
636:
637: /* Scanline pad must be 1 */
638: if (image.scanlinePad != 1)
639: SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT);
640: switch (image.depth) {
641: case 1: {
642: /* Palette must be black and white or white and black */
643: PaletteData palette = image.palette;
644: RGB[] rgbs = palette.colors;
645: if (palette.isDirect || rgbs == null || rgbs.length != 2)
646: SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT);
647: RGB rgb0 = rgbs[0];
648: RGB rgb1 = rgbs[1];
649: if (!(rgb0.red == rgb0.green && rgb0.green == rgb0.blue
650: && rgb1.red == rgb1.green
651: && rgb1.green == rgb1.blue && ((rgb0.red == 0x0 && rgb1.red == 0xFF) || (rgb0.red == 0xFF && rgb1.red == 0x0)))) {
652: SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT);
653: }
654: /* 0 means a color index of 0 is imaged as white */
655: photometricInterpretation = image.palette.colors[0].red == 0xFF ? 0
656: : 1;
657: break;
658: }
659: case 4:
660: case 8: {
661: photometricInterpretation = 3;
662: break;
663: }
664: case 24: {
665: photometricInterpretation = 2;
666: break;
667: }
668: default: {
669: SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT);
670: }
671: }
672: write(photometricInterpretation);
673: }
674:
675: }
|