001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026: package com.sun.perseus.j2d;
027:
028: import javax.microedition.lcdui.Image;
029: import javax.microedition.lcdui.Graphics;
030:
031: import java.io.InputStream;
032: import java.io.IOException;
033:
034: import javax.microedition.io.Connector;
035: import javax.microedition.io.StreamConnection;
036:
037: import com.sun.perseus.util.Base64DecodeStream;
038:
039: /**
040: * This class contains utility methods which make <code>ImageLoader</code>
041: * implementations easier.
042: *
043: * @version $Id: ImageLoaderUtil.java,v 1.12 2006/04/21 06:34:56 st125089 Exp $
044: */
045: public class ImageLoaderUtil {
046:
047: /**
048: * Default, broken image returned if an image cannot be loaded.
049: */
050: protected RasterImage brokenImage;
051:
052: /**
053: * Image used to symbolize loading state for an image.
054: */
055: protected RasterImage loadingImage;
056:
057: /**
058: * HREF prefix for all Base64 encoded images
059: */
060: static final String BASE64_PREFIX = "data:";
061:
062: /**
063: * Color used for broken content.
064: */
065: static final int BROKEN_IMAGE_COLOR = 0x00000000;
066:
067: /**
068: * Color used for loading content.
069: */
070: static final int LOADING_IMAGE_COLOR = 0x00000000;
071:
072: /**
073: * Default constructor
074: */
075: public ImageLoaderUtil() {
076:
077: createPlaceholderImages();
078:
079: }
080:
081: /**
082: * Returns the image that should be used to represent
083: * an image which is loading.
084: *
085: * @return the image to use to represent a pending loading.
086: */
087: public RasterImage getLoadingImage() {
088: return loadingImage;
089: }
090:
091: /**
092: * Returns the image that should be used to represent an
093: * image which could not be loaded.
094: *
095: * @return the image to represent broken uris or content.
096: */
097: public RasterImage getBrokenImage() {
098: return brokenImage;
099: }
100:
101: /**
102: * Returns true if the input uri is a data uri.
103: *
104: * @param uri the URI to analyze.
105: * @return true if the input uri is a data uri.
106: */
107: public boolean isDataURI(final String uri) {
108: return (uri.startsWith(BASE64_PREFIX));
109: }
110:
111: /**
112: * Utility method to turn an image href into an Image. This assumes
113: * that the href points to an <b>external</b> resource. This can
114: * be tested on the href with the <code>isDataURI</code> method.
115: *
116: * @param href the address from which to load the image content.
117: * @return the loaded image or <code>brokenImage</code> if the image
118: * could not be loaded.
119: */
120: public RasterImage getExternalImage(final String href) {
121:
122: System.out.println("getExternalImage(), Image href = " + href);
123:
124: Image img = null;
125: StreamConnection c = null;
126: InputStream s = null;
127:
128: try {
129: c = (StreamConnection) Connector.open(href);
130: s = c.openInputStream();
131: img = Image.createImage(s);
132:
133: } catch (IOException ioe) {
134: ioe.printStackTrace();
135:
136: System.out.println("returning broken image");
137: return brokenImage;
138:
139: } catch (IllegalArgumentException iae) {
140: iae.printStackTrace();
141:
142: System.out.println("returning broken image");
143: return brokenImage;
144:
145: } finally {
146:
147: try {
148: if (s != null)
149: s.close();
150: if (c != null)
151: c.close();
152: } catch (IOException ioe) {
153:
154: //note : we have already read the image successfully.
155: //So don't fail, simply print stacktrace.
156:
157: ioe.printStackTrace();
158: }
159:
160: }
161: return (new RasterImage(img));
162:
163: }
164:
165: /**
166: * Creates a RasterImage from a byte array.
167: *
168: * @param b the byte array containing the encoded image
169: * data.
170: */
171: public RasterImage createImage(final byte[] imageData) {
172: Image img = Image.createImage(imageData, 0, imageData.length);
173:
174: return (new RasterImage(img));
175: }
176:
177: /**
178: * Creates a RasterImage from an int array containing the pixel data
179: */
180: public RasterImage createImage(int[] imageData, int width,
181: int height) {
182: Image img = Image
183: .createRGBImage(imageData, width, height, true);
184: return new RasterImage(img);
185: }
186:
187: /**
188: * Utility method to get an <tt>Image</tt> from Base64
189: * encoded image data
190: *
191: * @param uri the uri with encoded image data
192: * @return the decoded <tt>Image</tt> or brokenImage if the encoded data
193: * is invalid and could not be decoded.
194: */
195: public RasterImage getEmbededImage(final String uri) {
196: int startAt = 0;
197: if (uri.startsWith(BASE64_PNG_HREF_PREFIX)) {
198: startAt = BASE64_PNG_HREF_PREFIX_LENGTH;
199: } else if (uri.startsWith(BASE64_JPG_HREF_PREFIX)) {
200: startAt = BASE64_JPG_HREF_PREFIX_LENGTH;
201: } else if (uri.startsWith(BASE64_JPG_HREF_PREFIX2)) {
202: startAt = BASE64_JPG_HREF_PREFIX2_LENGTH;
203: } else if (uri.startsWith(BASE64_HREF_PREFIX)) {
204: startAt = BASE64_HREF_PREFIX_LENGTH;
205: } else {
206: return brokenImage;
207: }
208:
209: InputStream is = new Base64StringStream(uri, startAt);
210: is = new Base64DecodeStream(is);
211:
212: // Base64 encodes 3 bytes with 4 characters
213: byte[] data = new byte[(uri.length() - startAt) * 3 / 4];
214: try {
215: Image img = Image.createImage(is);
216: return (new RasterImage(img));
217: } catch (java.io.IOException ioe) {
218: ioe.printStackTrace();
219:
220: return brokenImage;
221: } catch (java.lang.IllegalArgumentException iae) {
222: iae.printStackTrace();
223:
224: return brokenImage;
225:
226: } finally {
227: try {
228: is.close();
229: } catch (java.io.IOException ioe) {
230: }
231: }
232: }
233:
234: protected void createPlaceholderImages() {
235: int[] argb = { BROKEN_IMAGE_COLOR };
236: Image image = Image.createRGBImage(argb, 1, 1, true);
237: brokenImage = new RasterImage(image);
238:
239: argb = new int[] { LOADING_IMAGE_COLOR };
240: image = Image.createRGBImage(argb, 1, 1, true);
241: loadingImage = new RasterImage(image);
242: }
243:
244: /**
245: * HREF prefix for Base64 encoded JPEG files
246: */
247: static final String BASE64_JPG_HREF_PREFIX = "data:image/jpg;base64,";
248:
249: /**
250: * HREF prefix for Base64 encoded JPEG files
251: */
252: static final String BASE64_JPG_HREF_PREFIX2 = "data:image/jpeg;base64,";
253:
254: /**
255: * HREF prefix for Base64 encoded PNG files
256: */
257: static final String BASE64_PNG_HREF_PREFIX = "data:image/png;base64,";
258:
259: /**
260: * HREF prefix for Base64 encoded images with unspecified media type
261: */
262: static final String BASE64_HREF_PREFIX = "data:;base64,";
263:
264: /**
265: * Length of the HREF prefix for Base64 encoded JPEG files
266: */
267: static final int BASE64_JPG_HREF_PREFIX_LENGTH = BASE64_JPG_HREF_PREFIX
268: .getBytes().length;
269:
270: /**
271: * Length of the HREF prefix for Base64 encoded JPEG files
272: */
273: static final int BASE64_JPG_HREF_PREFIX2_LENGTH = BASE64_JPG_HREF_PREFIX2
274: .getBytes().length;
275:
276: /**
277: * Length of the HREF prefix for Base64 encoded PNG files
278: */
279: static final int BASE64_PNG_HREF_PREFIX_LENGTH = BASE64_PNG_HREF_PREFIX
280: .getBytes().length;
281:
282: /**
283: * Length of the HREF prefix for Base64 encoded images with
284: * unspecified media type
285: */
286: static final int BASE64_HREF_PREFIX_LENGTH = BASE64_HREF_PREFIX
287: .getBytes().length;
288:
289: // =========================================================================
290:
291: /**
292: * Specialized InputStream to read bytes from a String containing a
293: * Base64 encoded value. Because we know only the last 8 bits of each
294: * character are used in Base64 encoded strings, we can safely map each
295: * string character to a byte of data for the Base64 decoded. This saves
296: * memory allocation as it avoids having to get a byte array from the
297: * String (i.e., we do not need to use getBytes).
298: */
299: static class Base64StringStream extends InputStream {
300: /**
301: * The <code>String</code> from which bytes are read.
302: */
303: private String str;
304:
305: /**
306: * The length of the string
307: */
308: private int len = 0;
309:
310: /**
311: * Bytes are read starting at this index.
312: */
313: private int offset = 0;
314:
315: /**
316: * Reads the next byte of data from the input stream. The value byte
317: * is returned as an int in the range 0 to 255. If no byte is available
318: * because the end of the stream has been reached, the value -1 is
319: * returned. This method blocks until input data is available, the
320: * end of the stream is detected, or an exception is thrown.
321: *
322: * @return the next byte of data, or -1 if the end of the stream is
323: * reached.
324: */
325: public int read() {
326: return offset < len ? str.charAt(offset++) : -1;
327: }
328:
329: /**
330: * Constructor.
331: *
332: * @param str the String where base64 values are read
333: * @param offset the offset from which values are read
334: */
335: public Base64StringStream(final String str, final int offset) {
336: this .str = str;
337: this .offset = offset;
338: this .len = str.length();
339: }
340: }
341:
342: // =========================================================================
343:
344: }
|