To implement the ImageCanvas
class:
Create the ImageCanvas.java class file.
Import the required packages and classes.
package com.nokia.example.imagescaler; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Hashtable; import javax.microedition.amms.GlobalManager; import javax.microedition.amms.MediaProcessor; import javax.microedition.amms.MediaProcessorListener; import javax.microedition.amms.control.imageeffect.ImageEffectControl; import javax.microedition.io.Connector; import javax.microedition.io.file.FileConnection; import javax.microedition.lcdui.AlertType; import javax.microedition.lcdui.Canvas; import javax.microedition.lcdui.Command; import javax.microedition.lcdui.CommandListener; import javax.microedition.lcdui.Displayable; import javax.microedition.lcdui.Font; import javax.microedition.lcdui.Graphics; import javax.microedition.lcdui.Image; import javax.microedition.media.MediaException; import com.nokia.mid.imagescale.ImageScaler; import com.nokia.mid.imagescale.ImageScalerException; import com.nokia.mid.imagescale.ImageScalerListener; 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;
Create the ImageCanvas
class to extend Canvas
and
implement CommandListener
, GestureListener
, ImageScalerListener
, MediaProcessorListener
and OrientationListener
.
public class ImageCanvas extends Canvas implements CommandListener, GestureListener, ImageScalerListener, MediaProcessorListener, OrientationListener {
Create required constants and variables.
private static final String JPEG_TYPE = "image/jpeg"; private static final String DESTINATION_FILE_NAME_PREFIX = "temp_"; private static final double SEVENTYFIVE_PERCENTS = .75; private static final double FIFTY_PERCENTS = .5; private static final double TWENTYFIVE_PERCENTS = .25; private final Command backCommand = new Command("Back", Command.BACK, 1); private final Command downscaleTo75PercentsCommand = new Command("Scale to 75 %", Command.ITEM, 1); private final Command downscaleTo50PercentsCommand = new Command("Scale to 50 %", Command.ITEM, 2); private final Command downscaleTo25PercentsCommand = new Command("Scale to 25 %", Command.ITEM, 3); private final Command resetCommand = new Command("Reset to original size", Command.ITEM, 6); private final Command monochromeCommand = new Command("To monochrome", Command.ITEM, 7); private MainView mainView = null; private ImageScaler imageScaler = null; private Image originalImage = null; private Image currentImage = null; private Hashtable imageTable = new Hashtable(); private String currentImageFilePath = null; private ByteArrayOutputStream byteArrayOutputStream = null; private int originalImageWidth = 0; private int originalImageHeight = 0; private int currentImageWidth = 0; private int currentImageHeight = 0; private int currentPointerX = 0; private int currentPointerY = 0; private int deltaPointerX = 0; private int deltaPointerY = 0; private int imagePosX; private int imagePosY; private int rgbImageData[];
Create the ImageCanvas
class constructor. In the constructor, add Commands
to the Screen
, hide the virtual keyboard, and start
listening for pinch gestures.
public ImageCanvas(MainView mainView) { if (System.getProperty("com.nokia.keyboard.type").equals("None") || System.getProperty("com.nokia.keyboard.type").equals("OnekeyBack")) { VirtualKeyboard.hideOpenKeypadCommand(true); } this.mainView = mainView; setTitle("Image Scaler"); addCommand(backCommand); addCommand(downscaleTo75PercentsCommand); addCommand(downscaleTo50PercentsCommand); addCommand(downscaleTo25PercentsCommand); addCommand(resetCommand); setCommandListener(this); Orientation.addOrientationListener(this); GestureRegistrationManager.setListener(this, this); GestureInteractiveZone myGestureZone = new GestureInteractiveZone( GestureInteractiveZone.GESTURE_PINCH); myGestureZone.setRectangle(0, 0, getWidth(), getHeight()); GestureRegistrationManager.register(this, myGestureZone); }
Implement commandAction
method from the CommandListener
interface to capture UI events and handle them to call the respective
functions calls.
public void commandAction(Command command, Displayable displayable) { if (command == backCommand) { currentImage = null; rgbImageData = null; mainView.displayThis(); } else if (command == downscaleTo75PercentsCommand || command == downscaleTo50PercentsCommand || command == downscaleTo25PercentsCommand) { int width = originalImageWidth; int height = originalImageHeight; if (command == downscaleTo75PercentsCommand) { width *= SEVENTYFIVE_PERCENTS; height *= SEVENTYFIVE_PERCENTS; } else if (command == downscaleTo50PercentsCommand) { width *= FIFTY_PERCENTS; height *= FIFTY_PERCENTS; } else { width *= TWENTYFIVE_PERCENTS; height *= TWENTYFIVE_PERCENTS; } final int newWidth = width; final int newHeight = height; new Thread(new Runnable() { public void run() { scaleImage(newWidth, newHeight, currentImageFilePath); } }).start(); } else if (command == resetCommand) { new Thread(new Runnable() { public void run() { loadImage(currentImageFilePath); } }).start(); } else if (command == monochromeCommand) { new Thread(new Runnable() { public void run() { createMonochromeImage(currentImageFilePath); } }).start(); } }
Implement paint
method from the Canvas to paint the
Screen
with updates.
protected void paint(Graphics graphics) { final int width = getWidth(); final int height = getHeight(); graphics.setColor(0x000000); graphics.fillRect(0, 0, width, height); calculateImagePlacement(); if (currentImage != null) { graphics.drawImage(currentImage, imagePosX, imagePosY, Graphics.HCENTER | Graphics.VCENTER); } else { graphics.setColor(0x00f4f4f4); graphics.drawString("No image", 20, height / 2 - Font.getDefaultFont().getHeight() / 2, Graphics.HCENTER | Graphics.BASELINE); } }
Implement keyReleased
method from the Canvas
to display mainView
.
protected void keyReleased(int keyCode) { mainView.displayThis(); }
Implement pointerPressed
method from the Canvas
to
set x and y coordinates.
protected void pointerPressed(int x, int y) { currentPointerX = x; currentPointerY = y; }
Implement pointerReleased
method from the Canvas
to
set x and y coordinates.
protected void pointerReleased(int x, int y) { deltaPointerX = 0; deltaPointerY = 0; }
Implement pointerDragged
method from the Canvas
to
set x and y coordinates.
protected void pointerDragged(int x, int y) { System.out.println("ImageCanvas::pointerDragged(): [" + x + ", " + y + "]"); deltaPointerX = x - currentPointerX; deltaPointerY = y - currentPointerY; currentPointerX = x; currentPointerY = y; repaint(); }
Implement scaleFinished
method from the ImageScalerListener
. This method is called to deliver an event to a registered listener
when a ImageScaling
finish event is observed.
public void scaleFinished(int requestId, int result) { final int reqId = requestId; new Thread(new Runnable() { public void run() { String imageFilePath = (String) imageTable.get(new Integer(reqId)); String destinationFilePath = Utils.PHOTOS_DIR + "/" + DESTINATION_FILE_NAME_PREFIX + imageFilePath.substring(imageFilePath.lastIndexOf('/') + 1); FileConnection fileConnection = null; InputStream inputStream = null; try { fileConnection = (FileConnection) Connector.open(destinationFilePath); } catch (IOException e) { return; } Image image = null; if (fileConnection.exists()) { try { inputStream = fileConnection.openInputStream(); image = Image.createImage(inputStream); } catch (IOException e) { return; } } currentImage = image; currentImageWidth = currentImage.getWidth(); currentImageHeight = currentImage.getHeight(); repaint(); try { inputStream.close(); fileConnection.close(); } catch (IOException e) { } } }).start(); }
Implement gestureAction
method from the GestureListener
. This method Indicates that a gesture event has occurred on a Canvas
.
public void gestureAction(Object arg0, GestureInteractiveZone arg1, GestureEvent gestureEvent) { switch (gestureEvent.getType()) { case GestureInteractiveZone.GESTURE_PINCH: Image scaledImage = null; int newWidth = currentImageWidth; int newHeight = currentImageHeight; if (gestureEvent.getPinchDistanceChange() == 0) { break; } else if (gestureEvent.getPinchDistanceChange() < 0) { newWidth *= 0.9; newHeight *= 0.9; } else if (gestureEvent.getPinchDistanceChange() > 0) { newWidth *= 1.1; newHeight *= 1.1; } scaledImage = Utils.scaleImage(originalImage, newWidth, newHeight); if (scaledImage != null) { // Image was scaled successfully currentImage = scaledImage; currentImageWidth = newWidth; currentImageHeight = newHeight; repaint(); } break; default: break; } }
Implement mediaProcessorUpdate
method from the MediaProcessorListener
. This method is called to deliver an event to a registered listener
when a MediaProcessor
event is observed.
public void mediaProcessorUpdate(MediaProcessor processor, String event, Object eventData) { if (event.equals(MediaProcessorListener.PROCESSING_ABORTED)) { System.out.println("ImageCanvas::mediaProcessorUpdate(): PROCESSING_ABORTED: " + eventData.toString()); } else if (event.equals(MediaProcessorListener.PROCESSING_ERROR)) { System.out.println("ImageCanvas::mediaProcessorUpdate(): PROCESSING_ERROR: " + eventData.toString()); } else if (event.equals(MediaProcessorListener.PROCESSING_STARTED)) { System.out.println("ImageCanvas::mediaProcessorUpdate(): PROCESSING_STARTED: " + eventData.toString()); } else if (event.equals(MediaProcessorListener.PROCESSING_STOPPED)) { System.out.println("ImageCanvas::mediaProcessorUpdate(): PROCESSING_STOPPED: " + eventData.toString()); } else if (event.equals(MediaProcessorListener.PROCESSOR_REALIZED)) { System.out.println("ImageCanvas::mediaProcessorUpdate(): PROCESSOR_REALIZED: " + eventData.toString()); } else if (event.equals(MediaProcessorListener.PROCESSING_COMPLETED)) { System.out.println("ImageCanvas::mediaProcessorUpdate(): PROCESSING_COMPLETED: " + eventData.toString()); Image resultImage = Image.createImage(byteArrayOutputStream.toByteArray(), 0, byteArrayOutputStream.size()); if (resultImage != null) { currentImage = resultImage; repaint(); } } }
Implement displayOrientationChanged
method from the OrientationListener
. This method is called when the display orientation has changed.
public void displayOrientationChanged(int newDisplayOrientation) { Orientation.setAppOrientation(newDisplayOrientation); }
Create the loadImage
method. This method loads an image from the given
file path and displays it on this canvas.
public boolean loadImage(String filePath) { FileConnection fileConnection = null; try { fileConnection = (FileConnection) Connector.open(filePath, Connector.READ); } catch (IOException e) { return false; } currentImageFilePath = filePath; if (rgbImageData != null) { rgbImageData = null; } int fileSize = 0; try { fileSize = (int) fileConnection.fileSize(); } catch (IOException e) { return false; } byte[] imageData = new byte[fileSize]; try { InputStream inputStream = fileConnection.openInputStream(); inputStream.read(imageData, 0, fileSize); inputStream.close(); fileConnection.close(); } catch (IOException e) { return false; } currentImage = Image.createImage(imageData, 0, fileSize); originalImageWidth = currentImageWidth = currentImage.getWidth(); originalImageHeight = currentImageHeight = currentImage.getHeight(); repaint(); return true; }
Create the scaleImage
method. This method scales the image in the given
path using the image scaler API.
private void scaleImage(final int newWidth, final int newHeight, final String sourceImageFilePath) { final String destinationFilePath = Utils.PHOTOS_DIR + "/" + DESTINATION_FILE_NAME_PREFIX + sourceImageFilePath.substring(sourceImageFilePath.lastIndexOf('/') + 1); imageScaler = new ImageScaler(sourceImageFilePath, destinationFilePath); imageScaler.addListener(this); Integer requestId = null; try { requestId = new Integer(imageScaler.scaleImage(newWidth, newHeight, true)); imageTable.put(requestId, sourceImageFilePath); } catch (ImageScalerException e) { mainView.showMessage(AlertType.ERROR, e.toString()); } }
Create the createMonochromeImage
method. This method reads image data
from the given path and creates a monochrome image of the original
image.
private void createMonochromeImage(String imageFilePath) { MediaProcessor mediaProcessor = null; try { mediaProcessor = GlobalManager.createMediaProcessor(JPEG_TYPE); } catch (MediaException e) { mainView.showMessage(AlertType.ERROR, e.toString()); return; } mediaProcessor.addMediaProcessorListener(this); FileConnection fileConnection = null; try { fileConnection = (FileConnection) Connector.open(imageFilePath, Connector.READ); } catch (IOException e) { return; } if (fileConnection != null && fileConnection.exists()) { InputStream inputStream = null; try { inputStream = fileConnection.openInputStream(); } catch (IOException e) { return; } try { mediaProcessor.setInput(inputStream, MediaProcessor.UNKNOWN); } catch (MediaException e) { mainView.showMessage(AlertType.ERROR, e.toString()); return; } try { inputStream.close(); fileConnection.close(); } catch (IOException e) { } } byteArrayOutputStream = new ByteArrayOutputStream(); mediaProcessor.setOutput(byteArrayOutputStream); ImageEffectControl imageEffect = (ImageEffectControl) mediaProcessor.getControl( "javax.microedition.amms.control.imageeffect.ImageEffectControl"); imageEffect.setPreset("monochrome"); imageEffect.setEnabled(true); try { mediaProcessor.start(); } catch (MediaException e) { mainView.showMessage(AlertType.ERROR, e.toString()); } }
Create the calculateImagePlacement
method.
This method calculates the image placement on the screen.
private void calculateImagePlacement() { final int canvasWidth = getWidth(); final int canvasHeight = getHeight(); if (currentImageWidth > canvasWidth && deltaPointerX != 0) { imagePosX += deltaPointerX; if (imagePosX < (canvasWidth - currentImageWidth / 2)) { imagePosX = canvasWidth - currentImageWidth / 2; } else if (imagePosX > (currentImageWidth / 2)) { imagePosX = (currentImageWidth / 2); } } else { imagePosX = canvasWidth / 2; } if (currentImageHeight > canvasHeight && deltaPointerY != 0) { imagePosY += deltaPointerY; if (imagePosY < (canvasHeight - currentImageHeight / 2)) { imagePosY = canvasHeight - currentImageHeight / 2; } else if (imagePosY > (currentImageHeight / 2)) { imagePosY = (currentImageHeight / 2); } } else { imagePosY = canvasHeight / 2; } } }