程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> J2ME >> png壓縮原理

png壓縮原理

編輯:J2ME

1 壓縮原理
要明白 USI 的壓縮原理,首先需要對圖像的存儲方法有一個基礎的懂得。USI 壓縮是建立在索引色的基礎上進行的。
1.1 索引圖與RGB圖
對於PNG圖像,可以分為索引(Index)圖和RGB圖兩種,索引圖只包含固定數目標色彩,而RGB圖的色彩數目是不受限制的。
RGB圖的每一個象素都保留一個RGB值,代表這個象素的色彩,因此,一張RGB圖有多少個象素,文件中就保留多少個RGB值。
而索引圖會將其固定數目標色彩,按照次序排列起來,作為色彩的索引保留在文件頭中,被稱為調色板(palette)。每一個象素只保留其色彩在調色板中的索引。
如一個32色的索引圖,在文件頭中保留了32個色彩,索引值從0到31。圖中每一個象素只記錄其色彩的索引。
因此,對於一般的PNG圖,索引圖文件的大小總是小於RGB圖的。
1.2 行程壓縮原理
當我們把一張索引圖的所有象素(N個),按照從上到下,從左至右,即按行掃描的次序排列起來的時候,我們得到一個隊列。假如我們用1個字節來存儲一個象素

的索引值(調色板色彩不超過256),那麼數據的大小為N字節。這段數據的格局我們表現為 [I1][I2]…[In] 共 N 個。
在上面的隊列中,可能會呈現許多持續雷同的索引值,最多的就是透明色。假如我們在每個索引值前用1個字節保留這個值持續呈現的數目(最多可以表現256個

),那數據的格局變為 [C1][I1][C2][I2]…[Cm][Im] 共 M 個。那麼一張256個象素的單色圖的所有數據,只需要2個字節來保留。通常,我們所需的圖中總

是有***持續的色彩,包含透明色,因此按照這個格局保留的圖像,其文件大小可以大大下降,這就是行程的壓縮原理。
1.3 USI壓縮原理
假如一張索引圖的色彩數為32,那麼在[C1][I1][C2][I2]…[Cm][Im] 格局中,I的數值都小於32,那麼每個字節前3 bits 始終為0。為了充分利用這 3

bits,我們可以將 C 的值保留在這 3bits中,這樣我們的格局變為 [G1][G2]….[Gk] 共 K 個(G的高位為數目,低位為色彩索引)。這樣,對於32色的圖,

每個字節最多可以保留8個象素的信息,對於64色的圖,每個字節最多可以保留4個象素的信息,對於16色的圖,每個字節最多可以保留16個象素的信息。
在 [G1][G2]….[Gk] 這K個字節前,再加上調色板數據和其它本圖的必要信息,就得到了USI格局的文件。
 
conan(29842977) 15:03:01
1.1 載進文件
  private void load(String file) {
    try {
      DataInputStream din = new DataInputStream(getClass().getResourceAsStream(file));

      m_flags = din.readInt(); //格局標記

      /** 讀取調色板信息 */

 m_count = din.readByte() & 0xff;   //調色板位數
      m_mask = 0xff >> (8 - m_count);   //盤算 取色板索引的掩碼
      int pal_count = din.readByte() & 0xff;  //調色板數目
      int pal_len = din.readByte() & 0xff;  //調色板長度 即色彩數
      m_pal = new int[pal_count][pal_len]; //初始化調色板容器
      int pal;
      //讀取調色板信息
      for (int i = 0; i < pal_count; i++) {
        for (int j = 0; j < pal_len; j++) {
          pal = din.readShort() & 0xffff;
          m_pal[i][j] = (
              ( ( ( (pal & 0xF000) >>> 12) * (17 << 24)) & 0xFF000000) |
              ( ( ( (pal & 0x0F00) >>> 8) * (17 << 16)) & 0x00FF0000) |
              ( ( ( (pal & 0x00F0) >>> 4) * (17 << 8)) & 0x0000FF00) |
              ( ( ( (pal & 0x000F) * 17)))
              );
        }
      }

      /** 讀取圖塊信息 */
      m_modelCount = din.readShort() & 0xffff; //圖塊數目
      //讀取圖塊尺寸
      if ( (m_flags & FLAG_REBUILD_SIZE) != 0) {
        //基於尺寸的轉換方法
        m_rebuildWidth = din.readByte() & 0xff;
        m_rebuildHeight = din.readByte() & 0xff;
      } else if ( (m_flags & FLAG_REBUILD_MODULE) != 0) {
        //基於動畫model的轉換方法
        m_models = new byte[m_modelCount * 2];
        din.read(m_models);
      }

      /** 讀取像素數據 */
      m_dataSize = din.readInt();   //像素數據大小(壓縮數據)
      m_data = new byte[m_dataSize];
      din.read(m_data);    //讀取像素數據(壓縮數據)

      //讀取每個圖塊數據的起始偏移量

 int offset = 0;
      m_dataOffset = new int[m_modelCount];
      for (int i = 0; i < m_modelCount; i++) {
        m_dataOffset[i] = offset;
        if ( (m_flags & FLAG_16BIT_4_LEN) != 0) {
          offset += din.readShort();
        } else {
          offset += din.readByte() & 0xff;
        }
      }
    } catch (Exception ex) {}
  }

1.2 解壓縮

  /******************************************
   * 解壓縮指定圖塊像素數據
   * @param model_id int 圖塊號
   * @param pal_id int 調色板號
   * @return int[] 解壓縮圖塊像素數據(ARPG值)
   ******************************************/
  private int[] BuildRle8bFrm(int model_id, int pal_id) {

    //盤算解壓後,像素數據的大小(圖塊W*圖塊H)
    int size;
    if ( (m_flags & FLAG_REBUILD_SIZE) != 0) {
      size = m_rebuildWidth * m_rebuildHeight;
    } else {
      size = (m_models[model_id * 2] & 0xff) *
          (m_models[model_id * 2 + 1] & 0xff);
    }

    //初始化像素buf
    int[] m_bufB = new int[size];

    int pal[] = m_pal[pal_id];    //獲取當前調色板
    int offset = m_dataOffset[model_id];  //獲取壓縮數據出發點

    //解壓縮
    int count, index, pos = 0;
    while (pos < size) {
      count = ( (m_data[offset] & 0xFF) >> m_count) + 1;
      index = pal[m_data[offset] & m_mask];
      offset++;
      while (--count >= 0) {
        m_bufB[pos++] = index;
      }
    }
    return m_bufB;
  }


  /**********************************
   * 獲取指定圖塊Image
   * @param model_id int 圖塊號
   * @param pal_id int 調色板號
   * @return Image 圖塊Image對象
   **********************************/
  public Image GetImage(int model_id, int pal_id) {

    //獲得指定圖塊解壓數據(ARPG色彩數據)

 int[] m_bufB = BuildRle8bFrm(model_id, pal_id);

    //盤算圖塊尺寸
    int w, h;
    if ( (m_flags & FLAG_REBUILD_SIZE) != 0) {
      w = m_rebuildWidth;
      h = m_rebuildHeight;
    } else {
      w = m_models[model_id * 2] & 0xff;
      h = m_models[model_id * 2 + 1] & 0xff;
    }

    //天生Image圖片
    Image m_image = Image.createRGBImage(m_bufB, w, h, true);
    m_bufB = null;
    return m_image;
  }

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved