/** * Copyright (c) 2012-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 text file delivered with this project for more information. */ package com.nokia.example.statusshout.ui; import java.io.IOException; import java.io.InputStream; import com.nokia.mid.ui.DirectUtils; import javax.microedition.io.Connector; import javax.microedition.io.file.FileConnection; import javax.microedition.lcdui.Display; import javax.microedition.lcdui.Image; /** * Utilities for handling images. */ public class ImageUtils { // Constants private static final String TAG = "ImageUtils."; private static final int CHUNK_SIZE = 1024; /** * Loads an image from the phone and returns it. Note that you usually need * to call this method from a separate thread in order not to block the UI. * * @param imageUri The image URI. * @return The loaded image or null in case of an error. */ public static Image loadImageFromPhone(final String imageUri) { System.out.println(TAG + "loadImageFromPhone(): " + imageUri); Image image = null; try { FileConnection fileConnection = (FileConnection)Connector.open(imageUri); InputStream in = fileConnection.openInputStream(); if (in != null) { image = Image.createImage(in); in.close(); } fileConnection.close(); } catch (IOException e) { e.printStackTrace(); } return image; } /** * * @param imageUri * @return */ public static byte[] localImageToByteArray(final String imageUri) { System.out.println(TAG + "localImageToByteArray(): " + imageUri); byte[] imageData = null; try { FileConnection fileConnection = (FileConnection)Connector.open(imageUri); InputStream in = fileConnection.openInputStream(); if (in != null) { long length = 0; long overallSize = fileConnection.fileSize(); System.out.println(TAG + "localImageToByteArray(): File size is " + overallSize); byte[] nextChunk = new byte[CHUNK_SIZE]; imageData = new byte[0]; while (length < overallSize) { int readAmount = in.read(nextChunk, 0, CHUNK_SIZE); byte[] temp = new byte[imageData.length + readAmount]; System.arraycopy(imageData, 0, temp, 0, (int)length); System.arraycopy(nextChunk, 0, temp, (int)length, readAmount); imageData = temp; length += readAmount; } in.close(); } fileConnection.close(); } catch (IOException e) { e.printStackTrace(); } return imageData; } /** * Sets the alpha of the each pixel in the image based on the given value. * * @param image The original image. * @param alpha The alpha value. * @return A newly created image with applied alpha. * @throws NullPointerException If the given image is null. * @throws IllegalArgumentException If the alpha value is not in [0, 255]. */ public static Image setAlpha(final Image image, final int alpha) throws NullPointerException, IllegalArgumentException { if (image == null) { throw new NullPointerException(); } if (alpha < 0 || alpha > 255) { throw new IllegalArgumentException(); } final int width = image.getWidth(); final int height = image.getHeight(); final int[] originalRgb = new int[width * height]; image.getRGB(originalRgb, 0, width, 0, 0, width, height); final int opaqueRgb[] = new int[width * height]; for (int x = 0; x < width; ++x) { for (int y = 0; y < height; ++y) { if (originalRgb[(width * y) + x] >>> 24 == 255) { opaqueRgb[(width * y) + x] = originalRgb[(width * y) + x] + (alpha << 24); } else { opaqueRgb[(width * y) + x] = originalRgb[(width * y) + x]; } } } return Image.createRGBImage(opaqueRgb, width, height, true); } /** * Subtracts the given RGB values from the given image while maintaining * the alpha level of each pixel. * * @param image The original image. * @param r Red value to subtract. * @param g Green value to subtract. * @param b Blue value to subtract. * @return The modified image. * @throws NullPointerException If the given image is null. * @throws IllegalArgumentException If any of RGB values is invalid. */ public static Image substractRgb(final Image image, final int r, final int g, final int b) throws NullPointerException, IllegalArgumentException { if (image == null) { throw new NullPointerException(); } if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) { throw new IllegalArgumentException(); } final int[] rgbToSubstract = new int[3]; rgbToSubstract[0] = r; rgbToSubstract[1] = g; rgbToSubstract[2] = b; final int width = image.getWidth(); final int height = image.getHeight(); final int[] originalRgb = new int[width * height]; image.getRGB(originalRgb, 0, width, 0, 0, width, height); final int newRgb[] = new int[width * height]; int pixel = 0; int[] argb = new int[4]; for (int x = 0; x < width; ++x) { for (int y = 0; y < height; ++y) { pixel = originalRgb[(width * y) + x]; argb[0] = (pixel & 0xff000000) >>> 24; argb[1] = (pixel & 0x00ff0000) >>> 16; argb[2] = (pixel & 0x0000ff00) >>> 8; argb[3] = pixel & 0x000000ff; for (int i = 0; i < 3; ++i) { if (argb[i + 1] - rgbToSubstract[i] >= 0) { argb[i + 1] -= rgbToSubstract[i]; } else { argb[i + 1] = 0; } } newRgb[(width * y) + x] = (argb[0] << 24) | (argb[1] << 16) | (argb[2] << 8) | argb[3]; } } return Image.createRGBImage(newRgb, width, height, true); } /** * This method takes an image and overlays all the visible pixels with the * specified color. This is useful for single color icons that should be * colored according to the theme of the device. * * @param image The original image. * @return The resulting image. */ public static Image drawMaskedImage(Image image, Display display) { final int color = display.getColor(Display.COLOR_HIGHLIGHTED_BORDER); // Store the pixel array of the image final int[] sourceData = new int[image.getHeight() * image.getWidth()]; image.getRGB( sourceData, 0, image.getWidth(), 0, 0, image.getWidth(), image.getHeight()); // Overlay non-transparent pixels with the specified color for (int i = 0; i < sourceData.length; i++) { sourceData[i] = (sourceData[i] & 0xFF000000) | (color & 0x00FFFFFF); } // Create the new image final Image overlayed = DirectUtils.createImage( image.getWidth(), image.getHeight(), 0x000000); overlayed.getGraphics().drawRGB( sourceData, 0, image.getWidth(), 0, 0, image.getWidth(), image.getHeight(), true); return overlayed; } /** * Scales the given image. * * @param image The original image. * @param newWidth The new image width. * @param newHeight The new image height. * @return The scaled image. */ public static Image scale(final Image image, final int newWidth, final int newHeight) { if (newWidth <= 0 || newHeight <= 0 || image == null) { throw new IllegalArgumentException( "Invalid width or height or the given image is null!"); } // Get the size and the RGB array of the original image final int sourceWidth = image.getWidth(); final int sourceHeight = image.getHeight(); final int[] originalRgb = new int[sourceWidth * sourceHeight]; image.getRGB(originalRgb, 0, sourceWidth, 0, 0, sourceWidth, sourceHeight); final int scaledRgb[] = new int[newWidth * newHeight]; for (int y = 0; y < newHeight; y++) { final int dy = y * sourceHeight / newHeight; for (int x = 0; x < newWidth; x++) { final int dx = x * sourceWidth / newWidth; scaledRgb[(newWidth * y) + x] = originalRgb[(sourceWidth * dy) + dx]; } } return Image.createRGBImage(scaledRgb, newWidth, newHeight, true); } /** * Scales the given image using pixel mixing scaling algorithm. * * @param originalImage The original image instance. * @param newWidth The new image width. * @param newHeight The new image height. * @return The scaled image. */ public static Image pixelMixingScale(final Image originalImage, final int newWidth, final int newHeight) { if (newWidth <= 0 || newHeight <= 0 || originalImage == null) { throw new IllegalArgumentException( "Invalid width or height or the given image is null!"); } final int sourceWidth = originalImage.getWidth(); final int sourceHeight = originalImage.getHeight(); final int[] originalRgb = new int[sourceHeight * sourceWidth]; originalImage.getRGB(originalRgb, 0, sourceWidth, 0, 0, sourceWidth, sourceHeight); final int[] scaledRgb = new int[newWidth * newHeight]; final int oWidth = sourceWidth; final int[] oX16 = new int[newWidth + 1]; for (int newX = 0; newX <= newWidth; newX++) { oX16[newX] = ((newX * oWidth) << 4) / newWidth; } final int[] oXStartWidth = new int[newWidth]; final int[] oXEndWidth = new int[newWidth]; for (int newX = 0; newX < newWidth; newX++) { oXStartWidth[newX] = 16 - (oX16[newX] % 16); oXEndWidth[newX] = oX16[newX + 1] % 16; } final int oHeight = sourceHeight; final int[] oY16 = new int[newHeight + 1]; for (int newY = 0; newY <= newHeight; newY++) { oY16[newY] = ((newY * oHeight) << 4) / newHeight; } for (int newY = 0; newY < newHeight; newY++) { final int oY16Start = oY16[newY]; final int oY16End = oY16[newY + 1]; final int oYStart = oY16Start >>> 4; final int oYEnd = oY16End >>> 4; final int oYStartHeight = 16 - (oY16Start % 16); final int oYEndHeight = oY16End % 16; for (int newX = 0; newX < newWidth; newX++) { final int oX16Start = oX16[newX]; final int oX16End = oX16[newX + 1]; final int oXStart = oX16Start >>> 4; final int oXEnd = oX16End >>> 4; int outArea = 0; int outColorArea = 0; int outAlpha = 0; int outRed = 0; int outGreen = 0; int outBlue = 0; for (int j = oYStart; j <= oYEnd; j++) { final int areaHeight; if (oYStart == oYEnd) { areaHeight = oY16End - oY16Start; } else if (j == oYStart) { areaHeight = oYStartHeight; } else if (j == oYEnd) { areaHeight = oYEndHeight; } else { areaHeight = 16; } if (areaHeight == 0) { continue; } for (int i = oXStart; i <= oXEnd; i++) { final int areaWidth; if (oXStart == oXEnd) { areaWidth = oX16End - oX16Start; } else if (i == oXStart) { areaWidth = oXStartWidth[newX]; } else if (i == oXEnd) { areaWidth = oXEndWidth[newX]; } else { areaWidth = 16; } if (areaWidth == 0) { continue; } int area = areaWidth * areaHeight; outArea += area; int argb = originalRgb[i + j * sourceWidth]; int a = (argb >>> 24); if (a == 0) { continue; } area = a * area; outColorArea += area; final int r = (argb & 0x00ff0000) >>> 16; final int g = (argb & 0x0000ff00) >>> 8; final int b = argb & 0x000000ff; outRed += area * r; outGreen += area * g; outBlue += area * b; } } if (outColorArea > 0) { outAlpha = outColorArea / outArea; outRed = outRed / outColorArea; outGreen = outGreen / outColorArea; outBlue = outBlue / outColorArea; } scaledRgb[newX + newY * newWidth] = (outAlpha << 24) | (outRed << 16) | (outGreen << 8) | outBlue; } } return Image.createRGBImage(scaledRgb, newWidth, newHeight, true); } }