程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> J2ME >> 用MMAPI拍照

用MMAPI拍照

編輯:J2ME
而J2ME技術發展很快,文中提到的開發工具和運行測試環境現在都有較大變動,請讀者注意。

譯文

概述

    Mobile Media API(MMAPI)讓MIDlet能夠播放和錄制音頻和視頻數據.但是設備的真實能力還是依賴於其具體實現。目前,支持MMAPI的唯一設備是Nokia 3650.本文描述了如何利用MMAPI來構建一個簡單的拍照程序。

開發MMAPI應用程序所用工具


     構建MMAPI應用程序的第一個難題是找到正確的開發工具.J2ME Wireless Toolkit 2.0支持MIDP2.0,MMAPI 1.0,WMA1.1.乍一看,它包括了你所要的一切.但是Nokia 3650只能運行MIDP1.0,不能運行MIDP2.0.為了開發MIDP1.0的應用程序,你需要J2ME Wireless Toolkit的1.0.4版,外帶一個支持 MMAPI的模擬器。
    Sun提供這樣一個模擬器,你可以在MMAPI的主頁上找到(http://Java.sun.com/products/mmapi/index.JSP).盡管你可以利用該模擬器構建MMAPI應用程序,但是它不支持拍照,因此你不能用它來測試拍照的應用程序。
    Nokia有一個支持拍照的模擬器,它是Nokia SerIEs 60 MIDP Concept SDK Beta 0.2的一個組成部分.你可以在Nokia的開發者論壇(http://www.forum.nokia.com)上找到.文件的名字是nS60_jme_concept_sdk_b0_2_014.zip,Linux開發者應該是用2.0版的Nokia Developer's Suite for J2ME(http://www.forum.nokia.com/nds_for_J2ME.Html),下面的安裝指南只適用於Windows環境。
    首先,在<J2ME Wireless Toolkit>\wtklib\devices目錄下安裝Nokia SDK(把Nokia_SerIEs_60_MIDP_Concept_SDK_Beta_0_2的安裝目錄拷貝到這個目錄亦可).接下來,運行J2ME Wireless Toolkit,你就有一個額外的模擬器--Nokia_SerIEs_60_MIDP_Concept_SDK_Beta_0_2可用了。選擇該模擬器後,你就可以構建和測試你的MMAPI應用程序了。該模擬器和真實的Nokia 3650看起來非常相似。

MMAPI的測試設備


    沒有什麼能替代真機測試。從長遠觀點來看,將會有很多設備支持MMAPI,但是Nokia 3650是目前唯一支持MMAPI的設備.有好幾種方式可以在Nokia 3650真機上發布MIDlet.我使用紅外接口在我的筆記本和手機上傳輸文件。你也可以使用藍牙和OTA.

獲取照相機


    MIDlet中拍照(正式的說法叫視頻捕捉)的第一步是從Manager獲取一個Player。一個特殊的定位符:capture://video,指示照相機使用缺省的圖片大小來拍照。
    mPlayer = Manager.createPlayer("capture://video");
如果設備不支持視頻捕捉,這將會拋出一個MediaException。你可以預先檢查一下設備是否支持拍照,如果系統屬性supports.video.capture的值為真,那麼該設備就支持照相功能。
    為了獲取拍照所需資源,Player需要被realize.如果你沒有學過或者忘記了realized是什麼意思,請參考<Mobile Media API OverIEw>(http://developers.sun.com/techtopics/mobility/apis/articles/mmapi_overvIEw/)或者J2ME Mobile Media API.

mPlayer.realize();


顯示相機視頻


    來源於照相機的視頻可以作為一個Item添加到Form上,也可以作為Canvas的一部分。一個VideoControl可以讓你實現這個功能,你可以采用如下語句獲取VideoControl.
    
mVideoControl = (VideoControl)
        mPlayer.getControl("VideoControl");

    如果你希望在Canvas裡面顯示來源於相機的視頻,初始化VideoControl,然後在Canvas裡面設置視頻的大小和位置,最後使視頻可見。下面的例子(一個Canvas字類的構造函數)顯示了如何把視頻擺放在離Canvas上下邊框2個像素寬的位置。如果不能這樣放置,構造函數試著使用整個屏幕,最後,它調用setVisible()使視頻可見.
    public CameraCanvas(SnapperMIDlet midlet,
    VideoControl videoControl) {
  int width = getWidth();
  int height = getHeight();
  
  mSnapperMIDlet = midlet;
  
  videoControl.initDisplayMode(
      VideoControl.USE_DIRECT_VIDEO, this);
  
  try {
    videoControl.setDisplayLocation(2, 2);
    videoControl.setDisplaySize(width - 4, height - 4);
  }
  catch (MediaException me) {
    try { videoControl.setDisplayFullScreen(true); }
    catch (MediaException me2) {}
  }
  videoControl.setVisible(true);
}

在Form裡面顯示視頻稍微有所不同.我們不再用USE_DIRECT_VIDEO參數調用VideoControl的initDisplayMode(),而是代之以USE_GUI_PRIMITIVE參數。在MIDP設備上,你可以獲得一個Item顯示在Form上

Form form = new Form("Camera form");
Item item = (Item)mVideoControl.initDisplayMode(
    GUIControl.USE_GUI_PRIMITIVE, null);
form.append(item);

拍照


一旦相機視頻顯示在設備上,拍照就很容易了.你所需要的只是調用一下VideoControl的getSnapshot()方法。為了調用該方法,你需要傳遞一個圖片類型參數,如果你使用null作參數,那麼相機就會適用缺省的圖片類型?PNG.通過獲取用空格隔開的系統屬性video.snapshot.encodings的值,你可以預先獲取相機支持的圖片類型。

    The getSnapshot()方法返回一個字節數組,裡面是按你所指定的圖片格式的圖片數據。接下來,你就可以隨意行事了,你可以把這個字節數組存儲在數據庫裡,也可以把它發到服務器上去,或者依據這個字節數組構造一個Image對象,這樣你就可以把剛才所拍照片顯示在用戶面前,如下例所示:
    byte[] raw = mVideoControl.getSnapshot(null);
    Image image = Image.createImage(raw, 0, raw.length);

創建微縮圖


在這篇文章中,我想要談談如何創建微縮圖片,也就是使所拍的相片縮小化。這事看起來簡單,其實卻並不輕松。MIDP2.0中包含一些方法,這些方法可以從Image對象中獲取原始的像素數據,有可能實現圖像的伸縮變換。不幸的是,MIDP1.0並不提供對像素數據的直接訪問。
從圖像處理角度來看,我這裡采用的解決辦法既不優雅,也不嚴格正確。但是這種辦法接近我所需要的效果,並且不涉及到手工解析PNG格式。我創建了一個新的空白的圖片作為微縮圖,對於圖片的每個像素,我設置一個圍繞該像素的極小的剪切區。然後把原始圖片繪制在一個適當的位置上,這樣就設置了微縮圖的每一個像素.

private Image createThumbnail(Image image) {
  int sourceWidth = image.getWidth();
  int sourceHeight = image.getHeight();
  
  int thumbWidth = 64;
  int thumbHeight = -1;
  
  if (thumbHeight == -1)
    thumbHeight = thumbWidth * sourceHeight / sourceWidth;
  
  Image thumb = Image.createImage(thumbWidth, thumbHeight);
  Graphics g = thumb.getGraphics();
  
  for (int y = 0; y < thumbHeight; y++) {
    for (int x = 0; x < thumbWidth; x++) {
      g.setClip(x, y, 1, 1);
      int dx = x * sourceWidth / thumbWidth;
      int dy = y * sourceHeight / thumbHeight;
      g.drawImage(image, x - dx, y - dy,
          Graphics.LEFT | Graphics.TOP);
    }
  }
  
  Image immutableThumb = Image.createImage(thumb);
  
  return immutableThumb;
}

Snapper例子


從本文下載的源代碼是一個叫做Snapper的程序。Snapper讓你可以把所拍照片的所有微縮圖都顯示在一個Form裡.本文所引用的代碼來源於Snapper.Snapper程序僅包含2個類。SnapperMIDlet提供應用邏輯和視圖流程控制,與絕大部分的MMAPI代碼相似,需要創建Player,獲取snapshot.CameraCanvas是一個Canvas的子類,它包含一個VideoControl來顯示相機視頻。
    Snapper能聰明的發現目標設備是否支持視頻捕捉,如果你在Sun的MME模擬器上運行該程序,你會收到一個優雅的反饋信息:
Running Two Copies of the Whisper Example  
在不支持視頻捕捉的設備上運行Snapper
如果你使用Nokia的Concept模擬器,你將看到如下效果:
Snapper's Main Screen  
Snapper的主屏
選擇Camera命令(Nokia機型把該命令放在Options菜單裡),在一台真機上,你可以看到來源於攝像頭的視頻,模擬器只能顯示單幅的靜態圖像。但是在這2種情況下,CameraCanvas都會在視頻周圍畫上一個綠框。
Snapper's Camera Screen 
Snapper的攝像機屏幕
要拍照的話,你只需選擇Capture命令或者按開火鍵(位於方向鍵中心),Snapper將創建一個微縮圖片並顯示在MIDlet的主屏上。
Snapper's Main Screen With a Thumbnail  
放置了微縮圖的Snapper主屏

未來的改進


Snapper是一個非常簡單的例子,但是有很多有趣的地方你可以改進。
1.你可以把整個相片保存在數據庫裡,這樣你可以在今後浏覽。
2.你可以允許玩家刪除相片,或者改變其次序
3.你可以把整個相片發送到一個服務器上存儲起來,並且提供一個Web視圖進行浏覽。
4.使用MIDP2.0,你可以對圖片做標准的變換處理:模糊,銳化,顏色反轉,幾何變換等等。

總結

   MMAPI是一個靈活而強大的API,它讓開發者能表現和捕獲音頻和視頻數據。本文描述了MMAPI的拍照功能,所需工具,以及如何編寫拍照的MIDlet. Snapper例子實現了拍照功能和微縮圖功能。你只要稍作加工,該例子就可以成為一個網絡相片共享程序的基礎.

關於作者


    Jonathan Knudsen出了好幾本書,包括《Wireless Java (second edition)》,《The Unofficial Guide to LEGO MINDSTORMS Robots》,《Learning Java (second edition)》,《Java 2D Graphics》。Jonathan在Java 和 Lego robots方面廣泛寫作,他還為JavaWorld, EXE, NZZ Folio, and the O'Reilly Network寫文章. Jonathan在普林斯頓大學獲得了機械工程學位.
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved