カメラを起動して写真を撮影し、GPS情報を取得するS!アプリ
メール宛に質問が来て、その回答に作ったプログラムを公開します。表題通り、カメラを起動して写真を撮影し、GPS情報を取得しています。実機で動かしたところ、GPS情報の更新(DeviceControl#updateLocationInfo)に処理がブロックされないようなので、適宜その後2秒程度スリープするか、撮影前に更新処理をキックするのがいいと思います。
あと、応用が効くように写真データの読み込み、先頭256BのHexデータのダンプも行います。EXIFを操作する機能をつけてやればGoogle MAPとかとマッシュアップ(もう死語?)できそうです。だれかJ2MEのEXIFライブラリとか知りませんか?前に作ろうとしましたが作りきらなかったです。今調べてたらこことかここのAlbumMakerとか参考になるかもしれませんね。ソースも含まれているみたいですし。
とりあえず本日は以上で。
ソースファイル(CameraSample.java)
/* * To change this template, choose Tools | Templates * and open the template in the editor. */ import com.j_phone.io.CameraConnection; import com.j_phone.system.DeviceControl; import java.io.ByteArrayOutputStream; import java.io.InputStream; import javax.microedition.io.Connector; import javax.microedition.io.InputConnection; import javax.microedition.midlet.*; import javax.microedition.lcdui.*; import org.netbeans.microedition.lcdui.WaitScreen; import org.netbeans.microedition.util.SimpleCancellableTask; /** * @author g026817 */ public class CameraSampleMIDlet extends MIDlet implements CommandListener, ItemCommandListener { private boolean midletPaused = false; //<editor-fold defaultstate="collapsed" desc=" Generated Fields ">//GEN-BEGIN:|fields|0| private Form mainForm; private StringItem button; private StringItem filename; private StringItem filesize; private StringItem hexdata; private StringItem longitude; private StringItem latitude; private WaitScreen cameraWaitScreen; private Form errorForm; private StringItem errorMessage; private Command itemCommand; private SimpleCancellableTask cameraTask; //</editor-fold>//GEN-END:|fields|0| /** * The CameraSampleMIDlet constructor. */ public CameraSampleMIDlet() { } //<editor-fold defaultstate="collapsed" desc=" Generated Methods ">//GEN-BEGIN:|methods|0| //</editor-fold>//GEN-END:|methods|0| //<editor-fold defaultstate="collapsed" desc=" Generated Method: initialize ">//GEN-BEGIN:|0-initialize|0|0-preInitialize /** * Initilizes the application. * It is called only once when the MIDlet is started. The method is called before the <code>startMIDlet</code> method. */ private void initialize() {//GEN-END:|0-initialize|0|0-preInitialize // write pre-initialize user code here //GEN-LINE:|0-initialize|1|0-postInitialize // write post-initialize user code here }//GEN-BEGIN:|0-initialize|2| //</editor-fold>//GEN-END:|0-initialize|2| //<editor-fold defaultstate="collapsed" desc=" Generated Method: startMIDlet ">//GEN-BEGIN:|3-startMIDlet|0|3-preAction /** * Performs an action assigned to the Mobile Device - MIDlet Started point. */ public void startMIDlet() {//GEN-END:|3-startMIDlet|0|3-preAction // write pre-action user code here switchDisplayable(null, getMainForm());//GEN-LINE:|3-startMIDlet|1|3-postAction // write post-action user code here }//GEN-BEGIN:|3-startMIDlet|2| //</editor-fold>//GEN-END:|3-startMIDlet|2| //<editor-fold defaultstate="collapsed" desc=" Generated Method: resumeMIDlet ">//GEN-BEGIN:|4-resumeMIDlet|0|4-preAction /** * Performs an action assigned to the Mobile Device - MIDlet Resumed point. */ public void resumeMIDlet() {//GEN-END:|4-resumeMIDlet|0|4-preAction // write pre-action user code here //GEN-LINE:|4-resumeMIDlet|1|4-postAction // write post-action user code here }//GEN-BEGIN:|4-resumeMIDlet|2| //</editor-fold>//GEN-END:|4-resumeMIDlet|2| //<editor-fold defaultstate="collapsed" desc=" Generated Method: switchDisplayable ">//GEN-BEGIN:|5-switchDisplayable|0|5-preSwitch /** * Switches a current displayable in a display. The <code>display</code> instance is taken from <code>getDisplay</code> method. This method is used by all actions in the design for switching displayable. * @param alert the Alert which is temporarily set to the display; if <code>null</code>, then <code>nextDisplayable</code> is set immediately * @param nextDisplayable the Displayable to be set */ public void switchDisplayable(Alert alert, Displayable nextDisplayable) {//GEN-END:|5-switchDisplayable|0|5-preSwitch // write pre-switch user code here Display display = getDisplay();//GEN-BEGIN:|5-switchDisplayable|1|5-postSwitch if (alert == null) { display.setCurrent(nextDisplayable); } else { display.setCurrent(alert, nextDisplayable); }//GEN-END:|5-switchDisplayable|1|5-postSwitch // write post-switch user code here }//GEN-BEGIN:|5-switchDisplayable|2| //</editor-fold>//GEN-END:|5-switchDisplayable|2| //<editor-fold defaultstate="collapsed" desc=" Generated Method: commandAction for Displayables ">//GEN-BEGIN:|7-commandAction|0|7-preCommandAction /** * Called by a system to indicated that a command has been invoked on a particular displayable. * @param command the Command that was invoked * @param displayable the Displayable where the command was invoked */ public void commandAction(Command command, Displayable displayable) {//GEN-END:|7-commandAction|0|7-preCommandAction // write pre-action user code here if (displayable == cameraWaitScreen) {//GEN-BEGIN:|7-commandAction|1|19-preAction if (command == WaitScreen.FAILURE_COMMAND) {//GEN-END:|7-commandAction|1|19-preAction // write pre-action user code here switchDisplayable(null, getErrorForm());//GEN-LINE:|7-commandAction|2|19-postAction // write post-action user code here } else if (command == WaitScreen.SUCCESS_COMMAND) {//GEN-LINE:|7-commandAction|3|18-preAction // write pre-action user code here switchDisplayable(null, getMainForm());//GEN-LINE:|7-commandAction|4|18-postAction // write post-action user code here }//GEN-BEGIN:|7-commandAction|5|7-postCommandAction }//GEN-END:|7-commandAction|5|7-postCommandAction // write post-action user code here }//GEN-BEGIN:|7-commandAction|6| //</editor-fold>//GEN-END:|7-commandAction|6| //<editor-fold defaultstate="collapsed" desc=" Generated Getter: mainForm ">//GEN-BEGIN:|14-getter|0|14-preInit /** * Returns an initiliazed instance of mainForm component. * @return the initialized component instance */ public Form getMainForm() { if (mainForm == null) {//GEN-END:|14-getter|0|14-preInit // write pre-init user code here mainForm = new Form("title", new Item[] { getButton(), getFilename(), getFilesize(), getLongitude(), getLatitude(), getHexdata() });//GEN-LINE:|14-getter|1|14-postInit // write post-init user code here }//GEN-BEGIN:|14-getter|2| return mainForm; } //</editor-fold>//GEN-END:|14-getter|2| //<editor-fold defaultstate="collapsed" desc=" Generated Getter: cameraWaitScreen ">//GEN-BEGIN:|15-getter|0|15-preInit /** * Returns an initiliazed instance of cameraWaitScreen component. * @return the initialized component instance */ public WaitScreen getCameraWaitScreen() { if (cameraWaitScreen == null) {//GEN-END:|15-getter|0|15-preInit // write pre-init user code here cameraWaitScreen = new WaitScreen(getDisplay());//GEN-BEGIN:|15-getter|1|15-postInit cameraWaitScreen.setTitle("title"); cameraWaitScreen.setCommandListener(this); cameraWaitScreen.setText("\u3044\u308D\u3044\u308D\u51E6\u7406\u4E2D"); cameraWaitScreen.setTask(getCameraTask());//GEN-END:|15-getter|1|15-postInit // write post-init user code here }//GEN-BEGIN:|15-getter|2| return cameraWaitScreen; } //</editor-fold>//GEN-END:|15-getter|2| //</editor-fold> //<editor-fold defaultstate="collapsed" desc=" Generated Getter: cameraTask ">//GEN-BEGIN:|20-getter|0|20-preInit /** * Returns an initiliazed instance of cameraTask component. * @return the initialized component instance */ public SimpleCancellableTask getCameraTask() { if (cameraTask == null) {//GEN-END:|20-getter|0|20-preInit // write pre-init user code here cameraTask = new SimpleCancellableTask();//GEN-BEGIN:|20-getter|1|20-execute cameraTask.setExecutable(new org.netbeans.microedition.util.Executable() { public void execute() throws Exception {//GEN-END:|20-getter|1|20-execute // write task-execution user code here CameraConnection cc = (CameraConnection)Connector.open("camera:"); cc.capture(); getFilename().setText(cc.getFileName()); cc.close(); InputConnection ic = (InputConnection)Connector.open("file://" + getFilename().getText()); InputStream is = ic.openInputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buff=new byte[1024]; int size; while ((size=is.read(buff))!=-1) { baos.write(buff,0,size); } baos.flush(); baos.close(); is.close(); ic.close(); byte[] data = baos.toByteArray(); getFilesize().setText(data.length+" Bytes"); StringBuffer sb = new StringBuffer(); char[] hex = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F',}; for (int i=0;i<256;i++){ int n = 0xFF & data[i]; //System.out.println(n/16+" "+n%16); sb.append(hex[n/16]); sb.append(hex[n%16]); sb.append(" "); if(i%8==7){sb.append("\n");} } getHexdata().setText(sb.toString()); DeviceControl dc = DeviceControl.getDefaultDeviceControl(); try{ dc.updateLocationInfo(); getLongitude().setText(String.valueOf(dc.getLongitude())); getLatitude().setText(String.valueOf(dc.getLatitude())); }catch(Throwable t){ getLongitude().setText(t.getClass().getName()); getLatitude().setText(t.getMessage()); } }//GEN-BEGIN:|20-getter|2|20-postInit });//GEN-END:|20-getter|2|20-postInit // write post-init user code here }//GEN-BEGIN:|20-getter|3| return cameraTask; } //</editor-fold>//GEN-END:|20-getter|3| //</editor-fold> //<editor-fold defaultstate="collapsed" desc=" Generated Getter: button ">//GEN-BEGIN:|22-getter|0|22-preInit /** * Returns an initiliazed instance of button component. * @return the initialized component instance */ public StringItem getButton() { if (button == null) {//GEN-END:|22-getter|0|22-preInit // write pre-init user code here button = new StringItem(null, "\u30AB\u30E1\u30E9\u306E\u8D77\u52D5", Item.BUTTON);//GEN-BEGIN:|22-getter|1|22-postInit button.addCommand(getItemCommand()); button.setItemCommandListener(this); button.setDefaultCommand(getItemCommand()); button.setLayout(ImageItem.LAYOUT_DEFAULT | ImageItem.LAYOUT_NEWLINE_AFTER | Item.LAYOUT_2);//GEN-END:|22-getter|1|22-postInit // write post-init user code here }//GEN-BEGIN:|22-getter|2| return button; } //</editor-fold>//GEN-END:|22-getter|2| //<editor-fold defaultstate="collapsed" desc=" Generated Method: commandAction for Items ">//GEN-BEGIN:|8-itemCommandAction|0|8-preItemCommandAction /** * Called by a system to indicated that a command has been invoked on a particular item. * @param command the Command that was invoked * @param displayable the Item where the command was invoked */ public void commandAction(Command command, Item item) {//GEN-END:|8-itemCommandAction|0|8-preItemCommandAction // write pre-action user code here if (item == button) {//GEN-BEGIN:|8-itemCommandAction|1|24-preAction if (command == itemCommand) {//GEN-END:|8-itemCommandAction|1|24-preAction // write pre-action user code here switchDisplayable(null, getCameraWaitScreen());//GEN-LINE:|8-itemCommandAction|2|24-postAction // write post-action user code here }//GEN-BEGIN:|8-itemCommandAction|3|8-postItemCommandAction }//GEN-END:|8-itemCommandAction|3|8-postItemCommandAction // write post-action user code here }//GEN-BEGIN:|8-itemCommandAction|4| //</editor-fold>//GEN-END:|8-itemCommandAction|4| //</editor-fold> //<editor-fold defaultstate="collapsed" desc=" Generated Getter: filename ">//GEN-BEGIN:|25-getter|0|25-preInit /** * Returns an initiliazed instance of filename component. * @return the initialized component instance */ public StringItem getFilename() { if (filename == null) {//GEN-END:|25-getter|0|25-preInit // write pre-init user code here filename = new StringItem("\u30D5\u30A1\u30A4\u30EB\u540D", "\n");//GEN-BEGIN:|25-getter|1|25-postInit filename.setLayout(ImageItem.LAYOUT_DEFAULT | ImageItem.LAYOUT_NEWLINE_AFTER | Item.LAYOUT_2);//GEN-END:|25-getter|1|25-postInit // write post-init user code here }//GEN-BEGIN:|25-getter|2| return filename; } //</editor-fold>//GEN-END:|25-getter|2| //<editor-fold defaultstate="collapsed" desc=" Generated Getter: itemCommand ">//GEN-BEGIN:|23-getter|0|23-preInit /** * Returns an initiliazed instance of itemCommand component. * @return the initialized component instance */ public Command getItemCommand() { if (itemCommand == null) {//GEN-END:|23-getter|0|23-preInit // write pre-init user code here itemCommand = new Command("", Command.ITEM, 0);//GEN-LINE:|23-getter|1|23-postInit // write post-init user code here }//GEN-BEGIN:|23-getter|2| return itemCommand; } //</editor-fold>//GEN-END:|23-getter|2| //</editor-fold> //<editor-fold defaultstate="collapsed" desc=" Generated Getter: filesize ">//GEN-BEGIN:|26-getter|0|26-preInit /** * Returns an initiliazed instance of filesize component. * @return the initialized component instance */ public StringItem getFilesize() { if (filesize == null) {//GEN-END:|26-getter|0|26-preInit // write pre-init user code here filesize = new StringItem("\u30D5\u30A1\u30A4\u30EB\u30B5\u30A4\u30BA", "\n");//GEN-BEGIN:|26-getter|1|26-postInit filesize.setLayout(ImageItem.LAYOUT_DEFAULT | ImageItem.LAYOUT_NEWLINE_AFTER | Item.LAYOUT_2);//GEN-END:|26-getter|1|26-postInit // write post-init user code here }//GEN-BEGIN:|26-getter|2| return filesize; } //</editor-fold>//GEN-END:|26-getter|2| //</editor-fold> //<editor-fold defaultstate="collapsed" desc=" Generated Getter: hexdata ">//GEN-BEGIN:|27-getter|0|27-preInit /** * Returns an initiliazed instance of hexdata component. * @return the initialized component instance */ public StringItem getHexdata() { if (hexdata == null) {//GEN-END:|27-getter|0|27-preInit // write pre-init user code here hexdata = new StringItem("Hex\u30C7\u30FC\u30BF\uFF08\u5148\u982D256B\uFF09", "\n");//GEN-LINE:|27-getter|1|27-postInit // write post-init user code here }//GEN-BEGIN:|27-getter|2| return hexdata; } //</editor-fold>//GEN-END:|27-getter|2| //<editor-fold defaultstate="collapsed" desc=" Generated Getter: errorForm ">//GEN-BEGIN:|30-getter|0|30-preInit /** * Returns an initiliazed instance of errorForm component. * @return the initialized component instance */ public Form getErrorForm() { if (errorForm == null) {//GEN-END:|30-getter|0|30-preInit // write pre-init user code here errorForm = new Form("title", new Item[] { getErrorMessage() });//GEN-LINE:|30-getter|1|30-postInit // write post-init user code here }//GEN-BEGIN:|30-getter|2| return errorForm; } //</editor-fold>//GEN-END:|30-getter|2| //</editor-fold> //<editor-fold defaultstate="collapsed" desc=" Generated Getter: errorMessage ">//GEN-BEGIN:|32-getter|0|32-preInit /** * Returns an initiliazed instance of errorMessage component. * @return the initialized component instance */ public StringItem getErrorMessage() { if (errorMessage == null) {//GEN-END:|32-getter|0|32-preInit // write pre-init user code here errorMessage = new StringItem("\u30A8\u30E9\u30FC\u30E1\u30C3\u30BB\u30FC\u30B8", getCameraTask().getFailureMessage());//GEN-LINE:|32-getter|1|32-postInit // write post-init user code here }//GEN-BEGIN:|32-getter|2| return errorMessage; } //</editor-fold>//GEN-END:|32-getter|2| //</editor-fold> //<editor-fold defaultstate="collapsed" desc=" Generated Getter: longitude ">//GEN-BEGIN:|33-getter|0|33-preInit /** * Returns an initiliazed instance of longitude component. * @return the initialized component instance */ public StringItem getLongitude() { if (longitude == null) {//GEN-END:|33-getter|0|33-preInit // write pre-init user code here longitude = new StringItem("\u7D4C\u5EA6", "\n");//GEN-BEGIN:|33-getter|1|33-postInit longitude.setLayout(ImageItem.LAYOUT_DEFAULT | ImageItem.LAYOUT_NEWLINE_AFTER | Item.LAYOUT_2);//GEN-END:|33-getter|1|33-postInit // write post-init user code here }//GEN-BEGIN:|33-getter|2| return longitude; } //</editor-fold>//GEN-END:|33-getter|2| //</editor-fold> //<editor-fold defaultstate="collapsed" desc=" Generated Getter: latitude ">//GEN-BEGIN:|34-getter|0|34-preInit /** * Returns an initiliazed instance of latitude component. * @return the initialized component instance */ public StringItem getLatitude() { if (latitude == null) {//GEN-END:|34-getter|0|34-preInit // write pre-init user code here latitude = new StringItem("\u7DEF\u5EA6", "\n");//GEN-BEGIN:|34-getter|1|34-postInit latitude.setLayout(ImageItem.LAYOUT_DEFAULT | ImageItem.LAYOUT_NEWLINE_AFTER | Item.LAYOUT_2);//GEN-END:|34-getter|1|34-postInit // write post-init user code here }//GEN-BEGIN:|34-getter|2| return latitude; } //</editor-fold>//GEN-END:|34-getter|2| /** * Returns a display instance. * @return the display instance. */ public Display getDisplay () { return Display.getDisplay(this); } /** * Exits MIDlet. */ public void exitMIDlet() { switchDisplayable (null, null); destroyApp(true); notifyDestroyed(); } /** * Called when MIDlet is started. * Checks whether the MIDlet have been already started and initialize/starts or resumes the MIDlet. */ public void startApp() { if (midletPaused) { resumeMIDlet (); } else { initialize (); startMIDlet (); } midletPaused = false; } /** * Called when MIDlet is paused. */ public void pauseApp() { midletPaused = true; } /** * Called to signal the MIDlet to terminate. * @param unconditional if true, then the MIDlet has to be unconditionally terminated and all resources has to be released. */ public void destroyApp(boolean unconditional) { } }
JADファイル(CameraSample.jad)
MIDlet-1: CameraSampleMIDlet, , CameraSampleMIDlet MIDlet-Jar-Size: 43041 MIDlet-Jar-URL: CameraSample.jar MIDlet-Name: CameraSample MIDlet-Permissions: com.j_phone.io.Connector.CameraConnection.capture, com.j_phone.io.Connector.StorageConnection.read, com.j_phone.system.DeviceControl.Location, com.j_phone.system.DeviceControl.updateLocation MIDlet-Vendor: Vendor MIDlet-Version: 1.0 MIDxlet-API: MEXA MicroEdition-Configuration: CLDC-1.1 MicroEdition-Profile: MIDP-2.0