📄 tiffdirectory.java
字号:
/******************************************************************************* * Copyright (c) 2000, 2003 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -