MIDP 1.0 無 Graphics.drawImage() 縮放參數,唯一可行路徑:
Image.createImage(w, h) (可變位圖)。Graphics。(x, y)。g.setClip(x, y, 1, 1) 將繪圖區域限制為 1×1 像素。sx = x * srcW / dstW, sy = y * srcH / dstH。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 7610 | Symbian S60 | 140×140 | 1~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[] 陣列操作) | 記憶體中計算後 createRGBImage | 10x~20x | 所有 MIDP |
| 預先生成多解析度圖片 (建構期) | 零運行期成本 | ∞ | 所有版本 |
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 倍以上,且畫質優於最近鄰。
src = null; System.gc(); 釋放大塊記憶體。