用MMAPI拍照

原文信息

作者: Jonathan Knudsen
时间: July 2003
原文出处:  http://developers.sun.com/techtopics/mobility/midp/articles/picture/
源码下载:
http://developers.sun.com/techtopics/mobility/midp/articles/picture/src/Snapper.zip
译者注:因为该文成文时间很早,而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模拟器上运行该程序,你会收到一个优雅的反馈信息:
 
在不支持视频捕捉的设备上运行Snapper
如果你使用Nokia的Concept模拟器,你将看到如下效果:
 
Snapper的主屏
选择Camera命令(Nokia机型把该命令放在Options菜单里),在一台真机上,你可以看到来源于摄像头的视频,模拟器只能显示单幅的静态图像。但是在这2种情况下,CameraCanvas都会在视频周围画上一个绿框。

Snapper的摄像机屏幕
要拍照的话,你只需选择Capture命令或者按开火键(位于方向键中心),Snapper将创建一个微缩图片并显示在MIDlet的主屏上。
 
放置了微缩图的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在普林斯顿大学获得了机械工程学位.

关于译者


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值