Mobile Media API (JSR-135) 透過 capture://video 定位符提供攝影功能。核心類別:Player (媒體控制)、VideoControl (影像顯示/捕獲)、RecordControl (錄影)。本文以 Snapper 範例為基礎,完整呈現從初始化到縮圖生成的工程級實現。
// 1. 檢測裝置支援性
boolean supportsCapture = "true".equals(
System.getProperty("supports.video.capture"));
// 2. 建立 Player 並獲取資源
Player player = Manager.createPlayer("capture://video");
player.realize(); // 關鍵:分配攝影機硬體資源
// 3. 獲取 VideoControl
VideoControl videoControl = (VideoControl) player.getControl("VideoControl");
if (videoControl == null) throw new IllegalStateException("裝置不支援 VideoControl");
public class CameraCanvas extends Canvas {
private VideoControl videoControl;
public CameraCanvas(VideoControl vc) {
this.videoControl = vc;
// 直接視訊模式:繪製至 Canvas 圖形上下文
videoControl.initDisplayMode(VideoControl.USE_DIRECT_VIDEO, this);
try {
// 留 2px 邊框顯示綠色框架
videoControl.setDisplayLocation(2, 2);
videoControl.setDisplaySize(getWidth()-4, getHeight()-4);
} catch (MediaException e) {
try { videoControl.setDisplayFullScreen(true); }
catch (MediaException ignored) {}
}
videoControl.setVisible(true);
}
protected void paint(Graphics g) {
// 繪製綠色取景框
g.setColor(0x00FF00);
g.drawRect(1, 1, getWidth()-3, getHeight()-3);
}
// 按鍵事件觸發拍照
protected void keyPressed(int keyCode) {
if (getGameAction(keyCode) == FIRE) {
midlet.capturePhoto(); // 回調主 MIDlet
}
}
}
Form form = new Form("Camera Preview");
Item videoItem = (Item) videoControl.initDisplayMode(
VideoControl.USE_GUI_PRIMITIVE, null);
form.append(videoItem);
Display.getDisplay(midlet).setCurrent(form);
// 1. 捕獲原始影像資料 (預設 PNG 格式)
byte[] rawImage = videoControl.getSnapshot(null); // null = 預設編碼
// 2. 建立 Image 物件供顯示/儲存
Image capturedImage = Image.createImage(rawImage, 0, rawImage.length);
// 3. 可選:預先查詢支援編碼格式
String encodings = System.getProperty("video.snapshot.encodings"); // 如 "png jpeg"
// 指定格式捕獲
byte[] jpegImage = videoControl.getSnapshot("encoding=jpeg");
MIDP 1.0 無 Image.getRGB() 直接像素存取,採用剪裁繪製法:
private Image createThumbnail(Image source) {
int srcW = source.getWidth();
int srcH = source.getHeight();
int thumbW = 64;
int thumbH = thumbW * srcH / srcW; // 保持比例
Image thumb = Image.createImage(thumbW, thumbH);
Graphics g = thumb.getGraphics();
// 逐像素採樣:以 1x1 剪裁區域繪製源圖對應區域
for (int y = 0; y < thumbH; y++) {
for (int x = 0; x < thumbW; x++) {
g.setClip(x, y, 1, 1); // 單像素剪裁區
int srcX = x * srcW / thumbW;
int srcY = y * srcH / thumbH;
// 繪製源圖使目標像素 (x,y) 顯示源圖 (srcX, srcY)
g.drawImage(source, x - srcX, y - srcY, Graphics.LEFT | Graphics.TOP);
}
}
// 建立不可變副本釋放 Graphics 資源
return Image.createImage(thumb);
}
原理:利用 Graphics.setClip() 限制繪製區域為單一像素,透過負座標偏移將源圖對應區域「投影」至目標像素。雖效能較低 (O(W×H)),但在小尺寸縮圖 (64×48) 可接受。
ImageItem 動態展示縮圖畫廊rawImage 寫入檔案系統 (JSR-75) 或 RMSImage.getRGB()/createRGBImage() 實現濾鏡、銳化、幾何變換realize() 後才能獲取 Control,start() 後預覽才啟動player.close(),否則攝影機鎖定影響其他應用byte[]掌握 MMAPI 攝影完整流程,即可開發行動掃描、拍照記帳、人臉識別前端等豐富影像應用。