/* * Copyright © 2013 Nokia Corporation. All rights reserved. Nokia and Nokia * Connecting People are registered trademarks of Nokia Corporation. Oracle and * Java are trademarks or registered trademarks of Oracle and/or its affiliates. * Other product and company names mentioned herein may be trademarks or trade * names of their respective owners. See LICENSE.TXT for license information. */ package com.nokia.example; import com.nokia.mid.ui.VirtualKeyboard; import com.nokia.mid.ui.gestures.GestureEvent; import com.nokia.mid.ui.gestures.GestureInteractiveZone; import com.nokia.mid.ui.gestures.GestureListener; import com.nokia.mid.ui.gestures.GestureRegistrationManager; import com.nokia.mid.ui.orientation.Orientation; import com.nokia.mid.ui.orientation.OrientationListener; import java.io.IOException; import java.io.InputStream; import javax.microedition.io.Connector; import javax.microedition.io.file.FileConnection; import javax.microedition.lcdui.*; /** * This class displays a selected image centered in the screen. This class * implements a GestureListener which notifies the MIDlet of gesture events * associated with the UI element. This class also implements * OrientationListener to detect a change in the orientation of the device's * display */ class ImageCanvas extends Canvas implements CommandListener, OrientationListener, GestureListener { private final ImageViewerMIDlet midlet; private Image currentImage = null; int imageWidth; int imageHeight; private Command backCommand = new Command("Back", Command.BACK, 0); private Ticker ticker = new Ticker("Image Viewer"); private int mouseDownX; private int mouseDownY; private int deltaX; private int deltaY; private int posX; private int posY; int rgbImageData[]; int srcWidth; int srcHeight; float scaleIndex = 1; ImageCanvas(ImageViewerMIDlet midlet) { /** * VirtualKeyboard is supported from Java Runtime 2.0.0 for Series 40 * onwards. To determine whether a Series 40 device is a Full Touch * device and hide the open keypad command from the Options menu if it * is. */ if (System.getProperty("com.nokia.keyboard.type").equals("None")) { VirtualKeyboard.hideOpenKeypadCommand(true); } setTitle("Image Viewer"); this.midlet = midlet; this.addCommand(backCommand); this.setCommandListener(this); this.setTicker(ticker); /** * Orientation is supported for Java Runtime 2.0.0 for Series 40 * onwards. Registers the orientation listener. Applications that need * information about events related to display orientation changes need * to register with Orientation to get notifications of the events. */ Orientation.addOrientationListener(this); initializeGesture(); } public boolean displayImage(String imgName) { try { FileConnection fileConn = (FileConnection) Connector.open(imgName, Connector.READ); if(rgbImageData!=null)rgbImageData = null; InputStream fis = fileConn.openInputStream(); int overallSize = (int) fileConn.fileSize(); byte[] imageData = new byte[overallSize]; fis.read(imageData, 0, overallSize); fis.close(); fileConn.close(); //fis = null; //fileConn = null; ticker.setString("Image Viewer:" + imgName); currentImage = Image.createImage(imageData, 0, overallSize); imageData = null; srcWidth = imageWidth = currentImage.getWidth(); srcHeight = imageHeight = currentImage.getHeight(); scaleIndex = 1; repaint(); } catch (IOException e) { midlet.showError(e); return false; } catch (Exception e) { e.printStackTrace(); midlet.showError(e); return false; } catch (Error e) { e.printStackTrace(); if (e instanceof OutOfMemoryError) { midlet.showError("File is too large to display"); } else { midlet.showError("Failed to display this file. " + e.getMessage()); } return false; } return true; } protected void paint(Graphics g) { int w = getWidth(); int h = getHeight(); // Set background color to black g.setColor(0); g.fillRect(0, 0, w, h); setImagePlacementPoint(); System.out.println("Pos X:" + posX + " Y:" + posY); if (currentImage != null) { g.drawImage(currentImage, posX, posY, Graphics.HCENTER | Graphics.VCENTER); } else { // If no image is available display a message g.setColor(0x00FFFFFF); g.drawString("No image", posX, posY, Graphics.HCENTER | Graphics.BASELINE); } } protected void keyReleased(int keyCode) { // Exit with any key midlet.displayFileBrowser(); } public void commandAction(Command command, Displayable displayable) { if (command == backCommand) { currentImage = null; rgbImageData = null; midlet.displayFileBrowser(); } } protected void pointerPressed(int x, int y) { mouseDownX = x; mouseDownY = y; } protected void pointerReleased(int x, int y) { deltaX = 0; deltaY = 0; } protected void pointerDragged(int x, int y) { deltaX = x - mouseDownX; deltaY = y - mouseDownY; mouseDownX = x; mouseDownY = y; repaint(); } void setImagePlacementPoint() { // This needs to be taken each time, since the values will be chaged when // user tilt the phone to potrait mode to landscape mode. int canvasWidth = getWidth(); int canvasHeight = getHeight(); if (imageWidth > canvasWidth && deltaX != 0) { posX += deltaX; if (posX < (canvasWidth - imageWidth / 2)) { posX = canvasWidth - imageWidth / 2; } else if (posX > (imageWidth / 2)) { posX = (imageWidth / 2); } } else { posX = canvasWidth / 2; } if (imageHeight > canvasHeight && deltaY != 0) { posY += deltaY; if (posY < (canvasHeight - imageHeight / 2)) { posY = canvasHeight - imageHeight / 2; } else if (posY > (imageHeight / 2)) { posY = (imageHeight / 2); } } else { posY = canvasHeight / 2; } } /** * Orientation is supported for Java Runtime 2.0.0 for Series 40 onwards. * Called when display's orientation has changed. */ public void displayOrientationChanged(int newDisplayOrientation) { /** * Change MIDlet UI orientation */ Orientation.setAppOrientation(newDisplayOrientation); } /** * Initializes gestures and set it to receive gesture events */ public void initializeGesture() { /** * Set the listener to register events for ImageCanvas (this,) and * register the GestureListener for the UI element (,this) */ GestureRegistrationManager.setListener(this, this); /** * Create an interactive zone and set it to receive taps */ GestureInteractiveZone myGestureZone = new GestureInteractiveZone(GestureInteractiveZone.GESTURE_PINCH); /** * Set the interactive zone to also receive other events */ //myGestureZone.setGestures(GestureInteractiveZone.GESTURE_ALL); /** * Set the location (relative to the container) and size of the * interactive zone: */ myGestureZone.setRectangle(0, 0, getWidth(), getHeight()); /** * Register the interactive zone for GestureCanvas (this) */ GestureRegistrationManager.register(this, myGestureZone); } /** * Scales the current image */ private void scaleImage(float scale) { try { scaleIndex += scale; if(rgbImageData==null){ rgbImageData = new int[srcWidth * srcHeight]; currentImage.getRGB(rgbImageData, 0, imageWidth, 0, 0, imageWidth, imageHeight); } if (scaleIndex < 0.1f) { scaleIndex = 0.1f; } int newImageWidth = (int) (srcWidth * scaleIndex); int newImageHeight = (int) (srcHeight * scaleIndex); int rgbImageScaledData[] = new int[newImageWidth * newImageHeight]; // calculations and bit shift operations to optimize the for loop int tempScaleRatioWidth = ((srcWidth << 16) / newImageWidth); int tempScaleRatioHeight = ((srcHeight << 16) / newImageHeight); int i = 0; for (int y = 0; y < newImageHeight; y++) { for (int x = 0; x < newImageWidth; x++) { rgbImageScaledData[i++] = rgbImageData[(srcWidth * ((y * tempScaleRatioHeight) >> 16)) + ((x * tempScaleRatioWidth) >> 16)]; } } //Create an RGB image from rgbImageScaledData array currentImage = Image.createRGBImage(rgbImageScaledData, newImageWidth, newImageHeight, true); imageWidth = newImageWidth; imageHeight = newImageHeight; } catch (OutOfMemoryError e) { // TODO Auto-generated catch block scaleIndex -= scale; e.printStackTrace(); midlet.showError("Out of memory "+e.getMessage()); } } /** * Defines the gestureAction method for the class. This method is called * every time a gesture event occurs for a UI element that uses * GestureListener. The method is called with all the information related to * the gesture event. */ public void gestureAction(Object arg0, GestureInteractiveZone arg1, GestureEvent gestureEvent) { switch (gestureEvent.getType()) { /** * This gesture event is supported from Java Runtime 2.0.0 for * Series 40 onwards. Receives pinch events and check the pinch * distance change to scale the current image. */ case GestureInteractiveZone.GESTURE_PINCH: if (gestureEvent.getPinchDistanceChange() < 0) { scaleImage(-0.1f); } else if (gestureEvent.getPinchDistanceChange() > 0) { scaleImage(0.1f); } repaint(); break; default: break; } } }