FileDocCategorySizeDatePackage
ImageLoaderUtil.javaAPI DocphoneME MR2 API (J2ME)10386Wed May 02 18:00:34 BST 2007com.sun.perseus.j2d

ImageLoaderUtil.java

/*
 *
 *
 * Copyright  1990-2007 Sun Microsystems, Inc. All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version
 * 2 only, as published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License version 2 for more details (a copy is
 * included at /legal/license.txt).
 * 
 * You should have received a copy of the GNU General Public License
 * version 2 along with this work; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 * 
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
 * Clara, CA 95054 or visit www.sun.com if you need additional
 * information or have any questions.
 */
package com.sun.perseus.j2d;

import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.Graphics;

import java.io.InputStream;
import java.io.IOException;

import javax.microedition.io.Connector;
import javax.microedition.io.StreamConnection;

import com.sun.perseus.util.Base64DecodeStream;

/**
 * This class contains utility methods which make <code>ImageLoader</code> 
 * implementations easier.
 *
 * @version $Id: ImageLoaderUtil.java,v 1.12 2006/04/21 06:34:56 st125089 Exp $
 */
public class ImageLoaderUtil {

    /**
     * Default, broken image returned if an image cannot be loaded.
     */
    protected RasterImage brokenImage;

    /**
     * Image used to symbolize loading state for an image.
     */
    protected RasterImage loadingImage;

    /**
     * HREF prefix for all Base64 encoded images
     */
    static final String BASE64_PREFIX = "data:";

    /**
     * Color used for broken content.
     */
    static final int BROKEN_IMAGE_COLOR = 0x00000000;

    /**
     * Color used for loading content.
     */
    static final int LOADING_IMAGE_COLOR = 0x00000000;

    /**
     * Default constructor
     */
    public ImageLoaderUtil() {

        createPlaceholderImages();

    }

    /**
     * Returns the image that should be used to represent 
     * an image which is loading.
     *
     * @return the image to use to represent a pending loading.
     */
    public RasterImage getLoadingImage() {
        return loadingImage;
    }

    /**
     * Returns the image that should be used to represent an
     * image which could not be loaded.
     *
     * @return the image to represent broken uris or content.
     */
    public RasterImage getBrokenImage() {
        return brokenImage;
    }

    /**
     * Returns true if the input uri is a data uri.
     *
     * @param uri the URI to analyze.
     * @return true if the input uri is a data uri.
     */
    public boolean isDataURI(final String uri) {
        return (uri.startsWith(BASE64_PREFIX));
    }

    /**
     * Utility method to turn an image href into an Image. This assumes
     * that the href points to an <b>external</b> resource. This can 
     * be tested on the href with the <code>isDataURI</code> method.
     *
     * @param href the address from which to load the image content.
     * @return the loaded image or <code>brokenImage</code> if the image
     *         could not be loaded.
     */
    public RasterImage getExternalImage(final String href) {

	System.out.println("getExternalImage(), Image href = " + href);

        Image img = null;
        StreamConnection c = null;
        InputStream s = null;

        try {
            c = (StreamConnection)Connector.open(href);
            s = c.openInputStream();
            img = Image.createImage(s);

        } catch (IOException ioe) {
            ioe.printStackTrace();

	    System.out.println("returning broken image");
            return brokenImage;

        } catch (IllegalArgumentException iae) {
            iae.printStackTrace();

	    System.out.println("returning broken image");
            return brokenImage;

        } finally {

	    try {
		if (s != null) 
		    s.close();
		if (c != null)
		    c.close();
	    } catch (IOException ioe) {

		//note : we have already read the image successfully. 
		//So don't fail, simply print stacktrace.

		ioe.printStackTrace();
	    }

        }
        return (new RasterImage(img));

    }

    /**
     * Creates a RasterImage from a byte array.
     *
     * @param b the byte array containing the encoded image
     *        data.
     */
    public RasterImage createImage(final byte[] imageData) {
        Image img = Image.createImage(imageData, 0, imageData.length);

        return (new RasterImage(img));
    }

    /**
     * Creates a RasterImage from an int array containing the pixel data
     */
    public RasterImage createImage(int[] imageData, int width, int height) {
	Image img = Image.createRGBImage(imageData, width, height, true);
	return new RasterImage(img);
    }

    /**
     * Utility method to get an <tt>Image</tt> from Base64 
     * encoded image data
     *
     * @param uri the uri with encoded image data
     * @return the decoded <tt>Image</tt> or brokenImage if the encoded data
     *         is invalid and could not be decoded.
     */
    public RasterImage getEmbededImage(final String uri) {
        int startAt = 0;
        if (uri.startsWith(BASE64_PNG_HREF_PREFIX)) {
            startAt = BASE64_PNG_HREF_PREFIX_LENGTH;
        } else if (uri.startsWith(BASE64_JPG_HREF_PREFIX)) {
            startAt = BASE64_JPG_HREF_PREFIX_LENGTH;
        } else if (uri.startsWith(BASE64_JPG_HREF_PREFIX2)) {
            startAt = BASE64_JPG_HREF_PREFIX2_LENGTH;
        } else if (uri.startsWith(BASE64_HREF_PREFIX)) {
            startAt = BASE64_HREF_PREFIX_LENGTH;
        } else {
            return brokenImage;
        }

        InputStream is = new Base64StringStream(uri, startAt);
        is = new Base64DecodeStream(is);

        // Base64 encodes 3 bytes with 4 characters
        byte[] data = new byte[(uri.length() - startAt) * 3 / 4];
        try {
	    Image img = Image.createImage(is);
	    return (new RasterImage(img));
        } catch (java.io.IOException ioe) {
	    ioe.printStackTrace();

            return brokenImage;
        }  catch (java.lang.IllegalArgumentException iae) {
            iae.printStackTrace();

            return brokenImage;

        } finally {
            try {
                is.close();
            } catch (java.io.IOException ioe) {
            }
        }
    }

    protected void createPlaceholderImages() {
        int[] argb = {BROKEN_IMAGE_COLOR};
        Image image = Image.createRGBImage(argb, 1, 1, true);
        brokenImage  = new RasterImage(image);

        argb = new int[] {LOADING_IMAGE_COLOR};
        image = Image.createRGBImage(argb, 1, 1, true);
        loadingImage = new RasterImage(image); 
    }


    /**
     * HREF prefix for Base64 encoded JPEG files
     */
    static final String BASE64_JPG_HREF_PREFIX 
        = "data:image/jpg;base64,";

    /**
     * HREF prefix for Base64 encoded JPEG files
     */
    static final String BASE64_JPG_HREF_PREFIX2 
        = "data:image/jpeg;base64,";

    /**
     * HREF prefix for Base64 encoded PNG files
     */
    static final String BASE64_PNG_HREF_PREFIX 
        = "data:image/png;base64,";

    /**
     * HREF prefix for Base64 encoded images with unspecified media type
     */
    static final String BASE64_HREF_PREFIX = "data:;base64,";

    /**
     * Length of the HREF prefix for Base64 encoded JPEG files
     */
    static final int BASE64_JPG_HREF_PREFIX_LENGTH
        = BASE64_JPG_HREF_PREFIX.getBytes().length;

    /**
     * Length of the HREF prefix for Base64 encoded JPEG files
     */
    static final int BASE64_JPG_HREF_PREFIX2_LENGTH
        = BASE64_JPG_HREF_PREFIX2.getBytes().length;

    /**
     * Length of the HREF prefix for Base64 encoded PNG files
     */
    static final int BASE64_PNG_HREF_PREFIX_LENGTH
        = BASE64_PNG_HREF_PREFIX.getBytes().length;

    /**
     * Length of the HREF prefix for Base64 encoded images with 
     * unspecified media type
     */
    static final int BASE64_HREF_PREFIX_LENGTH  
        = BASE64_HREF_PREFIX.getBytes().length;

    // =========================================================================

    /**
     * Specialized InputStream to read bytes from a String containing a 
     * Base64 encoded value. Because we know only the last 8 bits of each
     * character are used in Base64 encoded strings, we can safely map each
     * string character to a byte of data for the Base64 decoded. This saves
     * memory allocation as it avoids having to get a byte array from the 
     * String (i.e., we do not need to use getBytes).
     */
    static class Base64StringStream extends InputStream {
        /**
         * The <code>String</code> from which bytes are read.
         */
        private String str;

        /**
         * The length of the string
         */
        private int len = 0;

        /**
         * Bytes are read starting at this index.
         */
        private int offset = 0;

        /**
         * Reads the next byte of data from the input stream. The value byte 
         * is returned as an int in the range 0 to 255. If no byte is available
         * because the end of the stream has been reached, the value -1 is 
         * returned. This method blocks until input data is available, the 
         * end of the stream is detected, or an exception is thrown.
         *
         * @return the next byte of data, or -1 if the end of the stream is 
         *         reached.
         */
        public int read() {
            return offset < len ? str.charAt(offset++) : -1;
        }

        /**
         * Constructor.
         *
         * @param str the String where base64 values are read
         * @param offset the offset from which values are read
         */
        public Base64StringStream(final String str,
                                  final int offset) {
            this.str = str;
            this.offset = offset;
            this.len = str.length();
        }
    }

    // =========================================================================

}