ImageCanvas.java
/**
* Copyright (c) 2012 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];
int readAmount = 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;
System.out.println("up up up !");
}
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;
}
}
}