首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> J2ME

J2ME BMP 圖片編碼器:無壓縮位圖生成與跨平台圖像交換實現

     編輯:J2ME

前言

J2ME 標準僅支援 PNG 解碼,**無任何圖片編碼器**。若需將運行時生成/修改的圖片持久化或網絡傳輸,BMP 是最簡單的無壓縮格式選擇。本文提供基於 LGPL 的 BMPEncoder 實現,解決 Endian、文件頭結構、行填充對齊等坑點。

為什麼選 BMP?

  • **格式極簡**:文件頭 (14B) + 信息頭 (40B) + 像素數據,無壓縮、無濾鏡、無塊。
  • **跨平台通用**:Windows、Linux、Java SE、Web 瀏覽器、圖片查看器皆原生支援。
  • **編碼邏輯直觀**:逐行寫入像素 (BGR 順序)、行尾 4 字節對齊填充。
  • **J2ME 可行**:僅需 DataOutputStream、Image.getRGB()、基本整數運算。

核心編碼流程


public class BMPEncoder {
    public static byte[] encode(Image img) throws IOException {
        int w = img.getWidth(), h = img.getHeight();
        int[] rgb = new int[w];
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        DataOutputStream dos = new DataOutputStream(bos);

        // 1. 計算行大小 (4 字節對齊)
        int rowSize = ((w * 3 + 3) / 4) * 4; // 24-bit BGR
        int dataSize = rowSize * h;
        int fileSize = 14 + 40 + dataSize;

        // 2. 寫文件頭 (BITMAPFILEHEADER, 14 bytes)
        dos.writeShort(0x4D42);          // 'BM'
        dos.writeInt(fileSize);          // 文件大小 (Little Endian)
        dos.writeShort(0); dos.writeShort(0); // 保留
        dos.writeInt(14 + 40);           // 數據偏移

        // 3. 寫信息頭 (BITMAPINFOHEADER, 40 bytes)
        dos.writeInt(40);                // 信息頭大小
        dos.writeInt(w); dos.writeInt(h); // 寬高
        dos.writeShort(1);               // 平面數
        dos.writeShort(24);              // 位深 (24-bit)
        dos.writeInt(0);                 // 無壓縮
        dos.writeInt(dataSize);          // 圖像數據大小
        dos.writeInt(2835); dos.writeInt(2835); // DPI (72dpi = 2835 px/m)
        dos.writeInt(0); dos.writeInt(0); // 調色板顏色數/重要顏色數

        // 4. 寫像素數據 (底行在前,BGR 順序,行填充)
        for (int y = h - 1; y >= 0; y--) {
            img.getRGB(rgb, 0, w, 0, y, w, 1);
            for (int x = 0; x < w; x++) {
                int pixel = rgb[x];
                dos.writeByte(pixel & 0xFF);         // B
                dos.writeByte((pixel >> 8) & 0xFF);  // G
                dos.writeByte((pixel >> 16) & 0xFF); // R
            }
            // 行填充
            for (int p = w * 3; p < rowSize; p++) dos.writeByte(0);
        }
        dos.flush();
        return bos.toByteArray();
    }
}

關鍵坑點總結

修正後的 Little Endian 寫入輔助方法


private static void writeIntLE(DataOutputStream dos, int v) throws IOException {
    dos.writeByte(v & 0xFF);
    dos.writeByte((v >> 8) & 0xFF);
    dos.writeByte((v >> 16) & 0xFF);
    dos.writeByte((v >> 24) & 0xFF);
}
private static void writeShortLE(DataOutputStream dos, int v) throws IOException {
    dos.writeByte(v & 0xFF);
    dos.writeByte((v >> 8) & 0xFF);
}

將文件頭/信息頭所有 writeInt/writeShort 替換為上述 LE 版本。

應用場景

  • 遊戲截圖分享 (保存到 RMS/文件系統、MMS 發送、HTTP 上傳)。
  • 動態生成圖表/地圖/二維碼圖片導出。
  • 跨平台圖像數據交換 (J2ME 端編碼 → 服務器/PC 端解碼)。

局限與擴展

  • 僅支援 24-bit RGB:不支援索引色、16-bit、32-bit、RLE 壓縮。
  • 無解碼器:J2ME 無法直接讀取 BMP 顯示 (需自寫解碼器或轉 PNG)。
  • 擴展方向: 基於此實現 PNG 編碼器 (需 DEFLATE 壓縩、CRC32、塊結構),參考 TinyLine GZIPInputStream 移植 zlib 最小子集。

總結

BMP 編碼器讓 J2ME 獲得「寫圖片」能力,打破「只能讀 PNG」的單向限制。掌握 Little Endian、行填充、BGR 順序、底行在前四大鐵律,即可輸出標準兼容的 BMP 文件。代碼 < 100 行,零依賴,直接集成。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
坑點說明解決
EndianBMP 規範強制 Little EndianDataOutputStream 默認 Big Endian,**必須手動寫 Little Endian** (如上代碼用 writeShort/writeInt 實際為 Big Endian,**錯誤!** 正確需自寫 writeIntLE 或用 ByteBuffer.order(ByteOrder.LITTLE_ENDIAN) — J2ME 無 ByteBuffer,只能手寫移位寫入)
行填充每行必須 4 字節對齊rowSize = ((w*3+3)/4)*4,不足補 0
行序BMP 底行在前 (y=h-1 先寫)循環 for (y=h-1; y>=0; y--)
像素序BGR (非 RGB),無 Alpha藍綠紅順序寫入,忽略 Alpha 通道
有符號/無符號Java byte 有符號,寫入時 & 0xFF 強制無符號見代碼 dos.writeByte(pixel & 0xFF)