001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.imaging.formats.tiff;
018
019import java.io.IOException;
020import java.nio.ByteOrder;
021
022import org.apache.commons.imaging.ImageReadException;
023import org.apache.commons.imaging.ImagingConstants;
024import org.apache.commons.imaging.common.bytesource.ByteSourceFile;
025import org.apache.commons.imaging.formats.tiff.constants.TiffPlanarConfiguration;
026import org.apache.commons.imaging.formats.tiff.constants.TiffTagConstants;
027import org.apache.commons.imaging.formats.tiff.datareaders.DataReaderStrips;
028import org.apache.commons.imaging.formats.tiff.datareaders.DataReaderTiled;
029import org.apache.commons.imaging.formats.tiff.datareaders.ImageDataReader;
030import org.apache.commons.imaging.formats.tiff.photometricinterpreters.PhotometricInterpreter;
031
032public abstract class TiffImageData {
033    public static class Tiles extends TiffImageData {
034        public final TiffElement.DataElement[] tiles;
035
036        // public final byte tiles[][];
037        private final int tileWidth;
038        private final int tileLength;
039
040        public Tiles(final TiffElement.DataElement[] tiles, final int tileWidth, final int tileLength) {
041            this.tiles = tiles;
042            this.tileWidth = tileWidth;
043            this.tileLength = tileLength;
044        }
045
046        @Override
047        public TiffElement.DataElement[] getImageData() {
048            return tiles;
049        }
050
051        @Override
052        public boolean stripsNotTiles() {
053            return false;
054        }
055
056        @Override
057        public ImageDataReader getDataReader(final TiffDirectory directory,
058          final PhotometricInterpreter photometricInterpreter,
059          final int bitsPerPixel, final int[] bitsPerSample, final int predictor,
060          final int samplesPerPixel, final int width, final int height,
061          final int compression,
062          final TiffPlanarConfiguration planarConfiguration,
063          final ByteOrder byteOrder) throws IOException, ImageReadException {
064            final int sampleFormat = extractSampleFormat(directory);
065            return new DataReaderTiled(directory, photometricInterpreter,
066              tileWidth, tileLength, bitsPerPixel, bitsPerSample,
067              predictor, samplesPerPixel, sampleFormat, width, height, compression,
068              planarConfiguration, byteOrder, this);
069        }
070
071        /**
072         * Get the width of individual tiles.  Note that if the overall
073         * image width is not a multiple of the tile width, then
074         * the last column of tiles may extend beyond the image width.
075         * @return an integer value greater than zero
076         */
077        public int getTileWidth() {
078            return tileWidth;
079        }
080
081        /**
082         * Get the height of individual tiles.  Note that if the overall
083         * image height is not a multiple of the tile height, then
084         * the last row of tiles may extend beyond the image height.
085         * @return an integer value greater than zero
086         */
087        public int getTileHeight() {
088            return tileLength;
089        }
090
091        // public TiffElement[] getElements()
092        // {
093        // return tiles;
094        // }
095    }
096
097    public static class Strips extends TiffImageData {
098        private final TiffElement.DataElement[] strips;
099        // public final byte strips[][];
100        public final int rowsPerStrip;
101
102        public Strips(final TiffElement.DataElement[] strips, final int rowsPerStrip) {
103            this.strips = strips;
104            this.rowsPerStrip = rowsPerStrip;
105        }
106
107        @Override
108        public TiffElement.DataElement[] getImageData() {
109            return strips;
110        }
111
112        public TiffElement.DataElement getImageData(final int offset) {
113            return strips[offset];
114        }
115
116        public int getImageDataLength() {
117            return strips.length;
118        }
119
120        @Override
121        public boolean stripsNotTiles() {
122            return true;
123        }
124
125        @Override
126        public ImageDataReader getDataReader(final TiffDirectory directory,
127          final PhotometricInterpreter photometricInterpreter,
128          final int bitsPerPixel, final int[] bitsPerSample, final int predictor,
129          final int samplesPerPixel, final int width, final int height,
130          final int compression,
131          final TiffPlanarConfiguration planarConfiguration,
132          final ByteOrder byteorder) throws IOException, ImageReadException {
133            final int sampleFormat = extractSampleFormat(directory);
134            return new DataReaderStrips(directory, photometricInterpreter,
135              bitsPerPixel, bitsPerSample, predictor,
136              samplesPerPixel, sampleFormat, width, height,
137              compression, planarConfiguration, byteorder, rowsPerStrip, this);
138        }
139
140    }
141
142    public abstract TiffElement.DataElement[] getImageData();
143
144    public abstract boolean stripsNotTiles();
145
146    public abstract ImageDataReader getDataReader(TiffDirectory directory,
147      PhotometricInterpreter photometricInterpreter, int bitsPerPixel,
148      int[] bitsPerSample, int predictor, int samplesPerPixel, int width,
149      int height, int compression,
150      TiffPlanarConfiguration planarConfiguration,
151      ByteOrder byteOrder) throws IOException, ImageReadException;
152
153    public static class Data extends TiffElement.DataElement {
154        public Data(final long offset, final int length, final byte[] data) {
155            super(offset, length, data);
156        }
157
158        @Override
159        public String getElementDescription() {
160            return "Tiff image data: " + getDataLength() + " bytes";
161        }
162
163    }
164
165    public static class ByteSourceData extends Data {
166        final ByteSourceFile byteSourceFile;
167
168        public ByteSourceData(final long offset, final int length, final ByteSourceFile byteSource) {
169            super(offset, length, ImagingConstants.EMPTY_BYTE_ARRAY);
170            byteSourceFile = byteSource;
171        }
172
173        @Override
174        public String getElementDescription() {
175            return "Tiff image data: " + getDataLength() + " bytes";
176        }
177
178        @Override
179        public byte[] getData() {
180            try {
181                return byteSourceFile.getBlock(offset, length);
182            } catch (final IOException ioex) {
183                return ImagingConstants.EMPTY_BYTE_ARRAY;
184            }
185        }
186    }
187
188    private static int extractSampleFormat(final TiffDirectory directory) throws ImageReadException {
189        final short[] sSampleFmt = directory.getFieldValue(
190            TiffTagConstants.TIFF_TAG_SAMPLE_FORMAT, false);
191        if (sSampleFmt != null && sSampleFmt.length > 0) {
192            return sSampleFmt[0];
193        }
194        return 0;  // unspecified format
195    }
196}