分享
 
 
 

基于NOKIA的Camera MIDlet设计

王朝other·作者佚名  2006-01-10
窄屏简体版  字體: |||超大  

作者:crystal 文章来源:yesky

简介

本设计指南以诺基亚3650为设计原型。一些基于MIDP的移动电话使用移动多媒体API,这些API使MIDlets具有更强大的多媒体能力,尤其是可以支持通过移动电话的照相设备进行图像捕获。

这个指南描述了照相MIDlet,提供了一个简单的使用这种图像捕获能力的示例程序。这种照相MIDlet非常简单特别适合作为使用指南介绍。所以在本指南中提出了一些扩展的方法。

本文假设你假设你已经了解Java编程,同时也了解了基于MIDP的编程,如果您没有这些基础,那么请先学习MIDP编程。

移动多媒体API进行图像捕获

移动多媒体规范包括了怎样使用照相设备捕获图像的代码片断,照相MIDlet使用了同样的技术。

首先必须创建一个用户:

Playerplayer;

player=Manager.createPlayer("capture://video");

然后初始化用户:

player.realize();

下面我们需要一个显示图像的video control:

VideoControlvideoControl;

videoControl=(VideoControl)player.getControl("VideoControl");

video control有两种显示模式:一种是作为MIDP低层用户接口Canvas对象出现;另一种是作为MIDP高层用户接口窗体控件出现。在这类MIDlet中可以使用Canvas方式,但在第5部分选择执行中需要选择窗体模式。

videoControl.initDisplayMode(VideoControl.USE_DIRECT_VIDEO,canvas);

启动原先创立的Player对象,以便用户可以看见照相头的指示:

player.start();

一旦照相启动,就可以获得一个简单的图像的数据:

byte[]pngData=videoControl.getSnapshot(null);

getSnapshot方法的参数代表获得图像数据的格式,如果该参数为NULL,那么表明获得图像的格式为PNG,这样就保证图像能被所有设备执行。

获得的数据可以由多种方式使用,比如该数据可以存储起来稍后使用,也可以用HTTP方式发送到服务器,也可以立即将其作为一幅图像显示出来,要立即显示可以使用Image对象的createImage(byte[], int, int)方法:

ImagephotoImg=Image.createImage(pngData,0,pngData.length);

图像和图像数据将占有大量内存,所以在不再需要以后要将其释放。

照相MIDlet设计

用户界面设计

照相MIDlet有两种屏幕可供选择:

图1

第一种屏幕是显示镜头前连续的视屏图像,当用户认为镜头图像已经选择好了只需要简单的选择"Capture"或"game action"按钮。

图2

第二种是显示获得的静态照片,为了使文中的MIDlet实例更为简单,所以我没有对图像作任何其他操作,包括存储或发送其他地方。

软件设计

图3 Camera MIDlet类框图

从框图中我们可以清楚的看到CameraMIDlet创建了CameraCanvas 和 DisplayCanvas,CameraCanvas需要一个由MMAPI Manager类创建的图像捕获player并接受一个执行player接口的对象,这个对象需要Video Control并接受一个执行VideoControl接口的对象。你不需要了解更具体的情况,只需通过界面与这些对象的交互就可以了。

示例程序

CameraMIDlet类

MIDlet类控制显示的screen用户界面,当screen需要转变到其他的screen时,screen将回调其自身,screen不能直接与其他screen接触。

//unnamed package

import javax.microedition.midlet.*;

import javax.microedition.lcdui.*;

public class CameraMIDletextendsMIDlet{

private CameraCanvascameraCanvas=null;

private DisplayCanvasdisplayCanvas=null;

public CameraMIDlet()

{

}

public void startApp()

{

Displayablecurrent=Display.getDisplay(this).getCurrent();

if(current==null)

{

//firstcallcameraCanvas=newCameraCanvas(this);

displayCanvas=newDisplayCanvas(this);

Display.getDisplay(this).setCurrent(cameraCanvas);

cameraCanvas.start();

}

else{

//returningfrompauseAppif(current==cameraCanvas)

{

cameraCanvas.start();

}

Display.getDisplay(this).setCurrent(current);

}

}

public void pauseApp()

{

if (Display.getDisplay(this).getCurrent()==cameraCanvas)

{

cameraCanvas.stop();

}

}

public void destroyApp(booleanunconditional)

{

if(Display.getDisplay(this).getCurrent()==cameraCanvas)

{

cameraCanvas.stop();

}

}

private void exitRequested()

{

destroyApp(false);

notifyDestroyed();

}

void cameraCanvasExit()

{

exitRequested();

}

void cameraCanvasCaptured(byte[]pngData)

{

cameraCanvas.stop();

displayCanvas.setImage(pngData);

Display.getDisplay(this).setCurrent(displayCanvas);

}

void displayCanvasBack()

{

Display.getDisplay(this).setCurrent(cameraCanvas);

cameraCanvas.start();

}

}

CameraCanvas类

CameraCanvas类创建一个video player对象和一个video control,同时规定了video contro在canvas的显示方式。需要注意的是CameraCanvas对象的paint方法不能重画图像,这个方法只能重画背景和重顶端拖曳的video control,为了阐明screen已经被显示,CameraCanvas使用黄色背景,而DisplayCanvas采用青色背景。

TakeSnapshot方法获取一个快照,并将其转化为图像数据一个PNG格式的字节数组传回到MIDlet,MIDlet再将其传回到DisplayCanvas来显示。

//unnamed package

import javax.microedition.lcdui.*;

import javax.microedition.media.*;

import javax.microedition.media.control.*;

import java.io.IOException;

class CameraCanvas

extends Canvas

implements CommandListener

{

private final CameraMIDlet midlet;

private final Commandexit Command;

private Command captureCommand=null;

private Player player=null;

private VideoControl videoControl=null;

private bool eanactive=false;

//Two strings for displaying error messages

private String message1=null;

private String message2=null;

CameraCanvas(CameraMID letmidlet)

{

this.midlet=midlet;

exitCommand=newCommand("Exit",Command.EXIT,1);

addCommand(exitCommand);

setCommandListener(this);

try{

player=Manager.createPlayer("capture://video");

player.realize();

//Grab the video control and set it to the current display.

videoControl=(VideoControl)(player.getControl("VideoControl"));

if(videoControl==null)

{

discardPlayer();

message1="Unsupported:";

message2="Can'tgetvideocontrol";

}

else{

videoControl.initDisplayMode(VideoControl.USE_DIRECT_VIDEO,this);

//center video , letting it be clippedifit'stoobig

int canvasWidth=getWidth();

int canvasHeight=getHeight();

int displayWidth=videoControl.getDisplayWidth();

int displayHeight=videoControl.getDisplayHeight();

int x=(canvasWidth-displayWidth)/2;

inty=(canvasHeight-displayHeight)/2;

videoControl.setDisplayLocation(x,y);

captureCommand=newCommand("Capture",Command.SCREEN,1);

addCommand(captureCommand);

}

}

catch(IOExceptionioe)

{

discardPlayer();

message1="IOException:";

message2=ioe.getMessage();

}

catch(MediaExceptionme)

{

discardPlayer();

message1="MediaException:";

message2=me.getMessage();

}

catch(SecurityExceptionse)

{

discardPlayer();

message1="SecurityException";

message2=se.getMessage();

}

}

//Called in case of exception to make sure in valid players are closed

private void discardPlayer()

{

if(player!=null)

{

player.close();

player=null;

}

videoControl=null;

}

publicvoidpaint(Graphicsg)

{

g.setColor(0x00FFFF00);//yellowg.fillRect(0,0,getWidth(),getHeight());

if(message1!=null)

{

g.setColor(0x00000000);//black

g.drawString(message1,1,1,Graphics.TOP|Graphics.LEFT);

g.drawString(message2,1,1+g.getFont().getHeight(),

Graphics.TOP|Graphics.LEFT);

}

}

synchronizedvoidstart()

{

if((player!=null)&&!active)

{

try{

player.start();

videoControl.setVisible(true);

}

catch(MediaExceptionme)

{

message1="Mediaexception:";

message2=me.getMessage();

}

catch(SecurityExceptionse)

{

message1="SecurityException";

message2=se.getMessage();

}

active=true;

}

}

synchronizedvoidstop()

{

if((player!=null)&&active)

{

try{

videoControl.setVisible(false);

player.stop();

}

catch(MediaExceptionme)

{

message1="MediaException:";

message2=me.getMessage();

}

active=false;

}

}

public void commandAction(Commandc,Displayabled)

{

if(c==exitCommand)

{

midlet.cameraCanvasExit();

}

elseif(c==captureCommand)

{

takeSnapshot();

}

}

public void keyPressed(intkeyCode)

{

if(getGameAction(keyCode)==FIRE)

{

takeSnapshot();

}

}

private void takeSnapshot()

{

if(player!=null)

{

try{

byte[]pngImage=videoControl.getSnapshot(null);

midlet.cameraCanvasCaptured(pngImage);

}

catch(MediaExceptionme)

{

message1="MediaException:";

message2=me.getMessage();

}

}

}

}

DisplayCanvas类

DisplayCanvas类的作为就是将接受自MIDlet的字节数组转变成图像并显示在屏幕上。

//unnamed package

import javax.microedition.lcdui.*;

class DisplayCanvas

extends Canvas

implements CommandListener{

private final CameraMIDletmidlet;

private Image image=null;

DisplayCanvas(CameraMIDlet midlet)

{

this.midlet=midlet;

addCommand(newCommand("Back",Command.BACK,1));

setCommandListener(this);

}

public void paint(Graphicsg)

{

g.setColor(0x0000FFFF);//cyan

g.fillRect(0,0,getWidth(),getHeight());

if(image!=null)

{

g.drawImage(image,

getWidth()/2,

getHeight()/2,

Graphics.VCENTER|Graphics.HCENTER);

}

}

void setImage(byte[]pngImage)

{

image=Image.createImage(pngImage,0,pngImage.length);

}

public void commandAction(Commandc,Displayabled)

{

midlet.displayCanvasBack();

}

}

应用程序描述符(camera.jad)

Camera MIDlet的应用程序描述符仅仅是简单的将MIDlet描述加入到托管域中。

MIDlet-Description:CameraMIDlet

0MIDlet-Jar-Size:4186

MIDlet-Jar-URL:camera.jar

MIDlet-Name:Camera

MIDlet-Vendor: Forum Nokia

MIDlet-Version:0.4

Manifest

Manifest包括了加入描述的托管域和一个icon()函数:

MIDlet-Name:Camera

MIDlet-Version:0.4

MIDlet-Vendor:Forum Nokia

MIDlet-Description:Camera

MIDletMIDlet-Icon:/camera.png

MicroEdition-Profile:MIDP-1.0

MicroEdition-Configuration:CLDC-1.0

MIDlet-1:Camera,/camera.png,CameraMIDlet

使用VideoControl表单

CameraCanvas类常用来显示采集到的图像,他所起的作用与常见的表单大致相同,一旦执行它就将取代CameraCanvas(对CameraMIDlet作了很少的微不足道的修改),代码片断如下:

CameraForm类

//unnamed package

import javax.microedition.lcdui.*;

import javax.microedition.media.*;

import javax.microedition.media.control.*;

import java.io.IOException;

class CameraForm

extends Form

implements CommandListener{

private final FormCameraMIDlet midlet;

private final Command exitCommand;

private Command captureCommand=null;

private Player player;

private VideoControl videoControl;

private Boolean active=false;

private StringItem messageItem;

CameraForm(FormCameraMIDlet midlet)

{

super("Camera");

this.midlet=midlet;

messageItem=newStringItem("Message","start");

append(messageItem);

exitCommand=newCommand("Exit",Command.EXIT,1);

addCommand(exitCommand);

setCommandListener(this);

//initialize camera

try{

player=Manager.createPlayer("capture://video");

player.realize();

//Grab the video control and set it to the current display.

videoControl=(VideoControl)(player.getControl("VideoControl"));

if(videoControl!=null)

{

append((Item)(videoControl.initDisplayMode(

VideoControl.USE_GUI_PRIMITIVE,null)));

captureCommand=newCommand("Capture",Command.SCREEN,1);

addCommand(captureCommand);

messageItem.setText("OK");

}

else{

messageItem.setText("Novideocontrol");

}

}

catch(IOExceptionioe)

{

messageItem.setText("IOException:"+ioe.getMessage());

}

catch(MediaExceptionme)

{

messageItem.setText("MediaException"+me.getMessage());

}

catch(SecurityExceptionse)

{

messageItem.setText("Securityexception:"+se.getMessage());

}

}

synchronizedvoidstart()

{

if(!active)

{

try{

if(player!=null)

{

player.start();

}

if(videoControl!=null)

{

videoControl.setVisible(true);

}

}

catch(MediaExceptionme)

{

messageItem.setText("Mediaexception:"+me.getMessage());

}

catch(SecurityExceptionse)

{

messageItem.setText("Securityexception:"+se.getMessage());

}

active=true;

}

}

synchronizedvoidstop()

{

if(active)

{

try{

if(videoControl!=null)

{

videoControl.setVisible(false);

}

if(player!=null)

{

player.stop();

}

}

catch(MediaExceptionme)

{

messageItem.setText("Mediaexception:"+me.getMessage());

}

active=false;

}

}

public void commandAction(Commandc,Displayabled)

{

if(c==exitCommand)

{

midlet.cameraFormExit();

}

elseif(c==captureCommand)

{

//if we have a capture command,we know videoControlisnotnulltry{

byte[]pngImage=videoControl.getSnapshot(null);

midlet.cameraFormCaptured(pngImage);

messageItem.setText("OK");

}

catch(MediaExceptionme)

{

messageItem.setText("Mediaexception:"+me.getMessage());

}

}

}

}

结束语

本文提供的MIDlet仅仅是一个实例,在实践中可以扩展这个实例。首先在实践中可以将图像存储起来,然后在其他屏幕浏览这些图像,这是一个非常有意思的做法。另外还可以将图像以HTTP方式传送到WEB服务器上,然后可以将这些图像动态的加入用户的WEB日志中,MIDlet也允许用户将带文本的图像传送到WEB站点。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有