KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > swt > internal > image > TIFFDirectory


1 /*******************************************************************************
2  * Copyright (c) 2000, 2005 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.swt.internal.image;
12
13
14 import org.eclipse.swt.*;
15 import org.eclipse.swt.graphics.*;
16 import java.io.*;
17
18 final class TIFFDirectory {
19
20     TIFFRandomFileAccess file;
21     boolean isLittleEndian;
22     ImageLoader loader;
23     int depth;
24     
25     /* Directory fields */
26     int imageWidth;
27     int imageLength;
28     int[] bitsPerSample;
29     int compression;
30     int photometricInterpretation;
31     int[] stripOffsets;
32     int samplesPerPixel;
33     int rowsPerStrip;
34     int[] stripByteCounts;
35     int t4Options;
36     int colorMapOffset;
37     
38     /* Encoder fields */
39     ImageData image;
40     LEDataOutputStream out;
41     
42     static final int NO_VALUE = -1;
43     
44     static final short TAG_ImageWidth = 256;
45     static final short TAG_ImageLength = 257;
46     static final short TAG_BitsPerSample = 258;
47     static final short TAG_Compression = 259;
48     static final short TAG_PhotometricInterpretation = 262;
49     static final short TAG_StripOffsets = 273;
50     static final short TAG_SamplesPerPixel = 277;
51     static final short TAG_RowsPerStrip = 278;
52     static final short TAG_StripByteCounts = 279;
53     static final short TAG_XResolution = 282;
54     static final short TAG_YResolution = 283;
55     static final short TAG_T4Options = 292;
56     static final short TAG_ResolutionUnit = 296;
57     static final short TAG_ColorMap = 320;
58     
59     static final int TYPE_BYTE = 1;
60     static final int TYPE_ASCII = 2;
61     static final int TYPE_SHORT = 3;
62     static final int TYPE_LONG = 4;
63     static final int TYPE_RATIONAL = 5;
64     
65     /* Different compression schemes */
66     static final int COMPRESSION_NONE = 1;
67     static final int COMPRESSION_CCITT_3_1 = 2;
68     static final int COMPRESSION_PACKBITS = 32773;
69     
70     static final int IFD_ENTRY_SIZE = 12;
71     
72 public TIFFDirectory(TIFFRandomFileAccess file, boolean isLittleEndian, ImageLoader loader) {
73     this.file = file;
74     this.isLittleEndian = isLittleEndian;
75     this.loader = loader;
76 }
77
78 public TIFFDirectory(ImageData image) {
79     this.image = image;
80 }
81
82 /* PackBits decoder */
83 int decodePackBits(byte[] src, byte[] dest, int offsetDest) {
84     int destIndex = offsetDest;
85     int srcIndex = 0;
86     while (srcIndex < src.length) {
87         byte n = src[srcIndex];
88         if (0 <= n && n <= 127) {
89             /* Copy next n+1 bytes literally */
90             System.arraycopy(src, ++srcIndex, dest, destIndex, n + 1);
91             srcIndex += n + 1;
92             destIndex += n + 1;
93         } else if (-127 <= n && n <= -1) {
94             /* Copy next byte -n+1 times */
95             byte value = src[++srcIndex];
96             for (int j = 0; j < -n + 1; j++) {
97                 dest[destIndex++] = value;
98             }
99             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) throws IOException {
114     int start = index + 8;
115     int size;
116     int offset = toInt(buffer, start, TYPE_LONG);
117     switch (type) {
118         case TYPE_SHORT: size = 2; break;
119         case TYPE_LONG: size = 4; break;
120         case TYPE_RATIONAL: size = 8; break;
121         case TYPE_ASCII:
122         case TYPE_BYTE: size = 1; break;
123         default: SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT); return;
124     }
125     if (values.length * size > 4) {
126         buffer = new byte[values.length * size];
127         file.seek(offset);
128         file.read(buffer);
129         start = 0;
130     }
131     for (int i = 0; i < values.length; i++) {
132         values[i] = toInt(buffer, start + i * size, type);
133     }
134 }
135
136 void decodePixels(ImageData image) throws IOException {
137     /* Each row is byte aligned */
138     byte[] imageData = new byte[(imageWidth * depth + 7) / 8 * imageLength];
139     image.data = imageData;
140     int destIndex = 0;
141     int length = stripOffsets.length;
142     for (int i = 0; i < length; i++) {
143         /* Read a strip */
144         byte[] data = new byte[stripByteCounts[i]];
145         file.seek(stripOffsets[i]);
146         file.read(data);
147         if (compression == COMPRESSION_NONE) {
148             System.arraycopy(data, 0, imageData, destIndex, data.length);
149             destIndex += data.length;
150         } else if (compression == COMPRESSION_PACKBITS) {
151             destIndex += decodePackBits(data, imageData, destIndex);
152         } else if (compression == COMPRESSION_CCITT_3_1 || compression == 3) {
153             TIFFModifiedHuffmanCodec codec = new TIFFModifiedHuffmanCodec();
154             int nRows = rowsPerStrip;
155             if (i == length -1) {
156                 int n = imageLength % rowsPerStrip;
157                 if (n != 0) nRows = n;
158             }
159             destIndex += codec.decode(data, imageData, destIndex, imageWidth, nRows);
160         }
161         if (loader.hasListeners()) {
162             loader.notifyListeners(new ImageLoaderEvent(loader, image, i, i == length - 1));
163         }
164     }
165 }
166
167 PaletteData getColorMap() throws IOException {
168     int numColors = 1 << bitsPerSample[0];
169     /* R, G, B entries are 16 bit wide (2 bytes) */
170     int numBytes = 3 * 2 * numColors;
171     byte[] buffer = new byte[numBytes];
172     file.seek(colorMapOffset);
173     file.read(buffer);
174     RGB[] colors = new RGB[numColors];
175     /**
176      * SWT does not support 16-bit depth color formats.
177      * Convert the 16-bit data to 8-bit data.
178      * The correct way to do this is to multiply each
179      * 16 bit value by the value:
180      * (2^8 - 1) / (2^16 - 1).
181      * The fast way to do this is just to drop the low
182      * byte of the 16-bit value.
183      */

184     int offset = isLittleEndian ? 1 : 0;
185     int startG = 2 * numColors;
186     int startB = startG + 2 * numColors;
187     for (int i = 0; i < numColors; i++) {
188         int r = buffer[offset] & 0xFF;
189         int g = buffer[startG + offset] & 0xFF;
190         int b = buffer[startB + offset] & 0xFF;
191         colors[i] = new RGB(r, g, b);
192         offset += 2;
193     }
194     return new PaletteData(colors);
195 }
196
197 PaletteData getGrayPalette() {
198     int numColors = 1 << bitsPerSample[0];
199     RGB[] rgbs = new RGB[numColors];
200     for (int i = 0; i < numColors; i++) {
201         int value = i * 0xFF / (numColors - 1);
202         if (photometricInterpretation == 0) value = 0xFF - value;
203         rgbs[i] = new RGB(value, value, value);
204     }
205     return new PaletteData(rgbs);
206 }
207
208 PaletteData getRGBPalette(int bitsR, int bitsG, int bitsB) {
209     int blueMask = 0;
210     for (int i = 0; i < bitsB; i++) {
211         blueMask |= 1 << i;
212     }
213     int greenMask = 0;
214     for (int i = bitsB; i < bitsB + bitsG; i++) {
215         greenMask |= 1 << i;
216     }
217     int redMask = 0;
218     for (int i = bitsB + bitsG; i < bitsB + bitsG + bitsR; i++) {
219         redMask |= 1 << i;
220     }
221     return new PaletteData(redMask, greenMask, blueMask);
222 }
223
224 int formatStrips(int rowByteSize, int nbrRows, byte[] data, int maxStripByteSize, int offsetPostIFD, int extraBytes, int[][] strips) {
225     /*
226     * Calculate the nbr of required strips given the following requirements:
227     * - each strip should, if possible, not be greater than maxStripByteSize
228     * - each strip should contain 1 or more entire rows
229     *
230     * Format the strip fields arrays so that the image data is stored in one
231     * contiguous block. This block is stored after the IFD and after any tag
232     * info described in the IFD.
233     */

234     int n, nbrRowsPerStrip;
235     if (rowByteSize > maxStripByteSize) {
236         /* Each strip contains 1 row */
237         n = data.length / rowByteSize;
238         nbrRowsPerStrip = 1;
239     } else {
240         int nbr = (data.length + maxStripByteSize - 1) / maxStripByteSize;
241         nbrRowsPerStrip = nbrRows / nbr;
242         n = (nbrRows + nbrRowsPerStrip - 1) / nbrRowsPerStrip;
243     }
244     int stripByteSize = rowByteSize * nbrRowsPerStrip;
245
246     int[] offsets = new int[n];
247     int[] counts = new int[n];
248     /*
249     * Nbr of bytes between the end of the IFD directory and the start of
250     * the image data. Keep space for at least the offsets and counts
251     * data, each field being TYPE_LONG (4 bytes). If other tags require
252     * space between the IFD and the image block, use the extraBytes
253     * parameter.
254     * If there is only one strip, the offsets and counts data is stored
255     * directly in the IFD and we need not reserve space for it.
256     */

257     int postIFDData = n == 1 ? 0 : n * 2 * 4;
258     int startOffset = offsetPostIFD + extraBytes + postIFDData; /* offset of image data */
259     
260     int offset = startOffset;
261     for (int i = 0; i < n; i++) {
262         /*
263         * Store all strips sequentially to allow us
264         * to copy all pixels in one contiguous area.
265         */

266         offsets[i] = offset;
267         counts[i] = stripByteSize;
268         offset += stripByteSize;
269     }
270     /* The last strip may contain fewer rows */
271     int mod = data.length % stripByteSize;
272     if (mod != 0) counts[counts.length - 1] = mod;
273     
274     strips[0] = offsets;
275     strips[1] = counts;
276     return nbrRowsPerStrip;
277 }
278
279 int[] formatColorMap(RGB[] rgbs) {
280     /*
281     * In a TIFF ColorMap, all red come first, followed by
282     * green and blue. All values must be converted from
283     * 8 bit to 16 bit.
284     */

285     int[] colorMap = new int[rgbs.length * 3];
286     int offsetGreen = rgbs.length;
287     int offsetBlue = rgbs.length * 2;
288     for (int i = 0; i < rgbs.length; i++) {
289         colorMap[i] = rgbs[i].red << 8 | rgbs[i].red;
290         colorMap[i + offsetGreen] = rgbs[i].green << 8 | rgbs[i].green;
291         colorMap[i + offsetBlue] = rgbs[i].blue << 8 | rgbs[i].blue;
292     }
293     return colorMap;
294 }
295
296 void parseEntries(byte[] buffer) throws IOException {
297     for (int offset = 0; offset < buffer.length; offset += IFD_ENTRY_SIZE) {
298         int tag = toInt(buffer, offset, TYPE_SHORT);
299         int type = toInt(buffer, offset + 2, TYPE_SHORT);
300         int count = toInt(buffer, offset + 4, TYPE_LONG);
301         switch (tag) {
302             case TAG_ImageWidth: {
303                 imageWidth = getEntryValue(type, buffer, offset);
304                 break;
305             }
306             case TAG_ImageLength: {
307                 imageLength = getEntryValue(type, buffer, offset);
308                 break;
309             }
310             case TAG_BitsPerSample: {
311                 if (type != TYPE_SHORT) SWT.error(SWT.ERROR_INVALID_IMAGE);
312                 bitsPerSample = new int[count];
313                 getEntryValue(type, buffer, offset, bitsPerSample);
314                 break;
315             }
316             case TAG_Compression: {
317                 compression = getEntryValue(type, buffer, offset);
318                 break;
319             }
320             case TAG_PhotometricInterpretation: {
321                 photometricInterpretation = getEntryValue(type, buffer, offset);
322                 break;
323             }
324             case TAG_StripOffsets: {
325                 if (type != TYPE_LONG && type != TYPE_SHORT) SWT.error(SWT.ERROR_INVALID_IMAGE);
326                 stripOffsets = new int[count];
327                 getEntryValue(type, buffer, offset, stripOffsets);
328                 break;
329             }
330             case TAG_SamplesPerPixel: {
331                 if (type != TYPE_SHORT) SWT.error(SWT.ERROR_INVALID_IMAGE);
332                 samplesPerPixel = getEntryValue(type, buffer, offset);
333                 /* Only the basic 1 and 3 values are supported */
334                 if (samplesPerPixel != 1 && samplesPerPixel != 3) SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
335                 break;
336             }
337             case TAG_RowsPerStrip: {
338                 rowsPerStrip = getEntryValue(type, buffer, offset);
339                 break;
340             }
341             case TAG_StripByteCounts: {
342                 stripByteCounts = new int[count];
343                 getEntryValue(type, buffer, offset, stripByteCounts);
344                 break;
345             }
346             case TAG_XResolution: {
347                 /* Ignored */
348                 break;
349             }
350             case TAG_YResolution: {
351                 /* Ignored */
352                 break;
353             }
354             case TAG_T4Options: {
355                 if (type != TYPE_LONG) SWT.error(SWT.ERROR_INVALID_IMAGE);
356                 t4Options = getEntryValue(type, buffer, offset);
357                 if ((t4Options & 0x1) == 1) {
358                     /* 2-dimensional coding is not supported */
359                     SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT);
360                 }
361                 break;
362             }
363             case TAG_ResolutionUnit: {
364                 /* Ignored */
365                 break;
366             }
367             case TAG_ColorMap: {
368                 if (type != TYPE_SHORT) SWT.error(SWT.ERROR_INVALID_IMAGE);
369                 /* Get the offset of the colorMap (use TYPE_LONG) */
370                 colorMapOffset = getEntryValue(TYPE_LONG, buffer, offset);
371                 break;
372             }
373         }
374     }
375 }
376
377 public ImageData read() throws IOException {
378     /* Set TIFF default values */
379     bitsPerSample = new int[] {1};
380     colorMapOffset = NO_VALUE;
381     compression = 1;
382     imageLength = NO_VALUE;
383     imageWidth = NO_VALUE;
384     photometricInterpretation = NO_VALUE;
385     rowsPerStrip = Integer.MAX_VALUE;
386     samplesPerPixel = 1;
387     stripByteCounts = null;
388     stripOffsets = null;
389     
390     byte[] buffer = new byte[2];
391     file.read(buffer);
392     int numberEntries = toInt(buffer, 0, TYPE_SHORT);
393     buffer = new byte[IFD_ENTRY_SIZE * numberEntries];
394     file.read(buffer);
395     parseEntries(buffer);
396     
397     PaletteData palette = null;
398     depth = 0;
399     switch (photometricInterpretation) {
400         case 0:
401         case 1: {
402             /* Bilevel or Grayscale image */
403             palette = getGrayPalette();
404             depth = bitsPerSample[0];
405             break;
406         }
407         case 2: {
408             /* RGB image */
409             if (colorMapOffset != NO_VALUE) SWT.error(SWT.ERROR_INVALID_IMAGE);
410             /* SamplesPerPixel 3 is the only value supported */
411             palette = getRGBPalette(bitsPerSample[0], bitsPerSample[1], bitsPerSample[2]);
412             depth = bitsPerSample[0] + bitsPerSample[1] + bitsPerSample[2];
413             break;
414         }
415         case 3: {
416             /* Palette Color image */
417             if (colorMapOffset == NO_VALUE) SWT.error(SWT.ERROR_INVALID_IMAGE);
418             palette = getColorMap();
419             depth = bitsPerSample[0];
420             break;
421         }
422         default: {
423             SWT.error(SWT.ERROR_INVALID_IMAGE);
424         }
425     }
426
427     ImageData image = ImageData.internal_new(
428             imageWidth,
429             imageLength,
430             depth,
431             palette,
432             1,
433             null,
434             0,
435             null,
436             null,
437             -1,
438             -1,
439             SWT.IMAGE_TIFF,
440             0,
441             0,
442             0,
443             0);
444     decodePixels(image);
445     return image;
446 }
447
448 int toInt(byte[] buffer, int i, int type) {
449     if (type == TYPE_LONG) {
450         return isLittleEndian ?
451         (buffer[i] & 0xFF) | ((buffer[i + 1] & 0xFF) << 8) | ((buffer[i + 2] & 0xFF) << 16) | ((buffer[i + 3] & 0xFF) << 24) :
452         (buffer[i + 3] & 0xFF) | ((buffer[i + 2] & 0xFF) << 8) | ((buffer[i + 1] & 0xFF) << 16) | ((buffer[i] & 0xFF) << 24);
453     }
454     if (type == TYPE_SHORT) {
455         return isLittleEndian ?
456         (buffer[i] & 0xFF) | ((buffer[i + 1] & 0xFF) << 8) :
457         (buffer[i + 1] & 0xFF) | ((buffer[i] & 0xFF) << 8);
458     }
459     /* Invalid type */
460     SWT.error(SWT.ERROR_INVALID_IMAGE);
461     return -1;
462 }
463
464 void write(int photometricInterpretation) throws IOException {
465     boolean isRGB = photometricInterpretation == 2;
466     boolean isColorMap = photometricInterpretation == 3;
467     boolean isBiLevel = photometricInterpretation == 0 || photometricInterpretation == 1;
468
469     int imageWidth = image.width;
470     int imageLength = image.height;
471     int rowByteSize = image.bytesPerLine;
472     
473     int numberEntries = isBiLevel ? 9 : 11;
474     int lengthDirectory = 2 + 12 * numberEntries + 4;
475     /* Offset following the header and the directory */
476     int nextOffset = 8 + lengthDirectory;
477
478     /* Extra space used by XResolution and YResolution values */
479     int extraBytes = 16;
480
481     int[] colorMap = null;
482     if (isColorMap) {
483         PaletteData palette = image.palette;
484         RGB[] rgbs = palette.getRGBs();
485         colorMap = formatColorMap(rgbs);
486         /* The number of entries of the Color Map must match the bitsPerSample field */
487         if (colorMap.length != 3 * 1 << image.depth) SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT);
488         /* Extra space used by ColorMap values */
489         extraBytes += colorMap.length * 2;
490     }
491     if (isRGB) {
492         /* Extra space used by BitsPerSample values */
493         extraBytes += 6;
494     }
495     /* TIFF recommends storing the data in strips of no more than 8 Ko */
496     byte[] data = image.data;
497     int[][] strips = new int[2][];
498     int nbrRowsPerStrip = formatStrips(rowByteSize, imageLength, data, 8192, nextOffset, extraBytes, strips);
499     int[] stripOffsets = strips[0];
500     int[] stripByteCounts = strips[1];
501
502     int bitsPerSampleOffset = NO_VALUE;
503     if (isRGB) {
504         bitsPerSampleOffset = nextOffset;
505         nextOffset += 6;
506     }
507     int stripOffsetsOffset = NO_VALUE, stripByteCountsOffset = NO_VALUE;
508     int xResolutionOffset, yResolutionOffset, colorMapOffset = NO_VALUE;
509     int cnt = stripOffsets.length;
510     if (cnt > 1) {
511         stripOffsetsOffset = nextOffset;
512         nextOffset += 4 * cnt;
513         stripByteCountsOffset = nextOffset;
514         nextOffset += 4 * cnt;
515     }
516     xResolutionOffset = nextOffset;
517     nextOffset += 8;
518     yResolutionOffset = nextOffset;
519     nextOffset += 8;
520     if (isColorMap) {
521         colorMapOffset = nextOffset;
522         nextOffset += colorMap.length * 2;
523     }
524     /* TIFF header */
525     writeHeader();
526     
527     /* Image File Directory */
528     out.writeShort(numberEntries);
529     writeEntry(TAG_ImageWidth, TYPE_LONG, 1, imageWidth);
530     writeEntry(TAG_ImageLength, TYPE_LONG, 1, imageLength);
531     if (isColorMap) writeEntry(TAG_BitsPerSample, TYPE_SHORT, 1, image.depth);
532     if (isRGB) writeEntry(TAG_BitsPerSample, TYPE_SHORT, 3, bitsPerSampleOffset);
533     writeEntry(TAG_Compression, TYPE_SHORT, 1, COMPRESSION_NONE);
534     writeEntry(TAG_PhotometricInterpretation, TYPE_SHORT, 1, photometricInterpretation);
535     writeEntry(TAG_StripOffsets, TYPE_LONG, cnt, cnt > 1 ? stripOffsetsOffset : stripOffsets[0]);
536     if (isRGB) writeEntry(TAG_SamplesPerPixel, TYPE_SHORT, 1, 3);
537     writeEntry(TAG_RowsPerStrip, TYPE_LONG, 1, nbrRowsPerStrip);
538     writeEntry(TAG_StripByteCounts, TYPE_LONG, cnt, cnt > 1 ? stripByteCountsOffset : stripByteCounts[0]);
539     writeEntry(TAG_XResolution, TYPE_RATIONAL, 1, xResolutionOffset);
540     writeEntry(TAG_YResolution, TYPE_RATIONAL, 1, yResolutionOffset);
541     if (isColorMap) writeEntry(TAG_ColorMap, TYPE_SHORT, colorMap.length, colorMapOffset);
542     /* Offset of next IFD (0 for last IFD) */
543     out.writeInt(0);
544     
545     /* Values longer than 4 bytes Section */
546     
547     /* BitsPerSample 8,8,8 */
548     if (isRGB) for (int i = 0; i < 3; i++) out.writeShort(8);
549     if (cnt > 1) {
550         for (int i = 0; i < cnt; i++) out.writeInt(stripOffsets[i]);
551         for (int i = 0; i < cnt; i++) out.writeInt(stripByteCounts[i]);
552     }
553     /* XResolution and YResolution set to 300 dpi */
554     for (int i = 0; i < 2; i++) {
555         out.writeInt(300);
556         out.writeInt(1);
557     }
558     /* ColorMap */
559     if (isColorMap) for (int i = 0; i < colorMap.length; i++) out.writeShort(colorMap[i]);
560     
561     /* Image Data */
562     out.write(data);
563 }
564
565 void writeEntry(short tag, int type, int count, int value) throws IOException {
566     out.writeShort(tag);
567     out.writeShort(type);
568     out.writeInt(count);
569     out.writeInt(value);
570 }
571
572 void writeHeader() throws IOException {
573     /* little endian */
574     out.write(0x49);
575     out.write(0x49);
576
577     /* TIFF identifier */
578     out.writeShort(42);
579     /*
580     * Offset of the first IFD is chosen to be 8.
581     * It is word aligned and immediately after this header.
582     */

583     out.writeInt(8);
584 }
585
586 void writeToStream(LEDataOutputStream byteStream) throws IOException {
587     out = byteStream;
588     int photometricInterpretation = -1;
589     
590     /* Scanline pad must be 1 */
591     if (image.scanlinePad != 1) SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT);
592     switch (image.depth) {
593         case 1: {
594             /* Palette must be black and white or white and black */
595             PaletteData palette = image.palette;
596             RGB[] rgbs = palette.colors;
597             if (palette.isDirect || rgbs == null || rgbs.length != 2) SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT);
598             RGB rgb0 = rgbs[0];
599             RGB rgb1 = rgbs[1];
600             if (!(rgb0.red == rgb0.green && rgb0.green == rgb0.blue &&
601                 rgb1.red == rgb1.green && rgb1.green == rgb1.blue &&
602                 ((rgb0.red == 0x0 && rgb1.red == 0xFF) || (rgb0.red == 0xFF && rgb1.red == 0x0)))) {
603                 SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT);
604             }
605             /* 0 means a color index of 0 is imaged as white */
606             photometricInterpretation = image.palette.colors[0].red == 0xFF ? 0 : 1;
607             break;
608         }
609         case 4:
610         case 8: {
611             photometricInterpretation = 3;
612             break;
613         }
614         case 24: {
615             photometricInterpretation = 2;
616             break;
617         }
618         default: {
619             SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT);
620         }
621     }
622     write(photometricInterpretation);
623 }
624
625 }
626
Popular Tags