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:
027: package javax.microedition.lcdui;
028:
029: import java.io.InputStream;
030: import java.io.IOException;
031:
032: import com.sun.midp.midlet.MIDletSuite;
033: import com.sun.midp.midlet.MIDletStateHandler;
034:
035: /**
036: * ImageFactory implementation based on putpixel graphics library and stores
037: * data on Java heap.
038: */
039: class ImageDataFactory implements AbstractImageDataFactory {
040:
041: /**
042: * PNG Header Data
043: */
044: private static final byte[] pngHeader = new byte[] { (byte) 0x89,
045: (byte) 0x50, (byte) 0x4e, (byte) 0x47, (byte) 0x0d,
046: (byte) 0x0a, (byte) 0x1a, (byte) 0x0a, (byte) 0x00,
047: (byte) 0x00, (byte) 0x00, (byte) 0x0d, (byte) 0x49,
048: (byte) 0x48, (byte) 0x44, (byte) 0x52 };
049:
050: /**
051: * JPEG Header Data
052: */
053: private static final byte[] jpegHeader = new byte[] { (byte) 0xff,
054: (byte) 0xd8, (byte) 0xff, (byte) 0xe0 };
055:
056: /**
057: * RAW Header Data
058: */
059: private static final byte[] rawHeader = new byte[] { (byte) 0x89,
060: (byte) 0x53, (byte) 0x55, (byte) 0x4E };
061:
062: /**
063: * ImageDataFactory singleton used for <code>ImageData</code>
064: * creation.
065: */
066: private static ImageDataFactory imageDataFactory = new ImageDataFactory();
067:
068: /**
069: * Returns the singleton <code>ImageDataFactory</code> instance.
070: *
071: * @return the singleton <code>ImageDataFactory</code> instance.
072: */
073: public static AbstractImageDataFactory getImageDataFactory() {
074: return imageDataFactory;
075: }
076:
077: /**
078: * Creates a new, mutable image for off-screen drawing. Every pixel
079: * within the newly created image is white. The width and height of the
080: * image must both be greater than zero.
081: *
082: * @param width the width of the new image, in pixels
083: * @param height the height of the new image, in pixels
084: * @return the created image
085: */
086: public ImageData createOffScreenImageData(int width, int height) {
087: return new ImageData(width, height, true, true, false);
088: }
089:
090: /**
091: * Creates an immutable <code>ImageData</code> from
092: * a <code>mutableSource ImageData</code>.
093: * If the source image data is mutable, an immutable copy is created and
094: * returned. If the source image data is immutable, the implementation may
095: * simply return it without creating a new image. If an immutable source
096: * image data contains transparency information,
097: * this information is copied to the new image data unchanged.
098: *
099: * <p> This method is useful for placing the contents of mutable images
100: * into <code>Choice</code> objects. The application can create
101: * an off-screen image
102: * using the
103: * {@link #createImage(int, int) createImage(w, h)}
104: * method, draw into it using a <code>Graphics</code> object
105: * obtained with the
106: * {@link #getGraphics() getGraphics()}
107: * method, and then create an immutable copy of it with this method.
108: * The immutable copy may then be placed into <code>Choice</code>
109: * objects. </p>
110: *
111: * @param mutableSource the source mutable image to be copied
112: * @return the new immutable image data
113: *
114: * @throws NullPointerException if <code>source</code> is <code>null</code>
115: */
116: public ImageData createImmutableCopy(ImageData mutableSource) {
117: int width = mutableSource.getWidth();
118: int height = mutableSource.getHeight();
119: int length = width * height * 2;
120:
121: return new ImageData(width, height, false, mutableSource
122: .getPixelData());
123: }
124:
125: /**
126: * Creates an immutable <code>ImageData</code>
127: * from decoded image data obtained from the
128: * named resource. The name parameter is a resource name as defined by
129: * {@link Class#getResourceAsStream(String)
130: * Class.getResourceAsStream(name)}. The rules for resolving resource
131: * names are defined in the
132: * <a href="../../../java/lang/package-summary.html">
133: * Application Resource Files</a> section of the
134: * <code>java.lang</code> package documentation.
135: *
136: * @param name the name of the resource containing the image data in one of
137: * the supported image formats
138: * @return the created image data
139: * @throws NullPointerException if <code>name</code> is <code>null</code>
140: * @throws java.io.IOException if the resource does not exist,
141: * the data cannot
142: * be loaded, or the image data cannot be decoded
143: */
144: public ImageData createResourceImageData(String name)
145: throws IOException {
146: ImageData data = new ImageData();
147:
148: /*
149: * Load native image data from cache and create
150: * image, if available. If image is not cached,
151: * proceed to load and create image normally.
152: */
153: if (!loadCachedImage(data, name)) {
154: createImageFromStream(data, ImageData.class
155: .getResourceAsStream(name));
156: }
157:
158: return data;
159: }
160:
161: /**
162: * Creates an immutable <code>ImageData</code>
163: * which is decoded from the data stored in
164: * the specified byte array at the specified offset and length. The data
165: * must be in a self-identifying image file format supported by the
166: * implementation, such as <a href="#PNG">PNG</A>.
167: *
168: * <p>The <code>imageoffset</code> and <code>imagelength</code>
169: * parameters specify a range of
170: * data within the <code>imageData</code> byte array. The
171: * <code>imageOffset</code> parameter
172: * specifies the
173: * offset into the array of the first data byte to be used. It must
174: * therefore lie within the range
175: * <code>[0..(imageData.length-1)]</code>. The
176: * <code>imageLength</code>
177: * parameter specifies the number of data bytes to be used. It must be a
178: * positive integer and it must not cause the range to extend beyond
179: * the end
180: * of the array. That is, it must be true that
181: * <code>imageOffset + imageLength < imageData.length</code>. </p>
182: *
183: * <p> This method is intended for use when loading an
184: * image from a variety of sources, such as from
185: * persistent storage or from the network.</p>
186: *
187: * @param imageBytes the array of image data in a supported image format
188: * @param imageOffset the offset of the start of the data in the array
189: * @param imageLength the length of the data in the array
190: *
191: * @return the created image
192: * @throws ArrayIndexOutOfBoundsException if <code>imageOffset</code>
193: * and <code>imageLength</code>
194: * specify an invalid range
195: * @throws NullPointerException if <code>imageData</code> is
196: * <code>null</code>
197: * @throws IllegalArgumentException if <code>imageData</code> is incorrectly
198: * formatted or otherwise cannot be decoded
199: */
200: public ImageData createImmutableImageData(byte[] imageBytes,
201: int imageOffset, int imageLength) {
202: ImageData data = new ImageData();
203: // parse the pixel data
204: decode(data, imageBytes, imageOffset, imageLength);
205: return data;
206: }
207:
208: /**
209: * Creates an immutable <code>ImageData</code>
210: * using pixel data from the specified
211: * region of a source <code>ImageData</code>, transformed as specified.
212: *
213: * <p>The source image dara may be mutable or immutable.
214: * For immutable source image data,
215: * transparency information, if any, is copied to the new
216: * image data unchanged.</p>
217: *
218: * <p>On some devices, pre-transformed images may render more quickly
219: * than images that are transformed on the fly using
220: * <code>drawRegion</code>.
221: * However, creating such images does consume additional heap space,
222: * so this technique should be applied only to images whose rendering
223: * speed is critical.</p>
224: *
225: * <p>The transform function used must be one of the following, as defined
226: * in the {@link javax.microedition.lcdui.game.Sprite Sprite} class:<br>
227: *
228: * <code>Sprite.TRANS_NONE</code> - causes the specified image
229: * region to be copied unchanged<br>
230: * <code>Sprite.TRANS_ROT90</code> - causes the specified image
231: * region to be rotated clockwise by 90 degrees.<br>
232: * <code>Sprite.TRANS_ROT180</code> - causes the specified image
233: * region to be rotated clockwise by 180 degrees.<br>
234: * <code>Sprite.TRANS_ROT270</code> - causes the specified image
235: * region to be rotated clockwise by 270 degrees.<br>
236: * <code>Sprite.TRANS_MIRROR</code> - causes the specified image
237: * region to be reflected about its vertical center.<br>
238: * <code>Sprite.TRANS_MIRROR_ROT90</code> - causes the specified image
239: * region to be reflected about its vertical center and then rotated
240: * clockwise by 90 degrees.<br>
241: * <code>Sprite.TRANS_MIRROR_ROT180</code> - causes the specified image
242: * region to be reflected about its vertical center and then rotated
243: * clockwise by 180 degrees.<br>
244: * <code>Sprite.TRANS_MIRROR_ROT270</code> - causes the specified image
245: * region to be reflected about its vertical center and then rotated
246: * clockwise by 270 degrees.<br></p>
247: *
248: * <p>
249: * The size of the returned image will be the size of the specified region
250: * with the transform applied. For example, if the region is
251: * <code>100 x 50</code> pixels and the transform is
252: * <code>TRANS_ROT90</code>, the
253: * returned image will be <code>50 x 100</code> pixels.</p>
254: *
255: * <p><strong>Note:</strong> If all of the following conditions
256: * are met, this method may
257: * simply return the source <code>Image</code> without creating a
258: * new one:</p>
259: * <ul>
260: * <li>the source image is immutable;</li>
261: * <li>the region represents the entire source image; and</li>
262: * <li>the transform is <code>TRANS_NONE</code>.</li>
263: * </ul>
264: *
265: * @param dataSource the source image data to be copied from
266: * @param x the horizontal location of the region to be copied
267: * @param y the vertical location of the region to be copied
268: * @param w the width of the region to be copied
269: * @param h the height of the region to be copied
270: * @param transform the transform to be applied to the region
271: * @return the new, immutable image
272: *
273: * @throws NullPointerException if <code>image</code> is <code>null</code>
274: * @throws IllegalArgumentException if the region to be copied exceeds
275: * the bounds of the source image
276: * @throws IllegalArgumentException if either <code>width</code> or
277: * <code>height</code> is zero or less
278: * @throws IllegalArgumentException if the <code>transform</code>
279: * is not valid
280: *
281: */
282: public ImageData createImmutableImageData(ImageData dataSource,
283: int x, int y, int w, int h, int transform) {
284:
285: ImageData dataDest = null;
286:
287: if ((transform & Image.TRANSFORM_SWAP_AXIS) == Image.TRANSFORM_SWAP_AXIS) {
288: dataDest = new ImageData(h, w, false, false, dataSource
289: .hasAlpha());
290: } else {
291: dataDest = new ImageData(w, h, false, false, dataSource
292: .hasAlpha());
293: }
294:
295: // Copy either the Java or romized data to its own array
296: loadRegion(dataDest, dataSource, x, y, w, h, transform);
297:
298: return dataDest;
299: }
300:
301: /**
302: * Creates an immutable <code>ImageData</code>
303: * from a sequence of ARGB values, specified
304: * as <code>0xAARRGGBB</code>.
305: * The ARGB data within the <code>rgb</code> array is arranged
306: * horizontally from left to right within each row,
307: * row by row from top to bottom.
308: * If <code>processAlpha</code> is <code>true</code>,
309: * the high-order byte specifies opacity; that is,
310: * <code>0x00RRGGBB</code> specifies
311: * a fully transparent pixel and <code>0xFFRRGGBB</code> specifies
312: * a fully opaque
313: * pixel. Intermediate alpha values specify semitransparency. If the
314: * implementation does not support alpha blending for image rendering
315: * operations, it must replace any semitransparent pixels with fully
316: * transparent pixels. (See <a href="#alpha">Alpha Processing</a>
317: * for further discussion.) If <code>processAlpha</code> is
318: * <code>false</code>, the alpha values
319: * are ignored and all pixels must be treated as fully opaque.
320: *
321: * <p>Consider <code>P(a,b)</code> to be the value of the pixel
322: * located at column <code>a</code> and row <code>b</code> of the
323: * Image, where rows and columns are numbered downward from the
324: * top starting at zero, and columns are numbered rightward from
325: * the left starting at zero. This operation can then be defined
326: * as:</p>
327: *
328: * <TABLE BORDER="2">
329: * <TR>
330: * <TD ROWSPAN="1" COLSPAN="1">
331: * <pre><code>
332: * P(a, b) = rgb[a + b * width]; </code></pre>
333: * </TD>
334: * </TR>
335: * </TABLE>
336: * <p>for</p>
337: *
338: * <TABLE BORDER="2">
339: * <TR>
340: * <TD ROWSPAN="1" COLSPAN="1">
341: * <pre><code>
342: * 0 <= a < width
343: * 0 <= b < height </code></pre>
344: * </TD>
345: * </TR>
346: * </TABLE>
347: * <p> </p>
348: *
349: * @param rgb an array of ARGB values that composes the image
350: * @param width the width of the image
351: * @param height the height of the image
352: * @param processAlpha <code>true</code> if <code>rgb</code>
353: * has an alpha channel,
354: * <code>false</code> if all pixels are fully opaque
355: * @return the created <code>ImageData</code>
356: * @throws NullPointerException if <code>rgb</code> is <code>null</code>.
357: * @throws IllegalArgumentException if either <code>width</code> or
358: * <code>height</code> is zero or less
359: * @throws ArrayIndexOutOfBoundsException if the length of
360: * <code>rgb</code> is
361: * less than<code> width * height</code>.
362: *
363: */
364: public ImageData createImmutableImageData(int rgb[], int width,
365: int height, boolean processAlpha) {
366: ImageData data = new ImageData(width, height, false, false,
367: processAlpha);
368: loadRGB(data, rgb);
369:
370: return data;
371: }
372:
373: /**
374: * Function to decode an <code>ImageData</code> from romized data.
375: *
376: * @param imageDataArrayPtr native pointer to image data as Java int
377: * @param imageDataArrayLength length of image data array
378: * @return <code>ImageData</code> created from romized data.
379: * @throws IllegalArgumentException if the id is invalid
380: */
381: public ImageData createImmutableImageData(int imageDataArrayPtr,
382: int imageDataArrayLength) {
383:
384: ImageData data = new ImageData();
385: if (!loadRomizedImage(data, imageDataArrayPtr,
386: imageDataArrayLength)) {
387: throw new IllegalArgumentException();
388: }
389: return data;
390: }
391:
392: /**
393: * Creates an immutable image from decoded image data obtained from an
394: * <code>InputStream</code>. This method blocks until all image data has
395: * been read and decoded. After this method completes (whether by
396: * returning or by throwing an exception) the stream is left open and its
397: * current position is undefined.
398: *
399: * @param stream the name of the resource containing the image data
400: * in one of the supported image formats
401: *
402: * @return the created image
403: * @throws NullPointerException if <code>stream</code> is <code>null</code>
404: * @throws java.io.IOException if an I/O error occurs, if the image data
405: * cannot be loaded, or if the image data cannot be decoded
406: *
407: */
408: public ImageData createImmutableImageData(InputStream stream)
409: throws IOException {
410:
411: ImageData data = new ImageData();
412: createImageFromStream(data, stream);
413: return data;
414: }
415:
416: /**
417: * Populates an immutable <code>ImageData</code>
418: * from decoded data obtained from an <code>InputStream</code>.
419: * This method blocks until all image data has
420: * been read and decoded. After this method completes (whether by
421: * returning or by throwing an exception) the stream is left open and its
422: * current position is undefined.
423: *
424: * @param data The <code>ImageData</code> to be populated
425: * @param stream the name of the resource containing the image data
426: * in one of the supported image formats
427: *
428: * @throws NullPointerException if <code>stream</code> is <code>null</code>
429: * @throws java.io.IOException if an I/O error occurs, if the image data
430: * cannot be loaded, or if the image data cannot be decoded
431: *
432: */
433: private void createImageFromStream(ImageData data,
434: InputStream stream) throws java.io.IOException {
435:
436: if (stream == null) {
437: throw new java.io.IOException();
438: } else {
439: /*
440: * Allocate an array assuming available is correct.
441: * Only reading an EOF is the real end of file
442: * so allocate an extra byte to read the EOF into.
443: * If available is incorrect, increase the buffer
444: * size and keep reading.
445: */
446: int l = stream.available();
447: byte[] buffer = new byte[l + 1];
448: int length = 0;
449:
450: // TBD: Guard against an implementation with incorrect available
451: while ((l = stream.read(buffer, length, buffer.length
452: - length)) != -1) {
453: length += l;
454: if (length == buffer.length) {
455: byte[] b = new byte[buffer.length + 4096];
456: System.arraycopy(buffer, 0, b, 0, length);
457: buffer = b;
458: }
459: }
460:
461: stream.close();
462:
463: try {
464: decode(data, buffer, 0, length);
465: } catch (IllegalArgumentException e) {
466: throw new java.io.IOException();
467: }
468: }
469: }
470:
471: /**
472: * Load an <code>ImageData</code> from cache. The real work is done in
473: * the native function.
474: *
475: * @param imageData The <code>ImageData</code> to be populated
476: * @param resName Image resource name
477: * @return true if image was loaded and created, false otherwise
478: */
479: private boolean loadCachedImage(ImageData imageData, String resName) {
480: MIDletSuite midletSuite = MIDletStateHandler
481: .getMidletStateHandler().getMIDletSuite();
482: int suiteId = midletSuite.getID();
483:
484: return loadCachedImage0(imageData, suiteId, resName);
485: }
486:
487: /**
488: * Native function to load native image data from cache and populate
489: * an immutable <code>ImageData</code>.
490: * pixelData and alphaData, width and height, will be set
491: * in native upon success.
492: *
493: * @param imageData The <code>ImageData</code> to populate
494: * @param suiteId The suite id
495: * @param resName The image resource name
496: * @return true if image was loaded and created, false otherwise
497: */
498: private native boolean loadCachedImage0(ImageData imageData,
499: int suiteId, String resName);
500:
501: /**
502: * Function to decode an <code>ImageData</code> from PNG data.
503: *
504: * @param imageData the <code>ImageData</code> to be populated
505: * @param imageBytes the array of image data in a supported image format
506: * @param imageOffset the offset of the start of the data in the array
507: * @param imageLength the length of the data in the array
508: */
509: private void decodePNG(ImageData imageData, byte[] imageBytes,
510: int imageOffset, int imageLength) {
511: // find the format of the image data
512: if (imageLength < pngHeader.length + 8) {
513: throw new IllegalArgumentException();
514: }
515:
516: int width = ((imageBytes[imageOffset + 16] & 0x0ff) << 24)
517: + ((imageBytes[imageOffset + 17] & 0x0ff) << 16)
518: + ((imageBytes[imageOffset + 18] & 0x0ff) << 8)
519: + (imageBytes[imageOffset + 19] & 0x0ff);
520:
521: int height = ((imageBytes[imageOffset + 20] & 0x0ff) << 24)
522: + ((imageBytes[imageOffset + 21] & 0x0ff) << 16)
523: + ((imageBytes[imageOffset + 22] & 0x0ff) << 8)
524: + (imageBytes[imageOffset + 23] & 0x0ff);
525:
526: if (width <= 0 || height <= 0) {
527: throw new IllegalArgumentException();
528: }
529:
530: imageData.initImageData(width, height, false, true);
531:
532: // load the decoded PNG data into the data byte arrays
533: if (loadPNG(imageData, imageBytes, imageOffset, imageLength) == false) {
534: // if loadPNG returns false, the image contains
535: // only opaque pixel and the alpha data is not needed
536: imageData.removeAlpha();
537: }
538: }
539:
540: /**
541: * Function to decode an <code>ImageData</code> from JPEG data.
542: *
543: * @param imageData the <code>ImageData</code> to be populated
544: * @param imageBytes the array of image data in a supported image format
545: * @param imageOffset the offset of the start of the data in the array
546: * @param imageLength the length of the data in the array
547: */
548: private void decodeJPEG(ImageData imageData, byte[] imageBytes,
549: int imageOffset, int imageLength) {
550: // find the format of the image data
551: if (imageLength < jpegHeader.length + 8) {
552: throw new IllegalArgumentException();
553: }
554:
555: int width = 0;
556: int height = 0;
557:
558: /**
559: * Find SOF (Start Of Frame) marker:
560: * format of SOF
561: * 2 bytes Marker Identity (0xff 0xc<N>)
562: * 2 bytes Length of block
563: * 1 byte bits/sample
564: * 2 bytes Image Height
565: * 2 bytes Image Width
566: * 1 bytes Number of components
567: * n bytes the components
568: *
569: * Searching for the byte pair representing SOF is unsafe
570: * because a prior marker might contain the SOFn pattern
571: * so we must skip over the preceding markers.
572: *
573: * When editing this code, don't forget to make the appropriate changes
574: * in src/lowlevelui/graphics_util/reference/native/gxutl_image_util.c.
575: */
576: int idx = imageOffset + 2;
577:
578: while (idx + 8 < imageOffset + imageLength) {
579: if (imageBytes[idx] != (byte) 0xff) {
580: break;
581: }
582:
583: if ((byte) (imageBytes[idx + 1] & 0xf0) == (byte) 0xc0) {
584: byte code = imageBytes[idx + 1];
585:
586: if (code != (byte) 0xc4 || code != (byte) 0xcc) {
587: /* Big endian */
588: height = ((imageBytes[idx + 5] & 0xff) << 8)
589: + (imageBytes[idx + 6] & 0xff);
590: width = ((imageBytes[idx + 7] & 0xff) << 8)
591: + (imageBytes[idx + 8] & 0xff);
592: break;
593: }
594: }
595:
596: /* Go to the next marker */
597: int field_len = ((imageBytes[idx + 2] & 0xff) << 8)
598: + (imageBytes[idx + 3] & 0xff);
599: idx += field_len + 2;
600: }
601:
602: if (width <= 0 || height <= 0) {
603: throw new IllegalArgumentException();
604: }
605:
606: imageData.initImageData(width, height, false, false);
607:
608: // load the decoded JPEG data into the pixelData array
609: loadJPEG(imageData, imageBytes, imageOffset, imageLength);
610: }
611:
612: /**
613: * Function to decode an <code>ImageData</code> from RAW data.
614: *
615: * @param imageData the <code>ImageData</code> to be populated
616: * @param imageBytes the array of image data in a supported image format
617: * @param imageOffset the offset of the start of the data in the array
618: * @param imageLength the length of the data in the array
619: */
620: private void decodeRAW(ImageData imageData, byte[] imageBytes,
621: int imageOffset, int imageLength) {
622: // find the format of the image data
623: if (imageLength < rawHeader.length + 8) {
624: throw new IllegalArgumentException();
625: }
626: loadRAW(imageData, imageBytes, imageOffset, imageLength);
627: }
628:
629: /**
630: * Function to compare byte data to the given header
631: *
632: * @param header header data to compare imageData with
633: * @param imageData the array of image data in a supported image format
634: * @param imageOffset the offset of the start of the data in the array
635: * @param imageLength the length of the data in the array
636: * @return true if the header.length bytes at imageData[imageOffset]
637: * are equal to the bytes in header array, false otherwise
638: */
639: private boolean headerMatch(byte[] header, byte[] imageData,
640: int imageOffset, int imageLength) {
641: if (imageLength < header.length) {
642: return false;
643: }
644:
645: for (int i = 0; i < header.length; i++) {
646: if (imageData[imageOffset + i] != header[i]) {
647: return false;
648: }
649: }
650:
651: return true;
652: }
653:
654: /**
655: * Function to decode an <code>ImageData</code> from byte data.
656: *
657: * @param imageData the <code>ImageData<code> to populate
658: * @param imageBytes the array of image data in a supported image format
659: * @param imageOffset the offset of the start of the data in the array
660: * @param imageLength the length of the data in the array
661: * @throws IllegalArgumentException if the data is not formatted correctly
662: */
663: private void decode(ImageData imageData, byte[] imageBytes,
664: int imageOffset, int imageLength) {
665: // check if it is a PNG image
666: if (headerMatch(pngHeader, imageBytes, imageOffset, imageLength)) {
667: // image type is PNG
668: decodePNG(imageData, imageBytes, imageOffset, imageLength);
669: } else if (headerMatch(jpegHeader, imageBytes, imageOffset,
670: imageLength)) {
671: // image type is JPEG
672: decodeJPEG(imageData, imageBytes, imageOffset, imageLength);
673: } else if (headerMatch(rawHeader, imageBytes, imageOffset,
674: imageLength)) {
675: // image type is RAW
676: decodeRAW(imageData, imageBytes, imageOffset, imageLength);
677: } else {
678: // does not match supported image type
679: throw new IllegalArgumentException();
680: }
681: }
682:
683: /**
684: * Native function to load an <code>ImageData</code> from PNG data.
685: *
686: * @param imageData the <code>ImageData</code> to load to
687: * @param imageBytes the array of image data in a supported image format
688: * @param imageOffset the offset of the start of the data in the array
689: * @param imageLength the length of the data in the array
690: *
691: * @return true if there is alpha data
692: */
693: private native boolean loadPNG(ImageData imageData,
694: byte[] imageBytes, int imageOffset, int imageLength);
695:
696: /**
697: * Native function to load an <code>ImageData </code>from JPEG data.
698: *
699: * @param imageData the <code>ImageData</code> to load to
700: * @param imageBytes the array of image data in a supported image format
701: * @param imageOffset the offset of the start of the data in the array
702: * @param imageLength the length of the data in the array
703: */
704: private native void loadJPEG(ImageData imageData,
705: byte[] imageBytes, int imageOffset, int imageLength);
706:
707: /**
708: * Native function to load an <code>ImageData</code>
709: * directly out of the rom image.
710: *
711: * @param data The <code>ImageData</code> to load to
712: * @param imageDataArrayPtr native pointer to image data as Java int
713: * @param imageDataArrayLength length of image data array
714: * @return true if romized image was loaded successfully,
715: * false - otherwise
716: */
717: private native boolean loadRomizedImage(ImageData data,
718: int imageDataArrayPtr, int imageDataArrayLength);
719:
720: /**
721: * Native function to load an <code>ImageData</code> from ARGB data.
722: *
723: * @param imgData The <code>ImageData</code> to load to
724: * @param rgb the array of image data in a ARGB format
725: */
726: private native void loadRGB(ImageData imgData, int[] rgb);
727:
728: /**
729: * Native function to load an <code>ImageData</code> from RAW data.
730: *
731: * @param imgData The <code>ImageData</code> to load to
732: * @param imageBytes the array of image data in a RAW format
733: */
734: private native void loadRAW(ImageData imgData, byte[] imageBytes,
735: int imageOffset, int imageLength);
736:
737: /**
738: * Copy either Java or romized data into another <code>ImageData</code>
739: * from an <code>ImageData</code> region.
740: *
741: * @param dest the <code>ImageData</code> to copy to
742: * @param source the source image to be copied from
743: * @param x the horizontal location of the region to be copied
744: * @param y the vertical location of the region to be copied
745: * @param width the width of the region to be copied
746: * @param height the height of the region to be copied
747: * @param transform the transform to be applied to the region
748: */
749: private native void loadRegion(ImageData dest, ImageData source,
750: int x, int y, int width, int height, int transform);
751: }
|