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

MIDP 1.0 圖片縮放實作:setClip 像素級採樣法與效能優化

     編輯:J2ME

演算法原理:最近鄰採樣 + setClip 逐像素繪製

MIDP 1.0 無 Graphics.drawImage() 縮放參數,唯一可行路徑:

  1. 建立目標尺寸 Image.createImage(w, h) (可變位圖)。
  2. 取得其 Graphics。
  3. 雙重迴圈遍歷目標每個像素 (x, y)。
  4. g.setClip(x, y, 1, 1) 將繪圖區域限制為 1×1 像素。
  5. 計算對應源圖座標 sx = x * srcW / dstW, sy = y * srcH / dstH。
  6. g.drawImage(srcImg, x - sx, y - sy, Graphics.LEFT|Graphics.TOP),只會在剪裁區畫出該源像素。

原始碼 (含縱橫比保持)

public Image resizeImage(Image src, int scalePercent) {
    // scalePercent: 100 = 原大小, 50 = 縮半, 200 = 放雙倍
    int srcW = src.getWidth();
    int srcH = src.getHeight();
    int dstW = srcW * scalePercent / 100;
    int dstH = srcH * scalePercent / 100; // 等比例

    Image dst = Image.createImage(dstW, dstH);
    Graphics g = dst.getGraphics();

    for (int y = 0; y < dstH; y++) {
        for (int x = 0; x < dstW; x++) {
            g.setClip(x, y, 1, 1);
            int sx = x * srcW / dstW;
            int sy = y * srcH / dstH;
            g.drawImage(src, x - sx, y - sy, Graphics.LEFT | Graphics.TOP);
        }
    }
    return dst;
}

實測效能數據 (參考)

裝置CPU/平台縮放 140×140 → 目標耗時評價
Motorola OT557低端140×140~6 秒極慢,慎用
Nokia 7610Symbian S60140×1401~2 秒可接受
Sony Ericsson K700中端140×140~1 秒尚可

結論:setClip 逐像素繪製涉及大量 Java/JNI 邊界呼叫與剪裁計算,極度消耗 CPU。僅適合「啟動時一次性縮放小圖示」等極低頻場合。

優化替代方案

方案原理速度提升適用版本
MIDP 2.0 drawImage + Graphics.drawRegion原生縮放 (裝置實作)100x+MIDP 2.0+
Nokia UI API DirectGraphics.drawImage with transform硬體加速/原生縮放50x+Nokia S40/S60
雙線性插值 Java 實作 (int[] 陣列操作)記憶體中計算後 createRGBImage10x~20x所有 MIDP
預先生成多解析度圖片 (建構期)零運行期成本∞所有版本

雙線性插值 Java 實作參考 (MIDP 1.0 通用)

public Image resizeBilinear(Image src, int dstW, int dstH) {
    int srcW = src.getWidth(), srcH = src.getHeight();
    int[] srcPix = new int[srcW * srcH];
    src.getRGB(srcPix, 0, srcW, 0, 0, srcW, srcH);

    int[] dstPix = new int[dstW * dstH];
    float xRatio = (float)srcW / dstW;
    float yRatio = (float)srcH / dstH;

    for (int y = 0; y < dstH; y++) {
        float sy = y * yRatio;
        int y0 = (int)sy;
        int y1 = Math.min(y0 + 1, srcH - 1);
        float dy = sy - y0;

        for (int x = 0; x < dstW; x++) {
            float sx = x * xRatio;
            int x0 = (int)sx;
            int x1 = Math.min(x0 + 1, srcW - 1);
            float dx = sx - x0;

            int c00 = srcPix[y0 * srcW + x0];
            int c10 = srcPix[y0 * srcW + x1];
            int c01 = srcPix[y1 * srcW + x0];
            int c11 = srcPix[y1 * srcW + x1];

            // 簡易雙線性 (分通道插值)
            int r = lerp(lerp((c00>>16)&0xFF, (c10>>16)&0xFF, dx),
                         lerp((c01>>16)&0xFF, (c11>>16)&0xFF, dx), dy);
            int g = lerp(lerp((c00>>8)&0xFF, (c10>>8)&0xFF, dx),
                         lerp((c01>>8)&0xFF, (c11>>8)&0xFF, dx), dy);
            int b = lerp(lerp(c00&0xFF, c10&0xFF, dx),
                         lerp(c01&0xFF, c11&0xFF, dx), dy);

            dstPix[y * dstW + x] = (0xFF<<24) | (r<<16) | (g<<8) | b;
        }
    }
    return Image.createRGBImage(dstPix, dstW, dstH, true);
}
private int lerp(int a, int b, float t) { return a + (int)((b - a) * t); }

此法在 140×140 圖片上通常 < 200ms (Nokia 7610),比 setClip 快 10 倍以上,且畫質優於最近鄰。

最佳實踐建議

  1. 優先建構期預生成:Ant/Polish 腳本呼叫 ImageMagick/Java2D 產出各解析度 PNG,打包進 JAR,運行期直接載入。
  2. 次選雙線性 Java 實作:僅在無法預知目標尺寸 (如用戶上傳頭像) 時使用。
  3. 避免 在遊戲主迴圈、動畫幀中做任何形式的圖片縮放。
  4. 記憶體管理:縮放後若不再需要原圖,手動 src = null; System.gc(); 釋放大塊記憶體。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved