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: import javax.microedition.lcdui.game.Sprite;
032:
033: /**
034: * The <code>Image</code> class is used to hold graphical image
035: * data. <code>Image</code>
036: * objects exist independently of the display device. They exist only in
037: * off-screen memory and will not be painted on the display unless an explicit
038: * command is issued by the application (such as within the
039: * <code>paint()</code> method of
040: * a <code>Canvas</code>) or when an <code>Image</code> object is
041: * placed within a <code>Form</code> screen or an
042: * <code>Alert</code> screen and that screen is made current.
043: *
044: * <p>Images are either <em>mutable</em> or <em>immutable</em> depending upon
045: * how they are created. Immutable images are generally created by loading
046: * image data from resource bundles, from files, or from the network. They may
047: * not be modified once created. Mutable images are created as blank images
048: * containing only white pixels. The application may render on a mutable image
049: * by calling {@link #getGraphics} on the <code>Image</code> to obtain
050: * a <code>Graphics</code> object
051: * expressly for this purpose.</p>
052: *
053: * <p><code>Images</code> may be placed within <code>Alert</code>,
054: * <code>Choice</code>, <code>Form</code>, or <code>ImageItem</code>
055: * objects.
056: * The high-level user interface implementation may need to update the display
057: * at any time, without notifying the application. In order to provide
058: * predictable behavior, the high-level user interface
059: * objects provide snapshot semantics for the image. That is, when a mutable
060: * image is placed within an <code>Alert</code>, <code>Choice</code>,
061: * <code>Form</code>, or <code>ImageItem</code> object,
062: * the effect is as if a snapshot is taken of its current contents. This
063: * snapshot is then used for all subsequent painting of the high-level user
064: * interface component. If the application modifies the contents of the
065: * image, the application must update the component containing the image (for
066: * example, by calling <code>ImageItem.setImage</code>) in order to
067: * make the modified
068: * contents visible.</p>
069: *
070: * <p>An immutable image may be created from a mutable image through the
071: * use of the {@link #createImage(Image) createImage} method. It is possible
072: * to create a mutable copy of an immutable image using a technique similar
073: * to the following: </p>
074: *
075: * <TABLE BORDER="2">
076: * <TR>
077: * <TD ROWSPAN="1" COLSPAN="1">
078: * <pre><code>
079: * Image source; // the image to be copied
080: * source = Image.createImage(...);
081: * Image copy = Image
082: * .createImage(source.getWidth(), source.getHeight());
083: * Graphics g = copy.getGraphics();
084: * g.drawImage(source, 0, 0, TOP|LEFT); </code></pre>
085: * </TD>
086: * </TR>
087: * </TABLE>
088: * <a name="alpha"></a>
089: * <h3>Alpha Processing</h3>
090: *
091: * <p>Every pixel within a mutable image is always fully opaque. Immutable
092: * images may contain a combination of fully opaque pixels
093: * <code>(alpha = 2<sup><em>bitdepth</em></sup> - 1)</code>, fully
094: * transparent pixels (<code>alpha = 0</code>), and
095: * semitransparent pixels
096: * (<code>0 < alpha <
097: * 2<sup><em>bitdepth</em></sup> - 1</code>),
098: * where <em>bitdepth</em> is the number of bits per sample in the source data.
099: *
100: * <p>Implementations must support storage, processing, and rendering of fully
101: * opaque pixels and fully transparent pixels in immutable images. When
102: * creating an image from source data (whether from a PNG file or from an
103: * array of ARGB data), a fully opaque pixel in the source data must always
104: * result in a fully opaque pixel in the new image, and a fully transparent
105: * pixel in the source data must always result in a fully transparent pixel in
106: * the new image.
107: *
108: * <p>The required treatment of semitransparent pixel data depends upon
109: * whether the implementation supports alpha blending at rendering time. If
110: * the implementation supports alpha blending, a semitransparent pixel in the
111: * source data must result in a semitransparent pixel in the new image. The
112: * resulting alpha value may be modified to accommodate the number of levels
113: * of semitransparency supported by the platform. (See the {@link
114: * Display#numAlphaLevels() Display.numAlphaLevels()} method.) If an
115: * implementation does not support alpha blending, any semitransparent pixels
116: * in the source data must be replaced with fully transparent pixels in the
117: * new image.
118: *
119: * <a name="PNG"></a>
120: * <h3>PNG Image Format</h3>
121: *
122: * <p>Implementations are required to support images stored in the PNG format,
123: * as specified by the <em>PNG (Portable Network Graphics) Specification,
124: * Version 1.0.</em> All conforming MIDP implementations are also conformant
125: * to the minimum set of requirements given by the <em>PNG Specification</em>.
126: * MIDP implementations also must conform to additional requirements given
127: * here with respect to handling of PNG images. Note that the requirements
128: * listed here take precedence over any conflicting recommendations given in
129: * the <em>PNG Specification</em>.</p>
130: *
131: * <h4>Critical Chunks</h4>
132: *
133: * <p>All of the 'critical' chunks specified by PNG must be supported. The
134: * paragraphs below describe these critical chunks.</p>
135: *
136: * <p>The IHDR chunk. MIDP devices must handle the following values in
137: * the IHDR chunk:</p>
138: *
139: * <ul>
140: * <li>All positive values of width and height are supported; however, a
141: * very large image may not be readable because of memory constraints. The
142: * dimensions of the resulting <code>Image</code> object must match
143: * the dimensions of the PNG image. That is, the values returned by
144: * {@link #getWidth() getWidth()} and {@link #getHeight() getHeight()}
145: * and the rendered width and height must
146: * equal the width and height specified in the IHDR chunk.</li>
147: *
148: * <li>All color types are supported, although the appearance of the image will
149: * be dependent on the capabilities of the device's screen. Color types that
150: * include alpha channel data are supported.</li>
151: *
152: * <li> For color types <code>4</code> & <code>6</code> (grayscale
153: * with alpha and RGB with alpha,
154: * respectively) the alpha channel must be decoded. Any pixels with an alpha
155: * value of zero must be treated as transparent. Any pixels with an alpha
156: * value of <code>255</code> (for images with <code>8</code> bits per
157: * sample) or <code>65535</code> (for images with
158: * <code>16</code> bits per sample) must be treated as opaque. If
159: * rendering with alpha
160: * blending is supported, any pixels with intermediate alpha values must be
161: * carried through to the resulting image. If alpha blending is not
162: * supported, any pixels with intermediate alpha values must be replaced with
163: * fully transparent pixels.</li>
164: *
165: * <li>All bit depth values for the given color type are supported.</li>
166: *
167: * <li>Compression method <code>0</code> (deflate) is the only
168: * supported compression method.
169: * This method utilizes the "zlib" compression scheme, which
170: * is also used for
171: * jar files; thus, the decompression (inflate) code may be shared between the
172: * jar decoding and PNG decoding implementations. As noted in the PNG
173: * specification, the compressed data stream may comprised internally of both
174: * compressed and uncompressed (raw) data.
175: * </li>
176: *
177: * <li>The filter method represents a series of encoding schemes that may be
178: * used to optimize compression. The PNG spec currently defines a single
179: * filter method (method <code>0</code>) that is an adaptive filtering
180: * scheme with five
181: * basic filter types. Filtering is essential for optimal compression since it
182: * allows the deflate algorithm to exploit spatial similarities within the
183: * image. Therefore, MIDP devices must support all five filter types defined
184: * by filter method <code>0</code>.</li>
185: *
186: * <li> MIDP devices are required to read PNG images that are encoded with
187: * either interlace method <code>0</code> (None) or interlace method
188: * <code>1</code> (Adam7). Image
189: * loading in MIDP is synchronous and cannot be overlapped with image
190: * rendering, and so there is no advantage for an application to use interlace
191: * method <code>1</code>. Support for decoding interlaced images is
192: * required for
193: * compatibility with PNG and for the convenience of developers who may already
194: * have interlaced images available.</li>
195: *
196: * </ul>
197: *
198: * <p>The PLTE chunk. Palette-based images must be supported.</p>
199: *
200: * <p>The IDAT chunk. Image data may be encoded using any of the
201: * <code>5</code> filter
202: * types defined by filter method <code>0</code> (None, Sub, Up,
203: * Average, Paeth).</p>
204: *
205: * <p>The IEND chunk. This chunk must be found in order for the image to be
206: * considered valid.</p>
207: *
208: * <h4>Ancillary Chunks</h4>
209: *
210: * <p>PNG defines several 'ancillary' chunks that may be present in a
211: * PNG image but are not critical for image decoding.</p>
212: *
213: * <p>The tRNS chunk. All implementations must support the tRNS chunk.
214: * This chunk is used to implement transparency without providing alpha
215: * channel data for each pixel. For color types <code>0</code> and
216: * <code>2</code>, a particular
217: * gray or RGB value is defined to be a transparent pixel. In this case, the
218: * implementation must treat pixels with this value as fully transparent.
219: * Pixel value comparison must be based on the actual pixel values using the
220: * original sample depth; that is, this comparison must be performed before
221: * the pixel values are resampled to reflect the display capabilities
222: * of the device. For color type <code>3</code> (indexed color),
223: * <code>8</code>-bit alpha values are
224: * potentially provided for each entry in the color palette. In this case,
225: * the implementation must treat pixels with an alpha value of
226: * <code>0</code> as fully
227: * transparent, and it must treat pixels with an alpha value of
228: * <code>255</code> as fully
229: * opaque. If rendering with alpha blending is supported, any pixels with
230: * intermediate alpha values must be carried through to the resulting image.
231: * If alpha blending is not supported, any pixels with intermediate alpha
232: * values must be replaced with fully transparent pixels.</p>
233: *
234: * <p>The implementation <em>may</em> (but is not required to) support
235: * any of the other ancillary chunks. The implementation <em>must</em>
236: * silently ignore any unsupported ancillary chunks that it encounters.
237: * The currently defined optional ancillary chunks are:</p>
238: *
239: * <PRE>
240: * cHRM gAMA hIST iCCP iTXt pHYs
241: * sBIT sPLT sRGB tEXt tIME zTXt </PRE>
242: *
243: * <h3>Reference</h3>
244: *
245: * <p><em>PNG (Portable Network Graphics) Specification, Version 1.0.</em>
246: * W3C Recommendation, October 1, 1996. http://www.w3.org/TR/REC-png.html.
247: * Also available as RFC 2083, http://www.ietf.org/rfc/rfc2083.txt.</p>
248: * @since MIDP 1.0
249: */
250:
251: public class Image {
252: /**
253: * Width of the image in pixels.
254: */
255: private int width;
256:
257: /**
258: * Height of the image in pixels.
259: */
260: private int height;
261:
262: /**
263: * <code>ImageData</code> instance associated with this <code>Image</code>.
264: */
265: private ImageData imageData;
266:
267: /**
268: * Valid transforms possible are 0 - 7
269: */
270: static final int INVALID_TRANSFORM_BITS = 0xFFFFFFF8;
271:
272: /**
273: * Transform swap axis bit is the 3 bit
274: */
275: static final int TRANSFORM_SWAP_AXIS = 4;
276:
277: /**
278: * Creates a new, mutable image for off-screen drawing. Every pixel
279: * within the newly created image is white. The width and height of the
280: * image must both be greater than zero.
281: *
282: * @param width the width of the new image, in pixels
283: * @param height the height of the new image, in pixels
284: * @return the created image
285: *
286: * @throws IllegalArgumentException if either <code>width</code> or
287: * <code>height</code> is zero or less
288: */
289: public static Image createImage(int width, int height) {
290: if (width <= 0 || height <= 0) {
291: throw new IllegalArgumentException();
292: }
293:
294: // SYNC NOTE: Not accessing any shared data, no locking necessary
295: return new Image(ImageDataFactory.getImageDataFactory()
296: .createOffScreenImageData(width, height));
297: }
298:
299: /**
300: * Creates an immutable image from a source image.
301: * If the source image is mutable, an immutable copy is created and
302: * returned. If the source image is immutable, the implementation may
303: * simply return it without creating a new image. If an immutable source
304: * image contains transparency information, this information is copied to
305: * the new image unchanged.
306: *
307: * <p> This method is useful for placing the contents of mutable images
308: * into <code>Choice</code> objects. The application can create
309: * an off-screen image
310: * using the
311: * {@link #createImage(int, int) createImage(w, h)}
312: * method, draw into it using a <code>Graphics</code> object
313: * obtained with the
314: * {@link #getGraphics() getGraphics()}
315: * method, and then create an immutable copy of it with this method.
316: * The immutable copy may then be placed into <code>Choice</code>
317: * objects. </p>
318: *
319: * @param source the source image to be copied
320: * @return the new, immutable image
321: *
322: * @throws NullPointerException if <code>source</code> is <code>null</code>
323: */
324: public static Image createImage(Image source) {
325: // SYNC NOTE: Not accessing any shared data, no locking necessary
326: if (source.isMutable()) {
327: return new Image(ImageDataFactory.getImageDataFactory()
328: .createImmutableCopy(source.imageData));
329: } else {
330: return source;
331: }
332: }
333:
334: /**
335: * Creates an immutable image from decoded image data obtained from the
336: * named resource. The name parameter is a resource name as defined by
337: * {@link Class#getResourceAsStream(String)
338: * Class.getResourceAsStream(name)}. The rules for resolving resource
339: * names are defined in the
340: * <a href="../../../java/lang/package-summary.html">
341: * Application Resource Files</a> section of the
342: * <code>java.lang</code> package documentation.
343: *
344: * @param name the name of the resource containing the image data in one of
345: * the supported image formats
346: * @return the created image
347: * @throws NullPointerException if <code>name</code> is <code>null</code>
348: * @throws java.io.IOException if the resource does not exist,
349: * the data cannot
350: * be loaded, or the image data cannot be decoded
351: */
352: public static Image createImage(java.lang.String name)
353: throws java.io.IOException {
354: return new Image(ImageDataFactory.getImageDataFactory()
355: .createResourceImageData(name));
356: }
357:
358: /**
359: * Creates an immutable image which is decoded from the data stored in
360: * the specified byte array at the specified offset and length. The data
361: * must be in a self-identifying image file format supported by the
362: * implementation, such as <a href="#PNG">PNG</A>.
363: *
364: * <p>The <code>imageoffset</code> and <code>imagelength</code>
365: * parameters specify a range of
366: * data within the <code>imageData</code> byte array. The
367: * <code>imageOffset</code> parameter
368: * specifies the
369: * offset into the array of the first data byte to be used. It must
370: * therefore lie within the range
371: * <code>[0..(imageData.length-1)]</code>. The
372: * <code>imageLength</code>
373: * parameter specifies the number of data bytes to be used. It must be a
374: * positive integer and it must not cause the range to extend beyond
375: * the end
376: * of the array. That is, it must be true that
377: * <code>imageOffset + imageLength < imageData.length</code>. </p>
378: *
379: * <p> This method is intended for use when loading an
380: * image from a variety of sources, such as from
381: * persistent storage or from the network.</p>
382: *
383: * @param imageData the array of image data in a supported image format
384: * @param imageOffset the offset of the start of the data in the array
385: * @param imageLength the length of the data in the array
386: *
387: * @return the created image
388: * @throws ArrayIndexOutOfBoundsException if <code>imageOffset</code>
389: * and <code>imageLength</code>
390: * specify an invalid range
391: * @throws NullPointerException if <code>imageData</code> is
392: * <code>null</code>
393: * @throws IllegalArgumentException if <code>imageData</code> is incorrectly
394: * formatted or otherwise cannot be decoded
395: */
396: public static Image createImage(byte[] imageData, int imageOffset,
397: int imageLength) {
398:
399: if (imageOffset < 0 || imageOffset >= imageData.length
400: || imageLength < 0
401: || imageOffset + imageLength > imageData.length) {
402: throw new ArrayIndexOutOfBoundsException();
403: }
404:
405: return new Image(ImageDataFactory.getImageDataFactory()
406: .createImmutableImageData(imageData, imageOffset,
407: imageLength));
408: }
409:
410: /**
411: * Creates an immutable image using pixel data from the specified
412: * region of a source image, transformed as specified.
413: *
414: * <p>The source image may be mutable or immutable. For immutable source
415: * images, transparency information, if any, is copied to the new
416: * image unchanged.</p>
417: *
418: * <p>On some devices, pre-transformed images may render more quickly
419: * than images that are transformed on the fly using
420: * <code>drawRegion</code>.
421: * However, creating such images does consume additional heap space,
422: * so this technique should be applied only to images whose rendering
423: * speed is critical.</p>
424: *
425: * <p>The transform function used must be one of the following, as defined
426: * in the {@link javax.microedition.lcdui.game.Sprite Sprite} class:<br>
427: *
428: * <code>Sprite.TRANS_NONE</code> - causes the specified image
429: * region to be copied unchanged<br>
430: * <code>Sprite.TRANS_ROT90</code> - causes the specified image
431: * region to be rotated clockwise by 90 degrees.<br>
432: * <code>Sprite.TRANS_ROT180</code> - causes the specified image
433: * region to be rotated clockwise by 180 degrees.<br>
434: * <code>Sprite.TRANS_ROT270</code> - causes the specified image
435: * region to be rotated clockwise by 270 degrees.<br>
436: * <code>Sprite.TRANS_MIRROR</code> - causes the specified image
437: * region to be reflected about its vertical center.<br>
438: * <code>Sprite.TRANS_MIRROR_ROT90</code> - causes the specified image
439: * region to be reflected about its vertical center and then rotated
440: * clockwise by 90 degrees.<br>
441: * <code>Sprite.TRANS_MIRROR_ROT180</code> - causes the specified image
442: * region to be reflected about its vertical center and then rotated
443: * clockwise by 180 degrees.<br>
444: * <code>Sprite.TRANS_MIRROR_ROT270</code> - causes the specified image
445: * region to be reflected about its vertical center and then rotated
446: * clockwise by 270 degrees.<br></p>
447: *
448: * <p>
449: * The size of the returned image will be the size of the specified region
450: * with the transform applied. For example, if the region is
451: * <code>100 x 50</code> pixels and the transform is
452: * <code>TRANS_ROT90</code>, the
453: * returned image will be <code>50 x 100</code> pixels.</p>
454: *
455: * <p><strong>Note:</strong> If all of the following conditions
456: * are met, this method may
457: * simply return the source <code>Image</code> without creating a
458: * new one:</p>
459: * <ul>
460: * <li>the source image is immutable;</li>
461: * <li>the region represents the entire source image; and</li>
462: * <li>the transform is <code>TRANS_NONE</code>.</li>
463: * </ul>
464: *
465: * @param image the source image to be copied from
466: * @param x the horizontal location of the region to be copied
467: * @param y the vertical location of the region to be copied
468: * @param width the width of the region to be copied
469: * @param height the height of the region to be copied
470: * @param transform the transform to be applied to the region
471: * @return the new, immutable image
472: *
473: * @throws NullPointerException if <code>image</code> is <code>null</code>
474: * @throws IllegalArgumentException if the region to be copied exceeds
475: * the bounds of the source image
476: * @throws IllegalArgumentException if either <code>width</code> or
477: * <code>height</code> is zero or less
478: * @throws IllegalArgumentException if the <code>transform</code>
479: * is not valid
480: *
481: */
482: public static Image createImage(Image image, int x, int y,
483: int width, int height, int transform) {
484:
485: if ((transform & INVALID_TRANSFORM_BITS) != 0) {
486: throw new IllegalArgumentException();
487: }
488:
489: if (x < 0 || y < 0 || (x + width) > image.getWidth()
490: || // throws NPE if image is null
491: (y + height) > image.getHeight() || width <= 0
492: || height <= 0) {
493: throw new IllegalArgumentException();
494: }
495:
496: if (x == 0 && y == 0 && width == image.getWidth()
497: && height == image.getHeight()
498: && transform == Sprite.TRANS_NONE) {
499: return createImage(image);
500: } else {
501: return new Image(ImageDataFactory.getImageDataFactory()
502: .createImmutableImageData(image.imageData, x, y,
503: width, height, transform));
504: }
505: }
506:
507: /**
508: * Creates an immutable image from decoded image data obtained froH an
509: * <code>InputStream</code>. This method blocks until all image data has
510: * been read and decoded. After this method completes (whether by
511: * returning or by throwing an exception) the stream is left open and its
512: * current position is undefined.
513: *
514: * @param stream the name of the resource containing the image data
515: * in one of the supported image formats
516: *
517: * @return the created image
518: * @throws NullPointerException if <code>stream</code> is <code>null</code>
519: * @throws java.io.IOException if an I/O error occurs, if the image data
520: * cannot be loaded, or if the image data cannot be decoded
521: *
522: */
523: public static Image createImage(InputStream stream)
524: throws java.io.IOException {
525:
526: if (stream == null) {
527: throw new java.lang.NullPointerException();
528: }
529:
530: try {
531: return new Image(ImageDataFactory.getImageDataFactory()
532: .createImmutableImageData(stream));
533: } catch (IllegalArgumentException e) {
534: throw new java.io.IOException();
535: }
536: }
537:
538: /**
539: * Creates an immutable image from a sequence of ARGB values, specified
540: * as <code>0xAARRGGBB</code>.
541: * The ARGB data within the <code>rgb</code> array is arranged
542: * horizontally from left to right within each row,
543: * row by row from top to bottom.
544: * If <code>processAlpha</code> is <code>true</code>,
545: * the high-order byte specifies opacity; that is,
546: * <code>0x00RRGGBB</code> specifies
547: * a fully transparent pixel and <code>0xFFRRGGBB</code> specifies
548: * a fully opaque
549: * pixel. Intermediate alpha values specify semitransparency. If the
550: * implementation does not support alpha blending for image rendering
551: * operations, it must replace any semitransparent pixels with fully
552: * transparent pixels. (See <a href="#alpha">Alpha Processing</a>
553: * for further discussion.) If <code>processAlpha</code> is
554: * <code>false</code>, the alpha values
555: * are ignored and all pixels must be treated as fully opaque.
556: *
557: * <p>Consider <code>P(a,b)</code> to be the value of the pixel
558: * located at column <code>a</code> and row <code>b</code> of the
559: * Image, where rows and columns are numbered downward from the
560: * top starting at zero, and columns are numbered rightward from
561: * the left starting at zero. This operation can then be defined
562: * as:</p>
563: *
564: * <TABLE BORDER="2">
565: * <TR>
566: * <TD ROWSPAN="1" COLSPAN="1">
567: * <pre><code>
568: * P(a, b) = rgb[a + b * width]; </code></pre>
569: * </TD>
570: * </TR>
571: * </TABLE>
572: * <p>for</p>
573: *
574: * <TABLE BORDER="2">
575: * <TR>
576: * <TD ROWSPAN="1" COLSPAN="1">
577: * <pre><code>
578: * 0 <= a < width
579: * 0 <= b < height </code></pre>
580: * </TD>
581: * </TR>
582: * </TABLE>
583: * <p> </p>
584: *
585: * @param rgb an array of ARGB values that composes the image
586: * @param width the width of the image
587: * @param height the height of the image
588: * @param processAlpha <code>true</code> if <code>rgb</code>
589: * has an alpha channel,
590: * <code>false</code> if all pixels are fully opaque
591: * @return the created image
592: * @throws NullPointerException if <code>rgb</code> is <code>null</code>.
593: * @throws IllegalArgumentException if either <code>width</code> or
594: * <code>height</code> is zero or less
595: * @throws ArrayIndexOutOfBoundsException if the length of
596: * <code>rgb</code> is
597: * less than<code> width * height</code>.
598: *
599: */
600: public static Image createRGBImage(int rgb[], int width,
601: int height, boolean processAlpha) {
602:
603: if (width <= 0 || height <= 0) {
604: throw new IllegalArgumentException();
605: }
606:
607: if ((width * height) > rgb.length) {
608: throw new ArrayIndexOutOfBoundsException();
609: }
610:
611: return new Image(ImageDataFactory.getImageDataFactory()
612: .createImmutableImageData(rgb, width, height,
613: processAlpha));
614: }
615:
616: /**
617: * Creates a new <code>Graphics</code> object that renders to this
618: * image. This image
619: * must be
620: * mutable; it is illegal to call this method on an immutable image.
621: * The mutability of an image may be tested
622: * with the <code>isMutable()</code> method.
623: *
624: * <P>The newly created <code>Graphics</code> object has the
625: * following properties:
626: * </P>
627: * <UL>
628: * <LI>the destination is this <code>Image</code> object;</LI>
629: * <LI>the clip region encompasses the entire <code>Image</code>;</LI>
630: * <LI>the current color is black;</LI>
631: * <LI>the font is the same as the font returned by
632: * {@link Font#getDefaultFont() Font.getDefaultFont()};</LI>
633: * <LI>the stroke style is {@link Graphics#SOLID SOLID}; and
634: * </LI>
635: * <LI>the origin of the coordinate system is located at the upper-left
636: * corner of the Image.</LI>
637: * </UL>
638: *
639: * <P>The lifetime of <code>Graphics</code> objects created using
640: * this method is
641: * indefinite. They may be used at any time, by any thread.</P>
642: *
643: * @return a <code>Graphics</code> object with this image as its destination
644: * @throws IllegalStateException if the image is immutable
645: */
646: public Graphics getGraphics() {
647: if (isMutable()) {
648: // SYNC NOTE: no locking necessary as getGraphics() only allocates
649: // a new object
650: return Graphics.getImageGraphics(this );
651: } else {
652: // SYNC NOTE: Not accessing any shared data, no locking necessary
653: throw new IllegalStateException();
654: }
655: }
656:
657: /**
658: * Gets the width of the image in pixels. The value returned
659: * must reflect the actual width of the image when rendered.
660: * @return width of the image
661: */
662: public int getWidth() {
663: return width;
664: }
665:
666: /**
667: * Gets the height of the image in pixels. The value returned
668: * must reflect the actual height of the image when rendered.
669: * @return height of the image
670: */
671: public int getHeight() {
672: return height;
673: }
674:
675: /**
676: * Check if this image is mutable. Mutable images can be modified by
677: * rendering to them through a <code>Graphics</code> object
678: * obtained from the
679: * <code>getGraphics()</code> method of this object.
680: * @return <code>true</code> if the image is mutable,
681: * <code>false</code> otherwise
682: */
683: public boolean isMutable() {
684: return imageData.isMutable();
685: }
686:
687: // JAVADOC COMMENT ELIDED
688: public native void getRGB(int[] rgbData, int offset,
689: int scanlength, int x, int y, int width, int height);
690:
691: /**
692: * Returns <code>ImageData</code> associated with this
693: * <code>Image</code>.
694: *
695: * @return The <code>ImageData </code> associated with this
696: * <code>Image</code>.
697: */
698: ImageData getImageData() {
699: return imageData;
700: }
701:
702: /**
703: * Renders this Image onto the provided Graphics object.
704: *
705: * @param g the Graphics object to be rendered upon
706: * @param x the x coordinate of the anchor point
707: * @param y the y coordinate of the anchor point
708: * @param anchor the anchor point for positioning the image
709: * @return false if <code>anchor</code> is not a legal value
710: *
711: * @see Graphics
712: */
713: native boolean render(Graphics g, int x, int y, int anchor);
714:
715: /**
716: * Renders the specified region onto the provided Graphics object.
717: * ImmutableImage overrides this method so that the native
718: * implementation handles this appropriately.
719: *
720: * @param g the Graphics object to be rendered upon
721: * @param x_src the x coordinate of the upper left corner of the region
722: * within the source image to copy
723: * @param y_src the y coordinate of the upper left corner of the region
724: * within the source image to copy
725: * @param width the width of the region to copy
726: * @param height the height of the region to copy
727: * @param transform the desired transformation for the selected region
728: * being copied
729: * @param x_dest the x coordinate of the anchor point in the
730: * destination drawing area
731: * @param y_dest the y coordinate of the anchor point in the
732: * destination drawing area
733: * @param anchor the anchor point for positioning the region within
734: * the destination image
735: *
736: * @return false if <code>src</code> is the same image as the
737: * destination of this <code>Graphics</code> object,
738: * or <code>transform</code> is invalid,
739: * or <code>anchor</code> is invalid,
740: * or the region to be copied exceeds the bounds of the source image.
741: *
742: * @see Graphics
743: */
744: native boolean renderRegion(Graphics g, int x_src, int y_src,
745: int width, int height, int transform, int x_dest,
746: int y_dest, int anchor);
747:
748: /**
749: * Function to load an romized Image.
750: *
751: * @param imageDataArrayPtr native pointer to image data as Java int
752: * @param imageDataArrayLength length of image data array
753: * @return image created. Null if no romized image matches the id.
754: */
755: static Image getRomizedImage(int imageDataArrayPtr,
756: int imageDataArrayLength) {
757:
758: try {
759: AbstractImageDataFactory f = ImageDataFactory
760: .getImageDataFactory();
761: ImageData data = f.createImmutableImageData(
762: imageDataArrayPtr, imageDataArrayLength);
763: return new Image(data);
764: } catch (IllegalArgumentException iae) {
765: return null;
766: }
767: }
768:
769: /**
770: * Creates an Immutable image from the given ImageData.
771: * @param imageData <code>ImageData</code> instance to be used to
772: * create new Image
773: */
774: private Image(ImageData imageData) {
775: this .imageData = imageData;
776: this .width = imageData.getWidth();
777: this .height = imageData.getHeight();
778: }
779:
780: /**
781: * Resize Image optionally saving its content clipped according
782: * to the new geometry
783: *
784: * @param width new width of the Image
785: * @param height new height of the Image
786: * @param keepContent keep current content of the image
787: * binded to the (0, 0) of the resized image and clipped
788: * according to the new image dimensions
789: */
790: void resize(int width, int height, boolean keepContent) {
791: if (!imageData.isMutable() || width <= 0 || height <= 0) {
792: throw new IllegalArgumentException();
793: }
794:
795: // IMPL_NOTE: In the case content is not kept it is possible
796: // to resize the image more efficiently, especially for the
797: // case of rotation, when the memory reallocation is not needed.
798: // However, now there are no scenarios when resize is needed
799: // without content saving.
800: Image newImage = createImage(width, height);
801: synchronized (this ) {
802: if (keepContent) {
803: render(Graphics.getImageGraphics(newImage), 0, 0,
804: Graphics.TOP | Graphics.LEFT);
805: }
806: this.width = width;
807: this.height = height;
808: imageData = newImage.getImageData();
809: }
810: }
811:
812: }
|