geotiffimagereader.java
来自「world wind java sdk 源码」· Java 代码 · 共 686 行 · 第 1/2 页
JAVA
686 行
/* Copyright (C) 2001, 2008 United States Government as represented by the Administrator of the National Aeronautics and Space Administration. All Rights Reserved. */package gov.nasa.worldwind.formats.tiff;import javax.imageio.*;import javax.imageio.metadata.*;import javax.imageio.spi.*;import javax.imageio.stream.*;import java.awt.*;import java.awt.color.*;import java.awt.image.*;import java.io.*;import java.nio.*;import java.util.*;/** * @author brownrigg * @version $Id: GeotiffImageReader.java 7290 2008-10-29 20:50:12Z dcollins $ */public class GeotiffImageReader extends ImageReader{ public GeotiffImageReader(ImageReaderSpi provider) { super(provider); } @Override public int getNumImages(boolean allowSearch) throws IOException { // TODO: This should allow for multiple images that may be present. For now, we'll ignore all but first. return 1; } @Override public int getWidth(int imageIndex) throws IOException { if (imageIndex < 0 || imageIndex >= getNumImages(true)) throw new IllegalArgumentException( this.getClass().getName() + ".getWidth(): illegal imageIndex: " + imageIndex); if (ifds.size() == 0) readIFDs(); TiffIFDEntry widthEntry = getByTag(ifds.get(imageIndex), TiffTags.IMAGE_WIDTH); return (int) widthEntry.asLong(); } @Override public int getHeight(int imageIndex) throws IOException { if (imageIndex < 0 || imageIndex >= getNumImages(true)) throw new IllegalArgumentException( this.getClass().getName() + ".getHeight(): illegal imageIndex: " + imageIndex); if (ifds.size() == 0) readIFDs(); TiffIFDEntry heightEntry = getByTag(ifds.get(imageIndex), TiffTags.IMAGE_LENGTH); return (int) heightEntry.asLong(); } @Override public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex) throws IOException { throw new UnsupportedOperationException("Not supported yet."); } @Override public IIOMetadata getStreamMetadata() throws IOException { throw new UnsupportedOperationException("Not supported yet."); } @Override public IIOMetadata getImageMetadata(int imageIndex) throws IOException { throw new UnsupportedOperationException("Not supported yet."); } @Override public BufferedImage read(int imageIndex, ImageReadParam param) throws IOException { // TODO: For this first implementation, we are completely ignoring the ImageReadParam given to us. // Our target functionality is not the entire ImageIO, but only that needed to support the static // read method ImageIO.read("myImage.tif"). // TODO: more generally, the following test should reflect that more than one image is possible in a Tiff. if (imageIndex != 0) throw new IllegalArgumentException( this.getClass().getName() + ".read(): illegal imageIndex: " + imageIndex); readIFDs(); // Extract the various IFD tags we need to read this image... TiffIFDEntry widthEntry = null; TiffIFDEntry lengthEntry = null; TiffIFDEntry bitsPerSampleEntry = null; TiffIFDEntry samplesPerPixelEntry = null; TiffIFDEntry photoInterpEntry = null; TiffIFDEntry stripOffsetsEntry = null; TiffIFDEntry stripCountsEntry = null; TiffIFDEntry rowsPerStripEntry = null; TiffIFDEntry planarConfigEntry = null; TiffIFDEntry colorMapEntry = null; TiffIFDEntry sampleFormatEntry = null; TiffIFDEntry[] ifd = ifds.get(imageIndex); for (TiffIFDEntry entry : ifd) { switch (entry.tag) { case TiffTags.IMAGE_WIDTH: widthEntry = entry; break; case TiffTags.IMAGE_LENGTH: lengthEntry = entry; break; case TiffTags.BITS_PER_SAMPLE: bitsPerSampleEntry = entry; break; case TiffTags.SAMPLES_PER_PIXEL: samplesPerPixelEntry = entry; break; case TiffTags.PHOTO_INTERPRETATION: photoInterpEntry = entry; break; case TiffTags.STRIP_OFFSETS: stripOffsetsEntry = entry; break; case TiffTags.STRIP_BYTE_COUNTS: stripCountsEntry = entry; break; case TiffTags.ROWS_PER_STRIP: rowsPerStripEntry = entry; break; case TiffTags.PLANAR_CONFIGURATION: planarConfigEntry = entry; break; case TiffTags.COLORMAP: colorMapEntry = entry; break; case TiffTags.SAMPLE_FORMAT: sampleFormatEntry = entry; break; } } // Check that we have the mandatory tags present... if (widthEntry == null || lengthEntry == null || samplesPerPixelEntry == null || photoInterpEntry == null || stripOffsetsEntry == null || stripCountsEntry == null || rowsPerStripEntry == null || planarConfigEntry == null) throw new IIOException(this.getClass().getName() + ".read(): unable to decipher image organization"); int width = (int) widthEntry.asLong(); int height = (int) lengthEntry.asLong(); int samplesPerPixel = (int) samplesPerPixelEntry.asLong(); long photoInterp = photoInterpEntry.asLong(); long rowsPerStrip = rowsPerStripEntry.asLong(); long planarConfig = planarConfigEntry.asLong(); int[] bitsPerSample = getBitsPerSample(bitsPerSampleEntry); long[] stripOffsets = getStripsArray(stripOffsetsEntry); long[] stripCounts = getStripsArray(stripCountsEntry); ColorModel colorModel; WritableRaster raster; // // TODO: This isn't terribly robust; we know how to deal with a few specific types... // if (samplesPerPixel == 1 && bitsPerSample.length == 1 && bitsPerSample[0] == 16) { // 16-bit grayscale (typical of elevation data, for example)... long sampleFormat = (sampleFormatEntry != null) ? sampleFormatEntry.asLong() : TiffConstants.SAMPLEFORMAT_UNSIGNED; int dataBuffType = (sampleFormat == TiffConstants.SAMPLEFORMAT_SIGNED) ? DataBuffer.TYPE_SHORT : DataBuffer.TYPE_USHORT; colorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), bitsPerSample, false, false, Transparency.OPAQUE, dataBuffType); int[] offsets = new int[]{0}; ComponentSampleModel sampleModel = new ComponentSampleModel(dataBuffType, width, height, 1, width, offsets); short[][] imageData = readPlanar16(width, height, samplesPerPixel, stripOffsets, stripCounts, rowsPerStrip); DataBuffer dataBuff = (dataBuffType == DataBuffer.TYPE_SHORT) ? new DataBufferShort(imageData, width * height, offsets) : new DataBufferUShort(imageData, width * height, offsets); raster = Raster.createWritableRaster(sampleModel, dataBuff, new Point(0, 0)); } else if (samplesPerPixel == 1 && bitsPerSample.length == 1 && bitsPerSample[0] == 32 && sampleFormatEntry != null && sampleFormatEntry.asLong() == TiffConstants.SAMPLEFORMAT_IEEEFLOAT) { // 32-bit grayscale (typical of elevation data, for example)... colorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), bitsPerSample, false, false, Transparency.OPAQUE, DataBuffer.TYPE_FLOAT); int[] offsets = new int[]{0}; ComponentSampleModel sampleModel = new ComponentSampleModel(DataBuffer.TYPE_FLOAT, width, height, 1, width, offsets); float[][] imageData = readPlanarFloat32(width, height, samplesPerPixel, stripOffsets, stripCounts, rowsPerStrip); DataBuffer dataBuff = new DataBufferFloat(imageData, width * height, offsets); raster = Raster.createWritableRaster(sampleModel, dataBuff, new Point(0, 0)); } else { // make sure a DataBufferByte is going to do the trick for (int bits : bitsPerSample) { if (bits != 8) throw new IIOException(this.getClass().getName() + ".read(): only expecting 8 bits/sample; found " + bits); } // byte image data; could be RGB-component, grayscale, or indexed-color. // Set up an appropriate ColorModel... colorModel = null; if (samplesPerPixel > 1) { int transparency = Transparency.OPAQUE; boolean hasAlpha = false; if (samplesPerPixel == 4) { transparency = Transparency.TRANSLUCENT; hasAlpha = true; } colorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), bitsPerSample, hasAlpha, false, transparency, DataBuffer.TYPE_BYTE); } else { // grayscale or indexed-color? if (photoInterp == TiffConstants.PHOTOINTERP_PALETTE) { // indexed... if (colorMapEntry == null) throw new IIOException( this.getClass().getName() + ".read(): no ColorMap found for indexed image type"); byte[][] cmap = readColorMap(colorMapEntry); colorModel = new IndexColorModel(bitsPerSample[0], (int) colorMapEntry.count / 3, cmap[0], cmap[1], cmap[2]); } else { // grayscale... colorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), bitsPerSample, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE); } } int[] bankOffsets = new int[samplesPerPixel]; for (int i = 0; i < samplesPerPixel; i++) { bankOffsets[i] = i; } int[] offsets = new int[(planarConfig == TiffConstants.PLANARCONFIG_CHUNKY) ? 1 : samplesPerPixel]; for (int i = 0; i < offsets.length; i++) { offsets[i] = 0; } // construct the right SampleModel... ComponentSampleModel sampleModel; if (samplesPerPixel == 1) sampleModel = new ComponentSampleModel(DataBuffer.TYPE_BYTE, width, height, 1, width, bankOffsets); else sampleModel = (planarConfig == TiffConstants.PLANARCONFIG_CHUNKY) ? new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE, width, height, samplesPerPixel, width * samplesPerPixel, bankOffsets) : new BandedSampleModel(DataBuffer.TYPE_BYTE, width, height, width, bankOffsets, offsets); // Get the image data and make our Raster... byte[][] imageData; if (planarConfig == TiffConstants.PLANARCONFIG_CHUNKY) imageData = readPixelInterleaved8(width, height, samplesPerPixel, stripOffsets, stripCounts); else imageData = readPlanar8(width, height, samplesPerPixel, stripOffsets, stripCounts, rowsPerStrip); DataBufferByte dataBuff = new DataBufferByte(imageData, width * height, offsets); raster = Raster.createWritableRaster(sampleModel, dataBuff, new Point(0, 0)); } /**************************************/ decodeGeotiffInfo(); /**************************************/ // Finally, put it all together to get our BufferedImage... return new BufferedImage(colorModel, raster, false, null); } private void decodeGeotiffInfo() throws IOException { readIFDs(); TiffIFDEntry[] ifd = ifds.get(0); for (TiffIFDEntry entry : ifd) { switch (entry.tag) { case TiffTags.MODEL_PIXELSCALE: geoPixelScale = readDoubles(entry); break; case TiffTags.MODEL_TIEPOINT: geoTiePoints = readDoubles(entry); break; case TiffTags.MODEL_TRANSFORMATION: geoMatrix = readDoubles(entry); break; case TiffTags.GEO_KEY_DIRECTORY: readGeoKeys(entry); break; case TiffTags.GEO_DOUBLE_PARAMS: break; case TiffTags.GEO_ASCII_PARAMS: break; } } } /* * Coordinates reading all the ImageFileDirectories in a Tiff file (there's typically only one). * */ private void readIFDs() throws IOException { if (this.theStream != null) return; if (super.input == null || !(super.input instanceof ImageInputStream)) { throw new IIOException(this.getClass().getName() + ": null/invalid ImageInputStream"); } this.theStream = (ImageInputStream) super.input; // determine byte ordering... byte[] ifh = new byte[2]; // Tiff image-file header try { theStream.readFully(ifh);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?