⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 palettedimage.java

📁 用j2me midp1.0,原码正宗
💻 JAVA
字号:

import java.io.InputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import javax.microedition.lcdui.Image;

/**
 * PalettedImage调色板图片类,使用PNG-8图片,可更换其中的颜色。 <br>
 * 注意,除了更换调色板中的颜色之外,这个类实际上是不可更改的Image。
 * 
 * @author flyingghost
 * @version 1.0
 */
public final class PalettedImage {

    private Image image;//生成的图片

    private byte[] imgData;//图片字节数据

    private int paletteOffset;//调色板偏移量

    private int CRCOffset;//CRC校验码偏移量

    private int paletteColors;//调色板颜色数

    private boolean needRebuild;//改变,需要重建立图片

    private PalettedImage() {
    }

    /**
     * 从字节数组中创建PalettedImage
     * 
     * @param data
     *            存放png图片的字节数组
     * @return PalettedImage对象
     * @throws NullPointerException
     *             当data数组为空时
     */
    public static PalettedImage createPalettedImage(byte[] data) {
        if (data == null) {
            throw new NullPointerException();
        }
        PalettedImage pImage = null;
        pImage = new PalettedImage();
        pImage.imgData = data;
        pImage.analyze();
        pImage.image = Image.createImage(pImage.imgData, 0,
                pImage.imgData.length);
        return pImage;
    }

    /**
     * 从图片文件中创建PalettedImage
     * 
     * @param filename
     *            png图片文件路径
     * @return PalettedImage对象
     * @throws NullPointerException
     *             当filename为空时
     * @throws IllegalArgumentException
     *             当路径无效的时候
     * @throws IOException
     *             当发生IO错误时
     */
    public static PalettedImage createPalettedImage(String filename)
            throws IOException {
        if (filename == null) {
            throw new NullPointerException();
        }
        PalettedImage pImage = null;
        InputStream is = null;
        ByteArrayOutputStream baos = null;
        try {
            is = filename.getClass().getResourceAsStream(filename);
            if (is == null) {//创建不成功
                throw new IllegalArgumentException();
            }
            baos = new ByteArrayOutputStream();
            int ch = 0;
            while ((ch = is.read()) != -1) {
                baos.write(ch);
            }

        }
        catch (IOException ioe) {
            throw ioe;
        }
        finally {
            if (baos != null) {
                try {
                    baos.close();
                }
                catch (IOException e) {
                }
            }
            if (is != null) {
                try {
                    is.close();
                }
                catch (IOException e) {
                }
            }
        }
        pImage = createPalettedImage(baos.toByteArray());
        return pImage;
    }

    /**
     * 取得生成的Image对象
     * 
     * @return Image对象
     */
    public Image getImage() {
        if (needRebuild) {
            rebuild();
        }
        return image;
    }

    /**
     * 设置调色板
     * 
     * @param colors
     *            调色板的所有颜色数组
     * @throws NullPointerException
     *             如果颜色数组为空
     * @throws IllegalArgumentException
     *             颜色数组长度和颜色个数不符
     */
    public void setPalette(int[] colors) {
        if (colors == null) {
            throw new NullPointerException();
        }
        if (colors.length != paletteColors) {//长度不符
            throw new IllegalArgumentException();
        }
        for (int i = 0, offset = paletteOffset; i < colors.length; i++, offset += 3) {
            imgData[offset] = (byte) ((colors[i] >> 16) & 0xff);
            imgData[offset + 1] = (byte) ((colors[i] >> 8) & 0xff);
            imgData[offset + 2] = (byte) ((colors[i]) & 0xff);
        }
        needRebuild = true;
    }

    /**
     * 取得调色板的颜色数
     * 
     * @return 颜色数
     */
    public int getColorCount() {
        return paletteColors;
    }

    /**
     * 设置某种颜色
     * 
     * @param index
     *            颜色索引号
     * @param color
     *            新的颜色值,以0xRRGGBB的格式
     * @throws IllegalArgumentException
     *             当索引号不在范围内时
     */
    public void setColor(int index, int color) {
        if (index < 0 || index >= paletteColors) {
            throw new IllegalArgumentException();
        }
        int offset = paletteOffset + index * 3;
        imgData[offset] = (byte) ((color >> 16) & 0xff);
        imgData[offset + 1] = (byte) ((color >> 8) & 0xff);
        imgData[offset + 2] = (byte) ((color) & 0xff);
        needRebuild = true;
    }

    /**
     * 替换某种颜色
     * 
     * @param oldColor
     *            要替换的颜色值,0xRRGGBB格式
     * @param newColor
     *            新的颜色值,0xRRGGBB格式
     */
    public void replaceColor(int oldColor, int newColor) {
        byte rr = (byte) ((oldColor >> 16) & 0xff);
        byte gg = (byte) ((oldColor >> 8) & 0xff);
        byte bb = (byte) (oldColor & 0xff);
        for (int i = 0, offset = paletteOffset; i < paletteColors; i++, offset += 3) {
            if (rr == imgData[offset] && gg == imgData[offset + 1]
                    && bb == imgData[offset + 2]) {//找到
                imgData[offset] = (byte) ((newColor >> 16) & 0xff);
                imgData[offset + 1] = (byte) ((newColor >> 8) & 0xff);
                imgData[offset + 2] = (byte) (newColor & 0xff);
                needRebuild = true;
                break;
            }
        }
    }

    /**
     * 取得调色板颜色
     * 
     * @param index
     *            颜色索引号
     * @return int形式的颜色值
     * @throws IllegalArgumentException
     *             当索引号不在范围内时
     */
    public int getColor(int index) {
        if (index < 0 || index >= paletteColors) {
            throw new IllegalArgumentException();
        }
        int offset = paletteOffset + index * 3;
        return ((imgData[offset] & 0xFF) << 16)
                | ((imgData[offset + 1] & 0xFF) << 8)
                | (imgData[offset + 2] & 0xFF);
    }

    private void rebuild() {//根据新的字节数据重建Image
        CRCChecksum();//重新计算校验和
        image = Image.createImage(imgData, 0, imgData.length);
        needRebuild = false;
        System.gc();
    }

    private void analyze() {//分析调色板相关资料
        int offset = 8;//跳过8字节的PNG头,遍历每个块
        int chunkLen = 0;
        while (imgData[offset + 4] != 0x50 || imgData[offset + 5] != 0x4c
                || imgData[offset + 6] != 0x54 || imgData[offset + 7] != 0x45) {//offset指向的块名称不是PLTE
            chunkLen = readInt(offset);
            offset += (4 + 4 + chunkLen + 4);
        }
        chunkLen = readInt(offset);//块长
        paletteColors = chunkLen / 3;//颜色数
        paletteOffset = offset + 8;//调色板偏移量
        CRCOffset = offset + 8 + chunkLen;//CRC校验码偏移量
    }

    private int readInt(int offset) {//读一个int
        return ((imgData[offset] & 0xFF) << 24)
                | ((imgData[offset + 1] & 0xFF) << 16)
                | ((imgData[offset + 2] & 0xFF) << 8)
                | (imgData[offset + 3] & 0xFF);
    }

    private void CRCChecksum() {//求得新的校验和
        int checksum = CRCUtil.checksum(imgData, paletteOffset - 4,
                paletteColors * 3 + 4);
        imgData[CRCOffset] = (byte) ((checksum >> 24) & 0xff);
        imgData[CRCOffset + 1] = (byte) ((checksum >> 16) & 0xff);
        imgData[CRCOffset + 2] = (byte) ((checksum >> 8) & 0xff);
        imgData[CRCOffset + 3] = (byte) ((checksum) & 0xff);
    }
}

final class CRCUtil {

    private static int[] crc_table;//CRC 表

    private static void make_crc_table() {
        int c;
        int n, k;
        crc_table = new int[256];
        for (n = 0; n < 256; n++) {
            c = n;
            for (k = 0; k < 8; k++) {
                if ((c & 1) == 1)
                    c = 0xedb88320 ^ (c >>> 1);
                else
                    c = c >>> 1;
            }
            crc_table[n] = c;
        }
    }

    private static int update_crc(byte[] buf, int off, int len) {
        int c = 0xffffffff;
        int n;

        if (crc_table == null) {
            make_crc_table();
        }
        for (n = off; n < len + off; n++) {
            c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >>> 8);
        }
        return c;
    }

    static int checksum(byte[] buf, int off, int len) {
        return update_crc(buf, off, len) ^ 0xffffffff;
    }

    CRCUtil() {
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -