1. 程式人生 > >GifDecoder.java原始碼(處理GIF圖片)

GifDecoder.java原始碼(處理GIF圖片)

import java.net.*;
import java.io.*;
import java.util.*;
import java.awt.*;
import java.awt.image.*;

public class GifDecoder {

 /**
  * File read status: No errors.
  */
 public static final int STATUS_OK = 0;

 /**
  * File read status: Error decoding file (may be partially decoded)
  */
 public static final int STATUS_FORMAT_ERROR = 1;

 /**
  * File read status: Unable to open source.
  */
 public static final int STATUS_OPEN_ERROR = 2;

 protected BufferedInputStream in;
 protected int status;

 protected int width; // full image width
 protected int height; // full image height
 protected boolean gctFlag; // global color table used
 protected int gctSize; // size of global color table
 protected int loopCount = 1; // iterations; 0 = repeat forever

 protected int[] gct; // global color table
 protected int[] lct; // local color table
 protected int[] act; // active color table

 protected int bgIndex; // background color index
 protected int bgColor; // background color
 protected int lastBgColor; // previous bg color
 protected int pixelAspect; // pixel aspect ratio

 protected boolean lctFlag; // local color table flag
 protected boolean interlace; // interlace flag
 protected int lctSize; // local color table size

 protected int ix, iy, iw, ih; // current image rectangle
 protected Rectangle lastRect; // last image rect
 protected BufferedImage image; // current frame
 protected BufferedImage lastImage; // previous frame

 protected byte[] block = new byte[256]; // current data block
 protected int blockSize = 0; // block size

 // last graphic control extension info
 protected int dispose = 0;
 // 0=no action; 1=leave in place; 2=restore to bg; 3=restore to prev
 protected int lastDispose = 0;
 protected boolean transparency = false; // use transparent color
 protected int delay = 0; // delay in milliseconds
 protected int transIndex; // transparent color index

 protected static final int MaxStackSize = 4096;
 // max decoder pixel stack size

 // LZW decoder working arrays
 protected short[] prefix;
 protected byte[] suffix;
 protected byte[] pixelStack;
 protected byte[] pixels;

 protected ArrayList frames; // frames read from current file
 protected int frameCount;

 static class GifFrame {
  public GifFrame(BufferedImage im, int del) {
   image = im;
   delay = del;
  }
  public BufferedImage image;
  public int delay;
 }

 /**
  * Gets display duration for specified frame.
  *
  * @param n int index of frame
  * @return delay in milliseconds
  */
 public int getDelay(int n) {
  //
  delay = -1;
  if ((n >= 0) && (n < frameCount)) {
   delay = ((GifFrame) frames.get(n)).delay;
  }
  return delay;
 }

 /**
  * Gets the number of frames read from file.
  * @return frame count
  */
 public int getFrameCount() {
  return frameCount;
 }

 /**
  * Gets the first (or only) image read.
  *
  * @return BufferedImage containing first frame, or null if none.
  */
 public BufferedImage getImage() {
  return getFrame(0);
 }

 /**
  * Gets the "Netscape" iteration count, if any.
  * A count of 0 means repeat indefinitiely.
  *
  * @return iteration count if one was specified, else 1.
  */
 public int getLoopCount() {
  return loopCount;
 }

 /**
  * Creates new frame image from current data (and previous
  * frames as specified by their disposition codes).
  */
 protected void setPixels() {
  // expose destination image's pixels as int array
  int[] dest =
   ((DataBufferInt) image.getRaster().getDataBuffer()).getData();

  // fill in starting image contents based on last image's dispose code
  if (lastDispose > 0) {
   if (lastDispose == 3) {
    // use image before last
    int n = frameCount - 2;
    if (n > 0) {
     lastImage = getFrame(n - 1);
    } else {
     lastImage = null;
    }
   }

   if (lastImage != null) {
    int[] prev =
     ((DataBufferInt) lastImage.getRaster().getDataBuffer()).getData();
    System.arraycopy(prev, 0, dest, 0, width * height);
    // copy pixels

    if (lastDispose == 2) {
     // fill last image rect area with background color
     Graphics2D g = image.createGraphics();
     Color c = null;
     if (transparency) {
      c = new Color(0, 0, 0, 0);  // assume background is transparent
     } else {
      c = new Color(lastBgColor); // use given background color
     }
     g.setColor(c);
     g.setComposite(AlphaComposite.Src); // replace area
     g.fill(lastRect);
     g.dispose();
    }
   }
  }

  // copy each source line to the appropriate place in the destination
  int pass = 1;
  int inc = 8;
  int iline = 0;
  for (int i = 0; i < ih; i++) {
   int line = i;
   if (interlace) {
    if (iline >= ih) {
     pass++;
     switch (pass) {
      case 2 :
       iline = 4;
       break;
      case 3 :
       iline = 2;
       inc = 4;
       break;
      case 4 :
       iline = 1;
       inc = 2;
     }
    }
    line = iline;
    iline += inc;
   }
   line += iy;
   if (line < height) {
    int k = line * width;
    int dx = k + ix; // start of line in dest
    int dlim = dx + iw; // end of dest line
    if ((k + width) < dlim) {
     dlim = k + width; // past dest edge
    }
    int sx = i * iw; // start of line in source
    while (dx < dlim) {
     // map color and insert in destination
     int index = ((int) pixels[sx++]) & 0xff;
     int c = act[index];
     if (c != 0) {
      dest[dx] = c;
     }
     dx++;
    }
   }
  }
 }

 /**
  * Gets the image contents of frame n.
  *
  * @return BufferedImage representation of frame, or null if n is invalid.
  */
 public BufferedImage getFrame(int n) {
  BufferedImage im = null;
  if ((n >= 0) && (n < frameCount)) {
   im = ((GifFrame) frames.get(n)).image;
  }
  return im;
 }

 /**
  * Gets image size.
  *
  * @return GIF image dimensions
  */
 public Dimension getFrameSize() {
  return new Dimension(width, height);
 }

 /**
  * Reads GIF image from stream
  *
  * @param BufferedInputStream containing GIF file.
  * @return read status code (0 = no errors)
  */
 public int read(BufferedInputStream is) {
  init();
  if (is != null) {
   in = is;
   readHeader();
   if (!err()) {
    readContents();
    if (frameCount < 0) {
     status = STATUS_FORMAT_ERROR;
    }
   }
  } else {
   status = STATUS_OPEN_ERROR;
  }
  try {
   is.close();
  } catch (IOException e) {
  }
  return status;
 }

 /**
  * Reads GIF image from stream
  *
  * @param InputStream containing GIF file.
  * @return read status code (0 = no errors)
  */
 public int read(InputStream is) {
  init();
  if (is != null) {
   if (!(is instanceof BufferedInputStream))
    is = new BufferedInputStream(is);
   in = (BufferedInputStream) is;
   readHeader();
   if (!err()) {
    readContents();
    if (frameCount < 0) {
     status = STATUS_FORMAT_ERROR;
    }
   }
  } else {
   status = STATUS_OPEN_ERROR;
  }
  try {
   is.close();
  } catch (IOException e) {
  }
  return status;
 }

 /**
  * Reads GIF file from specified file/URL source  
  * (URL assumed if name contains ":/" or "file:")
  *
  * @param name String containing source
  * @return read status code (0 = no errors)
  */
 public int read(String name) {
  status = STATUS_OK;
  try {
   name = name.trim().toLowerCase();
   if ((name.indexOf("file:") >= 0) ||
    (name.indexOf(":/") > 0)) {
    URL url = new URL(name);
    in = new BufferedInputStream(url.openStream());
   } else {
    in = new BufferedInputStream(new FileInputStream(name));
   }
   status = read(in);
  } catch (IOException e) {
   status = STATUS_OPEN_ERROR;
  }

  return status;
 }

 /**
  * Decodes LZW image data into pixel array.
  * Adapted from John Cristy's ImageMagick.
  */
 protected void decodeImageData() {
  int NullCode = -1;
  int npix = iw * ih;
  int available, 
   clear,
   code_mask,
   code_size,
   end_of_information,
   in_code,
   old_code,
   bits,
   code,
   count,
   i,
   datum,
   data_size,
   first,
   top,
   bi,
   pi;

  if ((pixels == null) || (pixels.length < npix)) {
   pixels = new byte[npix]; // allocate new pixel array
  }
  if (prefix == null) prefix = new short[MaxStackSize];
  if (suffix == null) suffix = new byte[MaxStackSize];
  if (pixelStack == null) pixelStack = new byte[MaxStackSize + 1];

  //  Initialize GIF data stream decoder.

  data_size = read();
  clear = 1 << data_size;
  end_of_information = clear + 1;
  available = clear + 2;
  old_code = NullCode;
  code_size = data_size + 1;
  code_mask = (1 << code_size) - 1;
  for (code = 0; code < clear; code++) {
   prefix[code] = 0;
   suffix[code] = (byte) code;
  }

  //  Decode GIF pixel stream.

  datum = bits = count = first = top = pi = bi = 0;

  for (i = 0; i < npix;) {
   if (top == 0) {
    if (bits < code_size) {
     //  Load bytes until there are enough bits for a code.
     if (count == 0) {
      // Read a new data block.
      count = readBlock();
      if (count <= 0)
       break;
      bi = 0;
     }
     datum += (((int) block[bi]) & 0xff) << bits;
     bits += 8;
     bi++;
     count--;
     continue;
    }

    //  Get the next code.

    code = datum & code_mask;
    datum >>= code_size;
    bits -= code_size;

    //  Interpret the code

    if ((code > available) || (code == end_of_information))
     break;
    if (code == clear) {
     //  Reset decoder.
     code_size = data_size + 1;
     code_mask = (1 << code_size) - 1;
     available = clear + 2;
     old_code = NullCode;
     continue;
    }
    if (old_code == NullCode) {
     pixelStack[top++] = suffix[code];
     old_code = code;
     first = code;
     continue;
    }
    in_code = code;
    if (code == available) {
     pixelStack[top++] = (byte) first;
     code = old_code;
    }
    while (code > clear) {
     pixelStack[top++] = suffix[code];
     code = prefix[code];
    }
    first = ((int) suffix[code]) & 0xff;

    //  Add a new string to the string table,

    if (available >= MaxStackSize)
     break;
    pixelStack[top++] = (byte) first;
    prefix[available] = (short) old_code;
    suffix[available] = (byte) first;
    available++;
    if (((available & code_mask) == 0)
     && (available < MaxStackSize)) {
     code_size++;
     code_mask += available;
    }
    old_code = in_code;
   }

   //  Pop a pixel off the pixel stack.

   top--;
   pixels[pi++] = pixelStack[top];
   i++;
  }

  for (i = pi; i < npix; i++) {
   pixels[i] = 0; // clear missing pixels
  }

 }

 /**
  * Returns true if an error was encountered during reading/decoding
  */
 protected boolean err() {
  return status != STATUS_OK;
 }

 /**
  * Initializes or re-initializes reader
  */
 protected void init() {
  status = STATUS_OK;
  frameCount = 0;
  frames = new ArrayList();
  gct = null;
  lct = null;
 }

 /**
  * Reads a single byte from the input stream.
  */
 protected int read() {
  int curByte = 0;
  try {
   curByte = in.read();
  } catch (IOException e) {
   status = STATUS_FORMAT_ERROR;
  }
  return curByte;
 }

 /**
  * Reads next variable length block from input.
  *
  * @return number of bytes stored in "buffer"
  */
 protected int readBlock() {
  blockSize = read();
  int n = 0;
  if (blockSize > 0) {
   try {
    int count = 0;
    while (n < blockSize) {
     count = in.read(block, n, blockSize - n);
     if (count == -1) 
      break;
     n += count;
    }
   } catch (IOException e) {
   }

   if (n < blockSize) {
    status = STATUS_FORMAT_ERROR;
   }
  }
  return n;
 }

 /**
  * Reads color table as 256 RGB integer values
  *
  * @param ncolors int number of colors to read
  * @return int array containing 256 colors (packed ARGB with full alpha)
  */
 protected int[] readColorTable(int ncolors) {
  int nbytes = 3 * ncolors;
  int[] tab = null;
  byte[] c = new byte[nbytes];
  int n = 0;
  try {
   n = in.read(c);
  } catch (IOException e) {
  }
  if (n < nbytes) {
   status = STATUS_FORMAT_ERROR;
  } else {
   tab = new int[256]; // max size to avoid bounds checks
   int i = 0;
   int j = 0;
   while (i < ncolors) {
    int r = ((int) c[j++]) & 0xff;
    int g = ((int) c[j++]) & 0xff;
    int b = ((int) c[j++]) & 0xff;
    tab[i++] = 0xff000000 | (r << 16) | (g << 8) | b;
   }
  }
  return tab;
 }

 /**
  * Main file parser.  Reads GIF content blocks.
  */
 protected void readContents() {
  // read GIF file content blocks
  boolean done = false;
  while (!(done || err())) {
   int code = read();
   switch (code) {

    case 0x2C : // image separator
     readImage();
     break;

    case 0x21 : // extension
     code = read();
     switch (code) {
      case 0xf9 : // graphics control extension
       readGraphicControlExt();
       break;

      case 0xff : // application extension
       readBlock();
       String app = "";
       for (int i = 0; i < 11; i++) {
        app += (char) block[i];
       }
       if (app.equals("NETSCAPE2.0")) {
        readNetscapeExt();
       }
       else
        skip(); // don't care
       break;

      default : // uninteresting extension
       skip();
     }
     break;

    case 0x3b : // terminator
     done = true;
     break;

    case 0x00 : // bad byte, but keep going and see what happens
     break;

    default :
     status = STATUS_FORMAT_ERROR;
   }
  }
 }

 /**
  * Reads Graphics Control Extension values
  */
 protected void readGraphicControlExt() {
  read(); // block size
  int packed = read(); // packed fields
  dispose = (packed & 0x1c) >> 2; // disposal method
  if (dispose == 0) {
   dispose = 1; // elect to keep old image if discretionary
  }
  transparency = (packed & 1) != 0;
  delay = readShort() * 10; // delay in milliseconds
  transIndex = read(); // transparent color index
  read(); // block terminator
 }

 /**
  * Reads GIF file header information.
  */
 protected void readHeader() {
  String id = "";
  for (int i = 0; i < 6; i++) {
   id += (char) read();
  }
  if (!id.startsWith("GIF")) {
   status = STATUS_FORMAT_ERROR;
   return;
  }

  readLSD();
  if (gctFlag && !err()) {
   gct = readColorTable(gctSize);
   bgColor = gct[bgIndex];
  }
 }

 /**
  * Reads next frame image
  */
 protected void readImage() {
  ix = readShort(); // (sub)image position & size
  iy = readShort();
  iw = readShort();
  ih = readShort();

  int packed = read();
  lctFlag = (packed & 0x80) != 0; // 1 - local color table flag
  interlace = (packed & 0x40) != 0; // 2 - interlace flag
  // 3 - sort flag
  // 4-5 - reserved
  lctSize = 2 << (packed & 7); // 6-8 - local color table size

  if (lctFlag) {
   lct = readColorTable(lctSize); // read table
   act = lct; // make local table active
  } else {
   act = gct; // make global table active
   if (bgIndex == transIndex)
    bgColor = 0;
  }
  int save = 0;
  if (transparency) {
   save = act[transIndex];
   act[transIndex] = 0; // set transparent color if specified
  }

  if (act == null) {
   status = STATUS_FORMAT_ERROR; // no color table defined
  }

  if (err()) return;

  decodeImageData(); // decode pixel data
  skip();

  if (err()) return;

  frameCount++;

  // create new image to receive frame data
  image =
   new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE);

  setPixels(); // transfer pixel data to image

  frames.add(new GifFrame(image, delay)); // add image to frame list

  if (transparency) {
   act[transIndex] = save;
  }
  resetFrame();

 }

 /**
  * Reads Logical Screen Descriptor
  */
 protected void readLSD() {

  // logical screen size
  width = readShort();
  height = readShort();

  // packed fields
  int packed = read();
  gctFlag = (packed & 0x80) != 0; // 1   : global color table flag
  // 2-4 : color resolution
  // 5   : gct sort flag
  gctSize = 2 << (packed & 7); // 6-8 : gct size

  bgIndex = read(); // background color index
  pixelAspect = read(); // pixel aspect ratio
 }

 /**
  * Reads Netscape extenstion to obtain iteration count
  */
 protected void readNetscapeExt() {
  do {
   readBlock();
   if (block[0] == 1) {
    // loop count sub-block
    int b1 = ((int) block[1]) & 0xff;
    int b2 = ((int) block[2]) & 0xff;
    loopCount = (b2 << 8) | b1;
   }
  } while ((blockSize > 0) && !err());
 }

 /**
  * Reads next 16-bit value, LSB first
  */
 protected int readShort() {
  // read 16-bit value, LSB first
  return read() | (read() << 8);
 }

 /**
  * Resets frame state for reading next image.
  */
 protected void resetFrame() {
  lastDispose = dispose;
  lastRect = new Rectangle(ix, iy, iw, ih);
  lastImage = image;
  lastBgColor = bgColor;
  int dispose = 0;
  boolean transparency = false;
  int delay = 0;
  lct = null;
 }


 protected void skip() {
  do {
   readBlock();
  } while ((blockSize > 0) && !err());
 }
}

相關推薦

GifDecoder.java原始碼處理GIF圖片

import java.net.*; import java.io.*; import java.util.*; import java.awt.*; import java.awt.image.*; public class GifDecoder {  /**   * Fi

NeuQuant.java原始碼處理GIF圖片

/* NeuQuant Neural-Net Quantization Algorithm  * ------------------------------------------  *  * Copyright (c) 1994 Anthony Dekker  *  * 

使用Thumbnailator處理gif圖片時遇到java.lang.ArrayIndexOutOfBoundsException: 4096異常處理

環境 1.7.0_80 在使用Thumbnailator處理gif圖片時,遇到問題: Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 4096 at com.sun.imageio.plugins.gif.

《瘋狂Java講義第4版》-----第10章【異常處理

異常處理可以提高程式的健壯性、呈現功能給使用者更加友好。Java異常機制主要關鍵字:try、catch、finally、throw、throws。throws關鍵字在宣告方法時候使用,用於宣告該方法可能丟擲的異常。而throw關鍵字用於丟擲一個實際的異常。Jav

《瘋狂Java講義第4版》-----第11章【AWT程式設計】AWT常用元件、事件處理

AWT常用元件 雖說是常用元件,如果不經常使用,還是比較陌生的!!!暫且根據書本列出來一些,先結合書上例項認識之,待之後結合實際案例選擇用之、研究之(參看官方API)! Button Canvas(用於繪圖的畫布) Checkbox CheckboxGroup(

JAVA原始碼學生資訊管理系統

1. [程式碼][Java]程式碼      package student; import java.sql.*; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.ev

Android 廣告banner圖片輪播、圖片瀏覽、仿微信大圖檢視控制元件支援視訊和gif圖片、支援動態新增資料

    之前專案需要做個仿微信檢視大圖,需要新增圓形下載進度,支援視訊和圖片切換等一系列功能控制元件,自己抽空把開發的自定義控制元件的成果重新構造、整理處理封裝成庫(aar),提供出來,有需要朋友,歡迎使用,如果有什麼建議歡迎留言或者GitHub上提issues

java圖片的各種操作(壓縮、加水印文字或圖片、旋轉)

先貼上原始碼,再呼叫測試看效果,整理了3天。如有更好想法或不同見解,歡迎@我([email protected]). import java.awt.AlphaComposite; import java.awt.Color; import java.awt.F

確定有限狀態機和非確定有限狀態機詳解 包含Java實現原始碼Nondeterministic finite automata

本文將講解確定有限自動狀態機和非確定有限自動狀態機的特點和區別。將結合圖片例子重點講解什麼是非確定有限自動狀態機。最後講解如何將非確定狀態機轉換為確定的狀態機。多圖預警!! 有限自動狀態機可以分為確定的和不確定的。“確定性”將在下文詳講。“有限”性表示存在一個

JAVA RGB轉CMYK 原始碼支援格式轉換

Java CMYK轉RGB原始碼網上很多,但是RGB轉CMYK原始碼網上很少,那麼多是隻提供公式,要麼提供依賴檔案不全。這兩天搜尋很好久,終於找到一個可行方法。 專案使用maven搭建,依賴的工具包如下。在pom.xm檔案新增該包依賴 <dependenc

學習代碼檢視方法 摘自某圖片

方法 字符串 路徑 拷貝 就會 溢出 輸入 是否 代碼 看見運算,就檢查整數溢出。 看見拷貝,就檢查越界。 看到字符串輸入,就檢查各種註入。 看到打印信息,就檢查格式話攻擊。 看到文件輸入,就檢查路徑利用。 看到加密算法,就檢查是否安全。 看到開源代碼,就找歷史漏洞。 考見

大文件拆分問題的java實踐附源碼

解決方案 初始化 問題 申請 border output 思想 行數據 時延 引子 大文件拆分問題涉及到io處理、並發編程、生產者/消費者模式的理解,是一個很好的綜合應用場景,為此,花點時間做一些實踐,對相關的知識做一次梳理和集成,總結一些共性的處理方案和思路,以供後續工

java基礎十一章

調用 class 類和對象 可維護 lips 成員 成員方法 基礎 安全 一、理解什麽是類和對象 萬事萬物皆對象 1、屬性——對象具有的特征(特點) 2、方法——對象可執行的操作(能幹什麽事) 3、對象的定義: 是一個客觀

java基礎十五章

ron pen 3.1 長度 默認值 表現 一個數 lang lastindex 一、字符串類String 1、String是一個類,位於java.lang包中 2、創建一個字符串對象的2種方式: String 變量名=“值”;

java基礎十二章

pub () 註釋 href 調用 作用 代碼 一個 for循環 java基礎(十二章) 一、變量的作用域(有效的使用範圍) 1、變量有2種 1.1成員變量(屬性) 聲明在類的裏面,方法的外面 1.2 局部變量

C#調用Java方法詳細實例

art dem 關系 進行 網上 auto mar ctr 環境 閱讀目錄 C#調用c++ C#調用JAVA方法 C#可以直接引用C++的DLL和轉換JAVA寫好的程序。最近由於工作原因接觸這方面比較多,根據實際需求,我們通過一個具體例子把一個JAVA方法轉換成可以

Jquery EasyUI Tree樹形結構的Java實現實體轉換VO

優勢 con control 項目 util turn ttr real org 前一陣做的OA項目,有一個是組織架構的樹,因為是分開做的,我做的是Controller和頁面,其他組做的Service和Dao,因為之前一直沒有商量頁面用什麽框架做比較好,導致,Dao層取出來

八大排序算法原理以及Java實現直接插入排序

不能 oat 設立 side 堆排 八大排序 算法 line load 概述 排序有內部排序和外部排序,內部排序是數據記錄在內存中進行排序,而外部排序是因排序的數據很大,一次不能容納全部的排序記錄,在排序過程中需要訪問外存。 我們這裏說說八大排序就是內部排序。

Java Struts文件下載

mage header int nbsp thead 輸出流 enc lose 註冊 1.從註冊成功頁面跳轉至用戶詳情頁面(跳轉至UserListAction) 2.UserListAction調用service獲得用戶列表,並將這些數據傳送到UserList.jsp

uploadify IE11 不兼容問題不顯示圖片

upload uploadify .html 不顯示圖片 cnblogs activex cti lsh logs 1.進入uploadify官網demo : http://www.uploadify.com/demos/ 2. 顯示 (確認flash為最新版本)