| /******************************************************************************* |
| * Copyright (c) 2000, 2005 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.swt.internal.image; |
| |
| |
| import org.eclipse.swt.*; |
| import org.eclipse.swt.graphics.*; |
| import java.io.*; |
| |
| final class TIFFDirectory { |
| |
| TIFFRandomFileAccess file; |
| boolean isLittleEndian; |
| ImageLoader loader; |
| int depth; |
| |
| /* Directory fields */ |
| int imageWidth; |
| int imageLength; |
| int[] bitsPerSample; |
| int compression; |
| int photometricInterpretation; |
| int[] stripOffsets; |
| int samplesPerPixel; |
| int rowsPerStrip; |
| int[] stripByteCounts; |
| int t4Options; |
| int colorMapOffset; |
| |
| /* Encoder fields */ |
| ImageData image; |
| LEDataOutputStream out; |
| |
| static final int NO_VALUE = -1; |
| |
| static final short TAG_ImageWidth = 256; |
| static final short TAG_ImageLength = 257; |
| static final short TAG_BitsPerSample = 258; |
| static final short TAG_Compression = 259; |
| static final short TAG_PhotometricInterpretation = 262; |
| static final short TAG_StripOffsets = 273; |
| static final short TAG_SamplesPerPixel = 277; |
| static final short TAG_RowsPerStrip = 278; |
| static final short TAG_StripByteCounts = 279; |
| static final short TAG_XResolution = 282; |
| static final short TAG_YResolution = 283; |
| static final short TAG_T4Options = 292; |
| static final short TAG_ResolutionUnit = 296; |
| static final short TAG_ColorMap = 320; |
| |
| static final int TYPE_BYTE = 1; |
| static final int TYPE_ASCII = 2; |
| static final int TYPE_SHORT = 3; |
| static final int TYPE_LONG = 4; |
| static final int TYPE_RATIONAL = 5; |
| |
| /* Different compression schemes */ |
| static final int COMPRESSION_NONE = 1; |
| static final int COMPRESSION_CCITT_3_1 = 2; |
| static final int COMPRESSION_PACKBITS = 32773; |
| |
| static final int IFD_ENTRY_SIZE = 12; |
| |
| public TIFFDirectory(TIFFRandomFileAccess file, boolean isLittleEndian, ImageLoader loader) { |
| this.file = file; |
| this.isLittleEndian = isLittleEndian; |
| this.loader = loader; |
| } |
| |
| public TIFFDirectory(ImageData image) { |
| this.image = image; |
| } |
| |
| /* PackBits decoder */ |
| int decodePackBits(byte[] src, byte[] dest, int offsetDest) { |
| int destIndex = offsetDest; |
| int srcIndex = 0; |
| while (srcIndex < src.length) { |
| byte n = src[srcIndex]; |
| if (0 <= n && n <= 127) { |
| /* Copy next n+1 bytes literally */ |
| System.arraycopy(src, ++srcIndex, dest, destIndex, n + 1); |
| srcIndex += n + 1; |
| destIndex += n + 1; |
| } else if (-127 <= n && n <= -1) { |
| /* Copy next byte -n+1 times */ |
| byte value = src[++srcIndex]; |
| for (int j = 0; j < -n + 1; j++) { |
| dest[destIndex++] = value; |
| } |
| srcIndex++; |
| } else { |
| /* Noop when n == -128 */ |
| srcIndex++; |
| } |
| } |
| /* Number of bytes copied */ |
| return destIndex - offsetDest; |
| } |
| |
| int getEntryValue(int type, byte[] buffer, int index) { |
| return toInt(buffer, index + 8, type); |
| } |
| |
| void getEntryValue(int type, byte[] buffer, int index, int[] values) throws IOException { |
| int start = index + 8; |
| int size; |
| int offset = toInt(buffer, start, TYPE_LONG); |
| switch (type) { |
| case TYPE_SHORT: size = 2; break; |
| case TYPE_LONG: size = 4; break; |
| case TYPE_RATIONAL: size = 8; break; |
| case TYPE_ASCII: |
| case TYPE_BYTE: size = 1; break; |
| default: SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT); return; |
| } |
| if (values.length * size > 4) { |
| buffer = new byte[values.length * size]; |
| file.seek(offset); |
| file.read(buffer); |
| start = 0; |
| } |
| for (int i = 0; i < values.length; i++) { |
| values[i] = toInt(buffer, start + i * size, type); |
| } |
| } |
| |
| void decodePixels(ImageData image) throws IOException { |
| /* Each row is byte aligned */ |
| byte[] imageData = new byte[(imageWidth * depth + 7) / 8 * imageLength]; |
| image.data = imageData; |
| int destIndex = 0; |
| int length = stripOffsets.length; |
| for (int i = 0; i < length; i++) { |
| /* Read a strip */ |
| byte[] data = new byte[stripByteCounts[i]]; |
| file.seek(stripOffsets[i]); |
| file.read(data); |
| if (compression == COMPRESSION_NONE) { |
| System.arraycopy(data, 0, imageData, destIndex, data.length); |
| destIndex += data.length; |
| } else if (compression == COMPRESSION_PACKBITS) { |
| destIndex += decodePackBits(data, imageData, destIndex); |
| } else if (compression == COMPRESSION_CCITT_3_1 || compression == 3) { |
| TIFFModifiedHuffmanCodec codec = new TIFFModifiedHuffmanCodec(); |
| int nRows = rowsPerStrip; |
| if (i == length -1) { |
| int n = imageLength % rowsPerStrip; |
| if (n != 0) nRows = n; |
| } |
| destIndex += codec.decode(data, imageData, destIndex, imageWidth, nRows); |
| } |
| if (loader.hasListeners()) { |
| loader.notifyListeners(new ImageLoaderEvent(loader, image, i, i == length - 1)); |
| } |
| } |
| } |
| |
| PaletteData getColorMap() throws IOException { |
| int numColors = 1 << bitsPerSample[0]; |
| /* R, G, B entries are 16 bit wide (2 bytes) */ |
| int numBytes = 3 * 2 * numColors; |
| byte[] buffer = new byte[numBytes]; |
| file.seek(colorMapOffset); |
| file.read(buffer); |
| RGB[] colors = new RGB[numColors]; |
| /** |
| * SWT does not support 16-bit depth color formats. |
| * Convert the 16-bit data to 8-bit data. |
| * The correct way to do this is to multiply each |
| * 16 bit value by the value: |
| * (2^8 - 1) / (2^16 - 1). |
| * The fast way to do this is just to drop the low |
| * byte of the 16-bit value. |
| */ |
| int offset = isLittleEndian ? 1 : 0; |
| int startG = 2 * numColors; |
| int startB = startG + 2 * numColors; |
| for (int i = 0; i < numColors; i++) { |
| int r = buffer[offset] & 0xFF; |
| int g = buffer[startG + offset] & 0xFF; |
| int b = buffer[startB + offset] & 0xFF; |
| colors[i] = new RGB(r, g, b); |
| offset += 2; |
| } |
| return new PaletteData(colors); |
| } |
| |
| PaletteData getGrayPalette() { |
| int numColors = 1 << bitsPerSample[0]; |
| RGB[] rgbs = new RGB[numColors]; |
| for (int i = 0; i < numColors; i++) { |
| int value = i * 0xFF / (numColors - 1); |
| if (photometricInterpretation == 0) value = 0xFF - value; |
| rgbs[i] = new RGB(value, value, value); |
| } |
| return new PaletteData(rgbs); |
| } |
| |
| PaletteData getRGBPalette(int bitsR, int bitsG, int bitsB) { |
| int blueMask = 0; |
| for (int i = 0; i < bitsB; i++) { |
| blueMask |= 1 << i; |
| } |
| int greenMask = 0; |
| for (int i = bitsB; i < bitsB + bitsG; i++) { |
| greenMask |= 1 << i; |
| } |
| int redMask = 0; |
| for (int i = bitsB + bitsG; i < bitsB + bitsG + bitsR; i++) { |
| redMask |= 1 << i; |
| } |
| return new PaletteData(redMask, greenMask, blueMask); |
| } |
| |
| int formatStrips(int rowByteSize, int nbrRows, byte[] data, int maxStripByteSize, int offsetPostIFD, int extraBytes, int[][] strips) { |
| /* |
| * Calculate the nbr of required strips given the following requirements: |
| * - each strip should, if possible, not be greater than maxStripByteSize |
| * - each strip should contain 1 or more entire rows |
| * |
| * Format the strip fields arrays so that the image data is stored in one |
| * contiguous block. This block is stored after the IFD and after any tag |
| * info described in the IFD. |
| */ |
| int n, nbrRowsPerStrip; |
| if (rowByteSize > maxStripByteSize) { |
| /* Each strip contains 1 row */ |
| n = data.length / rowByteSize; |
| nbrRowsPerStrip = 1; |
| } else { |
| int nbr = (data.length + maxStripByteSize - 1) / maxStripByteSize; |
| nbrRowsPerStrip = nbrRows / nbr; |
| n = (nbrRows + nbrRowsPerStrip - 1) / nbrRowsPerStrip; |
| } |
| int stripByteSize = rowByteSize * nbrRowsPerStrip; |
| |
| int[] offsets = new int[n]; |
| int[] counts = new int[n]; |
| /* |
| * Nbr of bytes between the end of the IFD directory and the start of |
| * the image data. Keep space for at least the offsets and counts |
| * data, each field being TYPE_LONG (4 bytes). If other tags require |
| * space between the IFD and the image block, use the extraBytes |
| * parameter. |
| * If there is only one strip, the offsets and counts data is stored |
| * directly in the IFD and we need not reserve space for it. |
| */ |
| int postIFDData = n == 1 ? 0 : n * 2 * 4; |
| int startOffset = offsetPostIFD + extraBytes + postIFDData; /* offset of image data */ |
| |
| int offset = startOffset; |
| for (int i = 0; i < n; i++) { |
| /* |
| * Store all strips sequentially to allow us |
| * to copy all pixels in one contiguous area. |
| */ |
| offsets[i] = offset; |
| counts[i] = stripByteSize; |
| offset += stripByteSize; |
| } |
| /* The last strip may contain fewer rows */ |
| int mod = data.length % stripByteSize; |
| if (mod != 0) counts[counts.length - 1] = mod; |
| |
| strips[0] = offsets; |
| strips[1] = counts; |
| return nbrRowsPerStrip; |
| } |
| |
| int[] formatColorMap(RGB[] rgbs) { |
| /* |
| * In a TIFF ColorMap, all red come first, followed by |
| * green and blue. All values must be converted from |
| * 8 bit to 16 bit. |
| */ |
| int[] colorMap = new int[rgbs.length * 3]; |
| int offsetGreen = rgbs.length; |
| int offsetBlue = rgbs.length * 2; |
| for (int i = 0; i < rgbs.length; i++) { |
| colorMap[i] = rgbs[i].red << 8 | rgbs[i].red; |
| colorMap[i + offsetGreen] = rgbs[i].green << 8 | rgbs[i].green; |
| colorMap[i + offsetBlue] = rgbs[i].blue << 8 | rgbs[i].blue; |
| } |
| return colorMap; |
| } |
| |
| void parseEntries(byte[] buffer) throws IOException { |
| for (int offset = 0; offset < buffer.length; offset += IFD_ENTRY_SIZE) { |
| int tag = toInt(buffer, offset, TYPE_SHORT); |
| int type = toInt(buffer, offset + 2, TYPE_SHORT); |
| int count = toInt(buffer, offset + 4, TYPE_LONG); |
| switch (tag) { |
| case TAG_ImageWidth: { |
| imageWidth = getEntryValue(type, buffer, offset); |
| break; |
| } |
| case TAG_ImageLength: { |
| imageLength = getEntryValue(type, buffer, offset); |
| break; |
| } |
| case TAG_BitsPerSample: { |
| if (type != TYPE_SHORT) SWT.error(SWT.ERROR_INVALID_IMAGE); |
| bitsPerSample = new int[count]; |
| getEntryValue(type, buffer, offset, bitsPerSample); |
| break; |
| } |
| case TAG_Compression: { |
| compression = getEntryValue(type, buffer, offset); |
| break; |
| } |
| case TAG_PhotometricInterpretation: { |
| photometricInterpretation = getEntryValue(type, buffer, offset); |
| break; |
| } |
| case TAG_StripOffsets: { |
| if (type != TYPE_LONG && type != TYPE_SHORT) SWT.error(SWT.ERROR_INVALID_IMAGE); |
| stripOffsets = new int[count]; |
| getEntryValue(type, buffer, offset, stripOffsets); |
| break; |
| } |
| case TAG_SamplesPerPixel: { |
| if (type != TYPE_SHORT) SWT.error(SWT.ERROR_INVALID_IMAGE); |
| samplesPerPixel = getEntryValue(type, buffer, offset); |
| /* Only the basic 1 and 3 values are supported */ |
| if (samplesPerPixel != 1 && samplesPerPixel != 3) SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH); |
| break; |
| } |
| case TAG_RowsPerStrip: { |
| rowsPerStrip = getEntryValue(type, buffer, offset); |
| break; |
| } |
| case TAG_StripByteCounts: { |
| stripByteCounts = new int[count]; |
| getEntryValue(type, buffer, offset, stripByteCounts); |
| break; |
| } |
| case TAG_XResolution: { |
| /* Ignored */ |
| break; |
| } |
| case TAG_YResolution: { |
| /* Ignored */ |
| break; |
| } |
| case TAG_T4Options: { |
| if (type != TYPE_LONG) SWT.error(SWT.ERROR_INVALID_IMAGE); |
| t4Options = getEntryValue(type, buffer, offset); |
| if ((t4Options & 0x1) == 1) { |
| /* 2-dimensional coding is not supported */ |
| SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT); |
| } |
| break; |
| } |
| case TAG_ResolutionUnit: { |
| /* Ignored */ |
| break; |
| } |
| case TAG_ColorMap: { |
| if (type != TYPE_SHORT) SWT.error(SWT.ERROR_INVALID_IMAGE); |
| /* Get the offset of the colorMap (use TYPE_LONG) */ |
| colorMapOffset = getEntryValue(TYPE_LONG, buffer, offset); |
| break; |
| } |
| } |
| } |
| } |
| |
| public ImageData read() throws IOException { |
| /* Set TIFF default values */ |
| bitsPerSample = new int[] {1}; |
| colorMapOffset = NO_VALUE; |
| compression = 1; |
| imageLength = NO_VALUE; |
| imageWidth = NO_VALUE; |
| photometricInterpretation = NO_VALUE; |
| rowsPerStrip = Integer.MAX_VALUE; |
| samplesPerPixel = 1; |
| stripByteCounts = null; |
| stripOffsets = null; |
| |
| byte[] buffer = new byte[2]; |
| file.read(buffer); |
| int numberEntries = toInt(buffer, 0, TYPE_SHORT); |
| buffer = new byte[IFD_ENTRY_SIZE * numberEntries]; |
| file.read(buffer); |
| parseEntries(buffer); |
| |
| PaletteData palette = null; |
| depth = 0; |
| switch (photometricInterpretation) { |
| case 0: |
| case 1: { |
| /* Bilevel or Grayscale image */ |
| palette = getGrayPalette(); |
| depth = bitsPerSample[0]; |
| break; |
| } |
| case 2: { |
| /* RGB image */ |
| if (colorMapOffset != NO_VALUE) SWT.error(SWT.ERROR_INVALID_IMAGE); |
| /* SamplesPerPixel 3 is the only value supported */ |
| palette = getRGBPalette(bitsPerSample[0], bitsPerSample[1], bitsPerSample[2]); |
| depth = bitsPerSample[0] + bitsPerSample[1] + bitsPerSample[2]; |
| break; |
| } |
| case 3: { |
| /* Palette Color image */ |
| if (colorMapOffset == NO_VALUE) SWT.error(SWT.ERROR_INVALID_IMAGE); |
| palette = getColorMap(); |
| depth = bitsPerSample[0]; |
| break; |
| } |
| default: { |
| SWT.error(SWT.ERROR_INVALID_IMAGE); |
| } |
| } |
| |
| ImageData image = ImageData.internal_new( |
| imageWidth, |
| imageLength, |
| depth, |
| palette, |
| 1, |
| null, |
| 0, |
| null, |
| null, |
| -1, |
| -1, |
| SWT.IMAGE_TIFF, |
| 0, |
| 0, |
| 0, |
| 0); |
| decodePixels(image); |
| return image; |
| } |
| |
| int toInt(byte[] buffer, int i, int type) { |
| if (type == TYPE_LONG) { |
| return isLittleEndian ? |
| (buffer[i] & 0xFF) | ((buffer[i + 1] & 0xFF) << 8) | ((buffer[i + 2] & 0xFF) << 16) | ((buffer[i + 3] & 0xFF) << 24) : |
| (buffer[i + 3] & 0xFF) | ((buffer[i + 2] & 0xFF) << 8) | ((buffer[i + 1] & 0xFF) << 16) | ((buffer[i] & 0xFF) << 24); |
| } |
| if (type == TYPE_SHORT) { |
| return isLittleEndian ? |
| (buffer[i] & 0xFF) | ((buffer[i + 1] & 0xFF) << 8) : |
| (buffer[i + 1] & 0xFF) | ((buffer[i] & 0xFF) << 8); |
| } |
| /* Invalid type */ |
| SWT.error(SWT.ERROR_INVALID_IMAGE); |
| return -1; |
| } |
| |
| void write(int photometricInterpretation) throws IOException { |
| boolean isRGB = photometricInterpretation == 2; |
| boolean isColorMap = photometricInterpretation == 3; |
| boolean isBiLevel = photometricInterpretation == 0 || photometricInterpretation == 1; |
| |
| int imageWidth = image.width; |
| int imageLength = image.height; |
| int rowByteSize = image.bytesPerLine; |
| |
| int numberEntries = isBiLevel ? 9 : 11; |
| int lengthDirectory = 2 + 12 * numberEntries + 4; |
| /* Offset following the header and the directory */ |
| int nextOffset = 8 + lengthDirectory; |
| |
| /* Extra space used by XResolution and YResolution values */ |
| int extraBytes = 16; |
| |
| int[] colorMap = null; |
| if (isColorMap) { |
| PaletteData palette = image.palette; |
| RGB[] rgbs = palette.getRGBs(); |
| colorMap = formatColorMap(rgbs); |
| /* The number of entries of the Color Map must match the bitsPerSample field */ |
| if (colorMap.length != 3 * 1 << image.depth) SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT); |
| /* Extra space used by ColorMap values */ |
| extraBytes += colorMap.length * 2; |
| } |
| if (isRGB) { |
| /* Extra space used by BitsPerSample values */ |
| extraBytes += 6; |
| } |
| /* TIFF recommends storing the data in strips of no more than 8 Ko */ |
| byte[] data = image.data; |
| int[][] strips = new int[2][]; |
| int nbrRowsPerStrip = formatStrips(rowByteSize, imageLength, data, 8192, nextOffset, extraBytes, strips); |
| int[] stripOffsets = strips[0]; |
| int[] stripByteCounts = strips[1]; |
| |
| int bitsPerSampleOffset = NO_VALUE; |
| if (isRGB) { |
| bitsPerSampleOffset = nextOffset; |
| nextOffset += 6; |
| } |
| int stripOffsetsOffset = NO_VALUE, stripByteCountsOffset = NO_VALUE; |
| int xResolutionOffset, yResolutionOffset, colorMapOffset = NO_VALUE; |
| int cnt = stripOffsets.length; |
| if (cnt > 1) { |
| stripOffsetsOffset = nextOffset; |
| nextOffset += 4 * cnt; |
| stripByteCountsOffset = nextOffset; |
| nextOffset += 4 * cnt; |
| } |
| xResolutionOffset = nextOffset; |
| nextOffset += 8; |
| yResolutionOffset = nextOffset; |
| nextOffset += 8; |
| if (isColorMap) { |
| colorMapOffset = nextOffset; |
| nextOffset += colorMap.length * 2; |
| } |
| /* TIFF header */ |
| writeHeader(); |
| |
| /* Image File Directory */ |
| out.writeShort(numberEntries); |
| writeEntry(TAG_ImageWidth, TYPE_LONG, 1, imageWidth); |
| writeEntry(TAG_ImageLength, TYPE_LONG, 1, imageLength); |
| if (isColorMap) writeEntry(TAG_BitsPerSample, TYPE_SHORT, 1, image.depth); |
| if (isRGB) writeEntry(TAG_BitsPerSample, TYPE_SHORT, 3, bitsPerSampleOffset); |
| writeEntry(TAG_Compression, TYPE_SHORT, 1, COMPRESSION_NONE); |
| writeEntry(TAG_PhotometricInterpretation, TYPE_SHORT, 1, photometricInterpretation); |
| writeEntry(TAG_StripOffsets, TYPE_LONG, cnt, cnt > 1 ? stripOffsetsOffset : stripOffsets[0]); |
| if (isRGB) writeEntry(TAG_SamplesPerPixel, TYPE_SHORT, 1, 3); |
| writeEntry(TAG_RowsPerStrip, TYPE_LONG, 1, nbrRowsPerStrip); |
| writeEntry(TAG_StripByteCounts, TYPE_LONG, cnt, cnt > 1 ? stripByteCountsOffset : stripByteCounts[0]); |
| writeEntry(TAG_XResolution, TYPE_RATIONAL, 1, xResolutionOffset); |
| writeEntry(TAG_YResolution, TYPE_RATIONAL, 1, yResolutionOffset); |
| if (isColorMap) writeEntry(TAG_ColorMap, TYPE_SHORT, colorMap.length, colorMapOffset); |
| /* Offset of next IFD (0 for last IFD) */ |
| out.writeInt(0); |
| |
| /* Values longer than 4 bytes Section */ |
| |
| /* BitsPerSample 8,8,8 */ |
| if (isRGB) for (int i = 0; i < 3; i++) out.writeShort(8); |
| if (cnt > 1) { |
| for (int i = 0; i < cnt; i++) out.writeInt(stripOffsets[i]); |
| for (int i = 0; i < cnt; i++) out.writeInt(stripByteCounts[i]); |
| } |
| /* XResolution and YResolution set to 300 dpi */ |
| for (int i = 0; i < 2; i++) { |
| out.writeInt(300); |
| out.writeInt(1); |
| } |
| /* ColorMap */ |
| if (isColorMap) for (int i = 0; i < colorMap.length; i++) out.writeShort(colorMap[i]); |
| |
| /* Image Data */ |
| out.write(data); |
| } |
| |
| void writeEntry(short tag, int type, int count, int value) throws IOException { |
| out.writeShort(tag); |
| out.writeShort(type); |
| out.writeInt(count); |
| out.writeInt(value); |
| } |
| |
| void writeHeader() throws IOException { |
| /* little endian */ |
| out.write(0x49); |
| out.write(0x49); |
| |
| /* TIFF identifier */ |
| out.writeShort(42); |
| /* |
| * Offset of the first IFD is chosen to be 8. |
| * It is word aligned and immediately after this header. |
| */ |
| out.writeInt(8); |
| } |
| |
| void writeToStream(LEDataOutputStream byteStream) throws IOException { |
| out = byteStream; |
| int photometricInterpretation = -1; |
| |
| /* Scanline pad must be 1 */ |
| if (image.scanlinePad != 1) SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT); |
| switch (image.depth) { |
| case 1: { |
| /* Palette must be black and white or white and black */ |
| PaletteData palette = image.palette; |
| RGB[] rgbs = palette.colors; |
| if (palette.isDirect || rgbs == null || rgbs.length != 2) SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT); |
| RGB rgb0 = rgbs[0]; |
| RGB rgb1 = rgbs[1]; |
| if (!(rgb0.red == rgb0.green && rgb0.green == rgb0.blue && |
| rgb1.red == rgb1.green && rgb1.green == rgb1.blue && |
| ((rgb0.red == 0x0 && rgb1.red == 0xFF) || (rgb0.red == 0xFF && rgb1.red == 0x0)))) { |
| SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT); |
| } |
| /* 0 means a color index of 0 is imaged as white */ |
| photometricInterpretation = image.palette.colors[0].red == 0xFF ? 0 : 1; |
| break; |
| } |
| case 4: |
| case 8: { |
| photometricInterpretation = 3; |
| break; |
| } |
| case 24: { |
| photometricInterpretation = 2; |
| break; |
| } |
| default: { |
| SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT); |
| } |
| } |
| write(photometricInterpretation); |
| } |
| |
| } |