×

ImageUtils.java

/**
 * 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);
    }
}

Last updated 15 October 2013

Back to top

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×