用MMAPI拍照

作者:JonathanKnudsen
时间:July2003
原文出处: http://developers.sun.com/techtopics/mobility/midp/articles/picture/
源码下载:
http://developers.sun.com/techtopics/mobility/midp/articles/picture/src/Snapper.zip
译者注:因为该文成文时间很早,而J2ME技术发展很快,文中提到的 开发工具和运行测试环境现在都有较大变动,请读者注意。

译文

概述
MobileMediaAPI(MMAPI)让MIDlet能够播放和录制音频和视频数据.但是设备的真实能力还是依赖于其具体实现。目前,支持MMAPI的唯一设备是Nokia3650.本文描述了如何利用MMAPI来构建一个简单的拍照程序。

开发MMAPI应用程序所用工具

构建MMAPI应用程序的第一个难题是找到正确的 开发工具.J2MEWirelessToolkit2.0 支持MIDP2.0,MMAPI1.0,WMA1.1.乍一看,它包括了你所要的一切.但是Nokia3650只能运行MIDP1.0,不能运行 MIDP2.0.为了开发MIDP1.0的应用程序,你需要J2MEWirelessToolkit的1.0.4版,外带一个支持MMAPI的模拟 器。
Sun提供这样一个模拟器,你可以在MMAPI的主页上找到( http://java.sun.com/products/mmapi/index.jsp).尽管你可以利用该模拟器构建MMAPI应用程序,但是它不支持拍照,因此你不能用它来测试拍照的应用程序。
Nokia有一个支持拍照的模拟器,它是NokiaSeries60MIDPConceptSDKBeta0.2的一个组成部分.你可以在Nokia的开发者论坛( http://www.forum.nokia.com)上找到.文件的名字是nS60_jme_concept_sdk_b0_2_014.zip,Linux开发者应该是用2.0版的NokiaDeveloper'sSuiteforJ2ME( http://www.forum.nokia.com/nds_for_j2me.html),下面的安装指南只适用于windows环境。
首先,在<J2MEWirelessToolkit>\wtklib\devices目录下安装NokiaSDK(把 Nokia_Series_60_MIDP_Concept_SDK_Beta_0_2的安装目录拷贝到这个目录亦可).接下来,运行 J2MEWirelessToolkit,你就有一个额外的模拟器-- Nokia_Series_60_MIDP_Concept_SDK_Beta_0_2可用了。选择该模拟器后,你就可以构建和测试你的MMAPI应用程 序了。该模拟器和真实的Nokia3650看起来非常相似。

MMAPI的测试设备

没有什么能替代真机测试。从长远观点来看,将会有很多设备支持MMAPI,但是 Nokia3650是目前唯一支持MMAPI的设备.有好几种方式可以在Nokia3650真机上发布MIDlet.我使用红外接口在我的笔记本和手 机上传输文件。你也可以使用蓝牙和OTA.

获取照相机

MIDlet中拍照(正式的说法叫视频捕捉)的第一步是从Manager获取一个Player。一个特殊的定位符:capture://video,指示照相机使用缺省的图片大小来拍照。
mPlayer=Manager.createPlayer("capture://video");
如果设备不支持视频捕捉,这将会抛出一个MediaException。你可以预先检查一下设备是否支持拍照,如果系统属性supports.video.capture的值为真,那么该设备就支持照相功能。
为了获取拍照所需资源,Player需要被realize.如果你没有学过或者忘记了realized是什么意思,请参考<MobileMediaAPIOveriew>( http://developers.sun.com/techtopics/mobility/apis/articles/mmapi_overview/)或者J2MEMobileMediaAPI.

mPlayer.realize();


显示相机视频

来源于照相机的视频可以作为一个Item添加到Form上,也可以作为Canvas的一部分。一个VideoControl可以让你实现这个功能,你可以采用如下语句获取VideoControl.

mVideoControl=(VideoControl)
mPlayer.getControl("VideoControl");

如果你希望在Canvas里面显示来源于相机的视频,初始化VideoControl,然后在Canvas里面设置视频的大小和位置,最后使视频可见。下 面的例子(一个Canvas字类的构造函数)显示了如何把视频摆放在离Canvas上下边框2个像素宽的位置。如果不能这样放置,构造函数试着使用整个屏 幕,最后,它调用setVisible()使视频可见.
publicCameraCanvas(SnapperMIDletmidlet,
VideoControlvideoControl){
intwidth=getWidth();
intheight=getHeight();

mSnapperMIDlet=midlet;

videoControl.initDisplayMode(
VideoControl.USE_DIRECT_VIDEO,this);

try{
videoControl.setDisplayLocation(2,2);
videoControl.setDisplaySize(width-4,height-4);
}
catch(MediaExceptionme){
try{videoControl.setDisplayFullScreen(true);}
catch(MediaExceptionme2){}
}
videoControl.setVisible(true);
}

在Form里面显示视频稍微有所不同.我们不再用USE_DIRECT_VIDEO参数调用VideoControl的initDisplayMode(),而是代之以USE_GUI_PRIMITIVE参数。在MIDP设备上,你可以获得一个Item显示在Form上

Formform=newForm("Cameraform");
Itemitem=(Item)mVideoControl.initDisplayMode(
GUIControl.USE_GUI_PRIMITIVE,null);
form.append(item);

拍照

一旦相机视频显示在设备上,拍照就很容易了.你所需要的只是调用一下VideoControl的getSnapshot ()方法。为了调用该方法,你需要传递一个图片类型参数,如果你使用null作参数,那么相机就会适用缺省的图片类型?PNG.通过获取用空格隔开的系统 属性video.snapshot.encodings的值,你可以预先获取相机支持的图片类型。

ThegetSnapshot ()方法返回一个字节数组,里面是按你所指定的图片格式的图片数据。接下来,你就可以随意行事了,你可以把这个字节数组存储在数据库里,也可以把它发到服 务器上去,或者依据这个字节数组构造一个Image对象,这样你就可以把刚才所拍照片显示在用户面前,如下例所示:
byte[]raw=mVideoControl.getSnapshot(null);
Imageimage=Image.createImage(raw,0,raw.length);

创建微缩图

在这篇文章中,我想要谈谈如何创建微缩图片,也就是使所拍的相片缩小化。这事看起来简单,其实却并不轻松。 MIDP2.0中包含一些方法,这些方法可以从Image对象中获取原始的像素数据,有可能实现图像的伸缩变换。不幸的是,MIDP1.0并不提供对像素 数据的直接访问。
从图像处理角度来看,我这里采用的解决办法既不优雅,也不严格正确。但是这种办法接近我所需要的效果,并且不涉及到手工解析 PNG格式。我创建了一个新的空白的图片作为微缩图,对于图片的每个像素,我设置一个围绕该像素的极小的剪切区。然后把原始图片绘制在一个适当的位置上, 这样就设置了微缩图的每一个像素.

privateImagecreateThumbnail(Imageimage){
intsourceWidth=image.getWidth();
intsourceHeight=image.getHeight();

intthumbWidth=64;
intthumbHeight=-1;

if(thumbHeight==-1)
thumbHeight=thumbWidth*sourceHeight/sourceWidth;

Imagethumb=Image.createImage(thumbWidth,thumbHeight);
Graphicsg=thumb.getGraphics();

for(inty=0;y<thumbHeight;y++){
for(intx=0;x<thumbWidth;x++){
g.setClip(x,y,1,1);
intdx=x*sourceWidth/thumbWidth;
intdy=y*sourceHeight/thumbHeight;
g.drawImage(image,x-dx,y-dy,
Graphics.LEFT|Graphics.TOP);
}
}

ImageimmutableThumb=Image.createImage(thumb);

returnimmutableThumb;
}

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例子实现了拍照功能和微缩图功能。你只要稍作加工,该例子就可以成为一个网络相片共享程序的基础.
关于作者

JonathanKnudsen出了好几本书,包括《WirelessJava (secondedition)》,《TheUnofficialGuidetoLEGOMINDSTORMSRobots》, 《LearningJava(secondedition)》,《Java2DGraphics》。Jonathan在Java和 Legorobots方面广泛写作,他还为JavaWorld,EXE,NZZFolio, andtheO'ReillyNetwork写文章.Jonathan在普林斯顿大学获得了机械工程学位.

关于译者

陈万飞,网名Jagie,培训师,爱好java技术.可通过 chen_cwf@163.com与他联系
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值