/** Read Image data */ private boolean readImage(boolean first, int disposal_method, int delay) throws IOException { if (curframe != null && !curframe.dispose()) { abort(); return false; } long tm = 0; if (verbose) { tm = System.currentTimeMillis(); } // Allocate the buffer byte block[] = new byte[256 + 3]; // Read the image descriptor if (readBytes(block, 0, 10) != 0) { throw new IOException(); } int x = ExtractWord(block, 0); int y = ExtractWord(block, 2); int width = ExtractWord(block, 4); int height = ExtractWord(block, 6); boolean interlace = (block[8] & INTERLACEMASK) != 0; IndexColorModel model = global_model; if ((block[8] & COLORMAPMASK) != 0) { // We read one extra byte above so now when we must // transfer that byte as the first colormap byte // and manually read the code size when we are done int num_local_colors = 1 << ((block[8] & 0x7) + 1); // Read local colors byte[] local_colormap = new byte[num_local_colors * 3]; local_colormap[0] = block[9]; if (readBytes(local_colormap, 1, num_local_colors * 3 - 1) != 0) { throw new IOException(); } // Now read the "real" code size byte which follows // the local color table if (readBytes(block, 9, 1) != 0) { throw new IOException(); } model = new IndexColorModel(8, num_local_colors, local_colormap, 0, false, trans_pixel); } else if (model == null || trans_pixel != model.getTransparentPixel()) { model = new IndexColorModel(8, num_global_colors, global_colormap, 0, false, trans_pixel); global_model = model; } // Notify the consumers if (first) { if (global_width == 0) global_width = width; if (global_height == 0) global_height = height; setDimensions(global_width, global_height); setProperties(props); setColorModel(model); headerComplete(); } if (disposal_method == GifFrame.DISPOSAL_SAVE && saved_image == null) { saved_image = new byte[global_width * global_height]; } int hints = (interlace ? interlaceflags : normalflags); setHints(hints); curframe = new GifFrame(this, disposal_method, delay, (curframe == null), model, x, y, width, height); // allocate the raster data byte rasline[] = new byte[width]; if (verbose) { System.out.print( "Reading a " + width + " by " + height + " " + (interlace ? "" : "non-") + "interlaced image..."); } boolean ret = parseImage(x, y, width, height, interlace, ExtractByte(block, 9), block, rasline, model); if (!ret) { abort(); } if (verbose) { System.out.println("done in " + (System.currentTimeMillis() - tm) + "ms"); } return ret; }
/** produce an image from the stream. */ public void produceImage() throws IOException, ImageFormatException { try { readHeader(); int totalframes = 0; int frameno = 0; int nloops = -1; int disposal_method = 0; int delay = -1; boolean loopsRead = false; boolean isAnimation = false; while (!aborted) { int code; if (!ImageProductionMonitor.allowsProduction()) { abort(); break; } switch (code = input.read()) { case EXBLOCK: switch (code = input.read()) { case EX_GRAPHICS_CONTROL: { byte buf[] = new byte[6]; if (readBytes(buf, 0, 6) != 0) { return; // error("corrupt GIF file"); } if ((buf[0] != 4) || (buf[5] != 0)) { return; // error("corrupt GIF file (GCE size)"); } // Get the index of the transparent color delay = ExtractWord(buf, 2) * 10; if (delay > 0 && !isAnimation) { isAnimation = true; ImageFetcher.startingAnimation(); } disposal_method = (buf[1] >> 2) & 7; if ((buf[1] & TRANSPARENCYMASK) != 0) { trans_pixel = ExtractByte(buf, 4); } else { trans_pixel = -1; } break; } case EX_COMMENT: case EX_APPLICATION: default: boolean loop_tag = false; String comment = ""; while (true) { int n = input.read(); if (n <= 0) { break; } byte buf[] = new byte[n]; if (readBytes(buf, 0, n) != 0) { return; // error("corrupt GIF file"); } if (code == EX_COMMENT) { comment += new String(buf); } else if (code == EX_APPLICATION) { if (loop_tag) { if (n == 3 && buf[0] == 1) { if (loopsRead) { ExtractWord(buf, 1); } else { nloops = ExtractWord(buf, 1); loopsRead = true; } } else { loop_tag = false; } } if ("NETSCAPE2.0".equals(new String(buf))) { loop_tag = true; } } } if (code == EX_COMMENT) { props.put("comment", comment); } if (loop_tag && !isAnimation) { isAnimation = true; ImageFetcher.startingAnimation(); } break; case -1: return; // error("corrupt GIF file"); } break; case IMAGESEP: if (!isAnimation) { input.mark(0); // we don't need the mark buffer } try { if (!readImage(totalframes == 0, disposal_method, delay)) { return; } } catch (Exception e) { if (verbose) { e.printStackTrace(); } return; } frameno++; totalframes++; break; default: case -1: if (verbose) { if (code == -1) { System.err.println("Premature EOF in GIF file," + " frame " + frameno); } else { System.err.println("corrupt GIF file (parse) [" + code + "]."); } } if (frameno == 0) { return; } // NOBREAK case TERMINATOR: if (nloops == 0 || nloops-- >= 0) { try { if (curframe != null) { curframe.dispose(); curframe = null; } input.reset(); saved_image = null; saved_model = null; frameno = 0; break; } catch (IOException e) { return; // Unable to reset input buffer } } if (verbose && frameno != 1) { System.out.println( "processing GIF terminator," + " frames: " + frameno + " total: " + totalframes); } imageComplete(ImageConsumer.STATICIMAGEDONE, true); return; } } } finally { close(); } }