zoukankan      html  css  js  c++  java
  • J2ME 图片压缩算法

    import java.io.DataInputStream;
    import javax.microedition.lcdui.Image;
    public class Tools {
    private static final int FLAG_16BIT_4_LEN = 0;
    private static final int FLAG_REBUILD_SIZE = 0;
    private static final int FLAG_REBUILD_MODULE = 0;


    * 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。为了充分利用这 3bits,我们可以将 C 的值保存在这 3bits中,
    * 这样我们的格式变为 [G1][G2]….[Gk] 共 K个(G的高位为数量,低位为颜色索引)。这样,对于32色的图,
    * 每个字节最多可以保存8个象素的信息,对于64色的图,每个字节最多可以保存4个象素的信息,对于16色的图,每个字节最多
    * 可以保存16个象素的信息。 在[G1][G2]….[Gk] 这K个字节前,再加上调色板数据和其它本图的必要信息,就得到了USI格式的文件。
    *****************************************************************************************************************/
    int m_flags ,m_count ,m_mask ,m_modelCount ,m_dataSize ;
    int m_rebuildWidth,m_rebuildHeight;
    int[][] m_pal ;
    int []m_dataOffset;
    byte[] m_models ,m_data ;
    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) {
    }
    }

    * 解压缩指定图块像素数据
    *
    * @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;
    }
    }
  • 相关阅读:
    SQL学习
    FOR XML PATH
    IOS学习网址
    weak nonatomic strong等介绍(ios)
    UVALive3045 POJ2000 ZOJ2345 Gold Coins
    UVA713 UVALive5539 POJ1504 ZOJ2001 Adding Reversed Numbers
    UVA713 UVALive5539 POJ1504 ZOJ2001 Adding Reversed Numbers
    UVA439 POJ2243 HDU1372 ZOJ1091 Knight Moves【BFS】
    UVA439 POJ2243 HDU1372 ZOJ1091 Knight Moves【BFS】
    UVA10905 Children's Game
  • 原文地址:https://www.cnblogs.com/liuzhuqing/p/7480445.html
Copyright © 2011-2022 走看看