111
112 // The number of rows decoded
113 int rowsDone = 0;
114
115 // The current interlace pass, starting with 0.
116 int interlacePass = 0;
117
118 private byte[] fallbackColorTable = null;
119
120 // End per-stream settings
121
122 // Constants used to control interlacing.
123 static final int[] interlaceIncrement = { 8, 8, 4, 2, -1 };
124 static final int[] interlaceOffset = { 0, 4, 2, 1, -1 };
125
126 public GIFImageReader(ImageReaderSpi originatingProvider) {
127 super(originatingProvider);
128 }
129
130 // Take input from an ImageInputStream
131 public void setInput(Object input,
132 boolean seekForwardOnly,
133 boolean ignoreMetadata) {
134 super.setInput(input, seekForwardOnly, ignoreMetadata);
135 if (input != null) {
136 if (!(input instanceof ImageInputStream)) {
137 throw new IllegalArgumentException
138 ("input not an ImageInputStream!");
139 }
140 this.stream = (ImageInputStream)input;
141 } else {
142 this.stream = null;
143 }
144
145 // Clear all values based on the previous stream contents
146 resetStreamSettings();
147 }
148
149 public int getNumImages(boolean allowSearch) throws IIOException {
150 if (stream == null) {
151 throw new IllegalStateException("Input not set!");
152 }
153 if (seekForwardOnly && allowSearch) {
154 throw new IllegalStateException
155 ("seekForwardOnly and allowSearch can't both be true!");
156 }
157
158 if (numImages > 0) {
159 return numImages;
160 }
161 if (allowSearch) {
162 this.numImages = locateImage(Integer.MAX_VALUE) + 1;
163 }
164 return numImages;
165 }
166
167 // Throw an IndexOutOfBoundsException if index < minIndex,
168 // and bump minIndex if required.
169 private void checkIndex(int imageIndex) {
170 if (imageIndex < minIndex) {
171 throw new IndexOutOfBoundsException("imageIndex < minIndex!");
172 }
173 if (seekForwardOnly) {
174 minIndex = imageIndex;
175 }
176 }
177
178 public int getWidth(int imageIndex) throws IIOException {
179 checkIndex(imageIndex);
180
181 int index = locateImage(imageIndex);
182 if (index != imageIndex) {
183 throw new IndexOutOfBoundsException();
184 }
185 readMetadata();
186 return imageMetadata.imageWidth;
187 }
188
189 public int getHeight(int imageIndex) throws IIOException {
190 checkIndex(imageIndex);
191
192 int index = locateImage(imageIndex);
193 if (index != imageIndex) {
194 throw new IndexOutOfBoundsException();
195 }
196 readMetadata();
197 return imageMetadata.imageHeight;
198 }
199
200 // We don't check all parameters as ImageTypeSpecifier.createIndexed do
201 // since this method is private and we pass consistent data here
202 private ImageTypeSpecifier createIndexed(byte[] r, byte[] g, byte[] b,
203 int bits) {
204 ColorModel colorModel;
205 if (imageMetadata.transparentColorFlag) {
206 // Some files erroneously have a transparent color index
207 // of 255 even though there are fewer than 256 colors.
208 int idx = Math.min(imageMetadata.transparentColorIndex,
210 colorModel = new IndexColorModel(bits, r.length, r, g, b, idx);
211 } else {
212 colorModel = new IndexColorModel(bits, r.length, r, g, b);
213 }
214
215 SampleModel sampleModel;
216 if (bits == 8) {
217 int[] bandOffsets = {0};
218 sampleModel =
219 new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE,
220 1, 1, 1, 1,
221 bandOffsets);
222 } else {
223 sampleModel =
224 new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE,
225 1, 1, bits);
226 }
227 return new ImageTypeSpecifier(colorModel, sampleModel);
228 }
229
230 public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex)
231 throws IIOException {
232 checkIndex(imageIndex);
233
234 int index = locateImage(imageIndex);
235 if (index != imageIndex) {
236 throw new IndexOutOfBoundsException();
237 }
238 readMetadata();
239
240 List<ImageTypeSpecifier> l = new ArrayList<>(1);
241
242 byte[] colorTable;
243 if (imageMetadata.localColorTable != null) {
244 colorTable = imageMetadata.localColorTable;
245 fallbackColorTable = imageMetadata.localColorTable;
246 } else {
247 colorTable = streamMetadata.globalColorTable;
248 }
249
272 // Bump to 8 bits
273 bits = 8;
274 }
275 int lutLength = 1 << bits;
276 byte[] r = new byte[lutLength];
277 byte[] g = new byte[lutLength];
278 byte[] b = new byte[lutLength];
279
280 // Entries from length + 1 to lutLength - 1 will be 0
281 int rgbIndex = 0;
282 for (int i = 0; i < length; i++) {
283 r[i] = colorTable[rgbIndex++];
284 g[i] = colorTable[rgbIndex++];
285 b[i] = colorTable[rgbIndex++];
286 }
287
288 l.add(createIndexed(r, g, b, bits));
289 return l.iterator();
290 }
291
292 public ImageReadParam getDefaultReadParam() {
293 return new ImageReadParam();
294 }
295
296 public IIOMetadata getStreamMetadata() throws IIOException {
297 readHeader();
298 return streamMetadata;
299 }
300
301 public IIOMetadata getImageMetadata(int imageIndex) throws IIOException {
302 checkIndex(imageIndex);
303
304 int index = locateImage(imageIndex);
305 if (index != imageIndex) {
306 throw new IndexOutOfBoundsException("Bad image index!");
307 }
308 readMetadata();
309 return imageMetadata;
310 }
311
312 // BEGIN LZW STUFF
313
314 private void initNext32Bits() {
315 next32Bits = block[0] & 0xff;
316 next32Bits |= (block[1] & 0xff) << 8;
317 next32Bits |= (block[2] & 0xff) << 16;
318 next32Bits |= block[3] << 24;
319 nextByte = 4;
320 }
838 yStep);
839
840 // Initialized updateMinY and updateYStep
841 this.updateMinY = vals[1];
842 this.updateYStep = vals[5];
843
844 // Inform IIOReadUpdateListeners of new pass
845 int[] bands = { 0 };
846
847 processPassStarted(theImage,
848 interlacePass,
849 sourceMinProgressivePass,
850 sourceMaxProgressivePass,
851 0,
852 updateMinY,
853 1,
854 updateYStep,
855 bands);
856 }
857
858 public BufferedImage read(int imageIndex, ImageReadParam param)
859 throws IIOException {
860 if (stream == null) {
861 throw new IllegalStateException("Input not set!");
862 }
863 checkIndex(imageIndex);
864
865 int index = locateImage(imageIndex);
866 if (index != imageIndex) {
867 throw new IndexOutOfBoundsException("imageIndex out of bounds!");
868 }
869
870 readMetadata();
871
872 // A null ImageReadParam means we use the default
873 if (param == null) {
874 param = getDefaultReadParam();
875 }
876
877 // Initialize the destination image
1020 for (int i = len - 1; i >= 0; i--) {
1021 string[i] = suffix[c];
1022 c = prefix[c];
1023 }
1024
1025 outputPixels(string, len);
1026 oldCode = code;
1027 } while (!abortRequested());
1028
1029 processReadAborted();
1030 return theImage;
1031 } catch (IOException e) {
1032 throw new IIOException("I/O error reading image!", e);
1033 }
1034 }
1035
1036 /**
1037 * Remove all settings including global settings such as
1038 * {@code Locale}s and listeners, as well as stream settings.
1039 */
1040 public void reset() {
1041 super.reset();
1042 resetStreamSettings();
1043 }
1044
1045 /**
1046 * Remove local settings based on parsing of a stream.
1047 */
1048 private void resetStreamSettings() {
1049 gotHeader = false;
1050 streamMetadata = null;
1051 currIndex = -1;
1052 imageMetadata = null;
1053 imageStartPosition = new ArrayList<>();
1054 numImages = -1;
1055
1056 // No need to reinitialize 'block'
1057 blockLength = 0;
1058 bitPos = 0;
1059 nextByte = 0;
|
111
112 // The number of rows decoded
113 int rowsDone = 0;
114
115 // The current interlace pass, starting with 0.
116 int interlacePass = 0;
117
118 private byte[] fallbackColorTable = null;
119
120 // End per-stream settings
121
122 // Constants used to control interlacing.
123 static final int[] interlaceIncrement = { 8, 8, 4, 2, -1 };
124 static final int[] interlaceOffset = { 0, 4, 2, 1, -1 };
125
126 public GIFImageReader(ImageReaderSpi originatingProvider) {
127 super(originatingProvider);
128 }
129
130 // Take input from an ImageInputStream
131 @Override
132 public void setInput(Object input,
133 boolean seekForwardOnly,
134 boolean ignoreMetadata) {
135 super.setInput(input, seekForwardOnly, ignoreMetadata);
136 if (input != null) {
137 if (!(input instanceof ImageInputStream)) {
138 throw new IllegalArgumentException
139 ("input not an ImageInputStream!");
140 }
141 this.stream = (ImageInputStream)input;
142 } else {
143 this.stream = null;
144 }
145
146 // Clear all values based on the previous stream contents
147 resetStreamSettings();
148 }
149
150 @Override
151 public int getNumImages(boolean allowSearch) throws IIOException {
152 if (stream == null) {
153 throw new IllegalStateException("Input not set!");
154 }
155 if (seekForwardOnly && allowSearch) {
156 throw new IllegalStateException
157 ("seekForwardOnly and allowSearch can't both be true!");
158 }
159
160 if (numImages > 0) {
161 return numImages;
162 }
163 if (allowSearch) {
164 this.numImages = locateImage(Integer.MAX_VALUE) + 1;
165 }
166 return numImages;
167 }
168
169 // Throw an IndexOutOfBoundsException if index < minIndex,
170 // and bump minIndex if required.
171 private void checkIndex(int imageIndex) {
172 if (imageIndex < minIndex) {
173 throw new IndexOutOfBoundsException("imageIndex < minIndex!");
174 }
175 if (seekForwardOnly) {
176 minIndex = imageIndex;
177 }
178 }
179
180 @Override
181 public int getWidth(int imageIndex) throws IIOException {
182 checkIndex(imageIndex);
183
184 int index = locateImage(imageIndex);
185 if (index != imageIndex) {
186 throw new IndexOutOfBoundsException();
187 }
188 readMetadata();
189 return imageMetadata.imageWidth;
190 }
191
192 @Override
193 public int getHeight(int imageIndex) throws IIOException {
194 checkIndex(imageIndex);
195
196 int index = locateImage(imageIndex);
197 if (index != imageIndex) {
198 throw new IndexOutOfBoundsException();
199 }
200 readMetadata();
201 return imageMetadata.imageHeight;
202 }
203
204 // We don't check all parameters as ImageTypeSpecifier.createIndexed do
205 // since this method is private and we pass consistent data here
206 private ImageTypeSpecifier createIndexed(byte[] r, byte[] g, byte[] b,
207 int bits) {
208 ColorModel colorModel;
209 if (imageMetadata.transparentColorFlag) {
210 // Some files erroneously have a transparent color index
211 // of 255 even though there are fewer than 256 colors.
212 int idx = Math.min(imageMetadata.transparentColorIndex,
214 colorModel = new IndexColorModel(bits, r.length, r, g, b, idx);
215 } else {
216 colorModel = new IndexColorModel(bits, r.length, r, g, b);
217 }
218
219 SampleModel sampleModel;
220 if (bits == 8) {
221 int[] bandOffsets = {0};
222 sampleModel =
223 new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE,
224 1, 1, 1, 1,
225 bandOffsets);
226 } else {
227 sampleModel =
228 new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE,
229 1, 1, bits);
230 }
231 return new ImageTypeSpecifier(colorModel, sampleModel);
232 }
233
234 @Override
235 public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex)
236 throws IIOException {
237 checkIndex(imageIndex);
238
239 int index = locateImage(imageIndex);
240 if (index != imageIndex) {
241 throw new IndexOutOfBoundsException();
242 }
243 readMetadata();
244
245 List<ImageTypeSpecifier> l = new ArrayList<>(1);
246
247 byte[] colorTable;
248 if (imageMetadata.localColorTable != null) {
249 colorTable = imageMetadata.localColorTable;
250 fallbackColorTable = imageMetadata.localColorTable;
251 } else {
252 colorTable = streamMetadata.globalColorTable;
253 }
254
277 // Bump to 8 bits
278 bits = 8;
279 }
280 int lutLength = 1 << bits;
281 byte[] r = new byte[lutLength];
282 byte[] g = new byte[lutLength];
283 byte[] b = new byte[lutLength];
284
285 // Entries from length + 1 to lutLength - 1 will be 0
286 int rgbIndex = 0;
287 for (int i = 0; i < length; i++) {
288 r[i] = colorTable[rgbIndex++];
289 g[i] = colorTable[rgbIndex++];
290 b[i] = colorTable[rgbIndex++];
291 }
292
293 l.add(createIndexed(r, g, b, bits));
294 return l.iterator();
295 }
296
297 @Override
298 public ImageReadParam getDefaultReadParam() {
299 return new ImageReadParam();
300 }
301
302 @Override
303 public IIOMetadata getStreamMetadata() throws IIOException {
304 readHeader();
305 return streamMetadata;
306 }
307
308 @Override
309 public IIOMetadata getImageMetadata(int imageIndex) throws IIOException {
310 checkIndex(imageIndex);
311
312 int index = locateImage(imageIndex);
313 if (index != imageIndex) {
314 throw new IndexOutOfBoundsException("Bad image index!");
315 }
316 readMetadata();
317 return imageMetadata;
318 }
319
320 // BEGIN LZW STUFF
321
322 private void initNext32Bits() {
323 next32Bits = block[0] & 0xff;
324 next32Bits |= (block[1] & 0xff) << 8;
325 next32Bits |= (block[2] & 0xff) << 16;
326 next32Bits |= block[3] << 24;
327 nextByte = 4;
328 }
846 yStep);
847
848 // Initialized updateMinY and updateYStep
849 this.updateMinY = vals[1];
850 this.updateYStep = vals[5];
851
852 // Inform IIOReadUpdateListeners of new pass
853 int[] bands = { 0 };
854
855 processPassStarted(theImage,
856 interlacePass,
857 sourceMinProgressivePass,
858 sourceMaxProgressivePass,
859 0,
860 updateMinY,
861 1,
862 updateYStep,
863 bands);
864 }
865
866 @Override
867 public BufferedImage read(int imageIndex, ImageReadParam param)
868 throws IIOException {
869 if (stream == null) {
870 throw new IllegalStateException("Input not set!");
871 }
872 checkIndex(imageIndex);
873
874 int index = locateImage(imageIndex);
875 if (index != imageIndex) {
876 throw new IndexOutOfBoundsException("imageIndex out of bounds!");
877 }
878
879 readMetadata();
880
881 // A null ImageReadParam means we use the default
882 if (param == null) {
883 param = getDefaultReadParam();
884 }
885
886 // Initialize the destination image
1029 for (int i = len - 1; i >= 0; i--) {
1030 string[i] = suffix[c];
1031 c = prefix[c];
1032 }
1033
1034 outputPixels(string, len);
1035 oldCode = code;
1036 } while (!abortRequested());
1037
1038 processReadAborted();
1039 return theImage;
1040 } catch (IOException e) {
1041 throw new IIOException("I/O error reading image!", e);
1042 }
1043 }
1044
1045 /**
1046 * Remove all settings including global settings such as
1047 * {@code Locale}s and listeners, as well as stream settings.
1048 */
1049 @Override
1050 public void reset() {
1051 super.reset();
1052 resetStreamSettings();
1053 }
1054
1055 /**
1056 * Remove local settings based on parsing of a stream.
1057 */
1058 private void resetStreamSettings() {
1059 gotHeader = false;
1060 streamMetadata = null;
1061 currIndex = -1;
1062 imageMetadata = null;
1063 imageStartPosition = new ArrayList<>();
1064 numImages = -1;
1065
1066 // No need to reinitialize 'block'
1067 blockLength = 0;
1068 bitPos = 0;
1069 nextByte = 0;
|