Image.java
上传用户:haobig99
上传日期:2022-06-15
资源大小:369k
文件大小:33k
源码类别:

J2ME

开发平台:

Java

  1. /*
  2.  * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
  3.  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4.  *
  5.  * This code is free software; you can redistribute it and/or modify it
  6.  * under the terms of the GNU General Public License version 2 only, as
  7.  * published by the Free Software Foundation.  Sun designates this
  8.  * particular file as subject to the "Classpath" exception as provided
  9.  * by Sun in the LICENSE file that accompanied this code.
  10.  *
  11.  * This code is distributed in the hope that it will be useful, but WITHOUT
  12.  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13.  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14.  * version 2 for more details (a copy is included in the LICENSE file that
  15.  * accompanied this code).
  16.  *
  17.  * You should have received a copy of the GNU General Public License version
  18.  * 2 along with this work; if not, write to the Free Software Foundation,
  19.  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20.  *
  21.  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22.  * CA 95054 USA or visit www.sun.com if you need additional information or
  23.  * have any questions.
  24.  */
  25. package com.sun.lwuit;
  26. import com.sun.lwuit.geom.Dimension;
  27. import com.sun.lwuit.impl.LWUITImplementation;
  28. import java.io.IOException;
  29. import java.io.InputStream;
  30. import java.lang.ref.WeakReference;
  31. import java.util.Hashtable;
  32. /**
  33.  * Abstracts the underlying platform images allowing us to treat them as a uniform
  34.  * object.
  35.  * 
  36.  * @author Chen Fishbein
  37.  */
  38. public class Image {
  39.     private WeakReference rgbCache;
  40.     private Object image;   
  41.     int transform;
  42.     private boolean opaqueTested = false;
  43.     private boolean opaque;
  44.     private WeakReference scaleCache;
  45.     private boolean animated = false;
  46.     private long imageTime = -1;
  47.     private boolean svg;
  48.     
  49.     /** Creates a new instance of ImageImpl */
  50.     Image(Object image) {
  51.         this.image = image;
  52.     }
  53.     /** Creates a new instance of ImageImpl */
  54.     Image(int[] imageArray, int w, int h) {
  55.         this(Display.getInstance().getImplementation().createImage(imageArray, w, h));
  56.     }
  57.     
  58.     private Hashtable getScaleCache() {
  59.         if(scaleCache == null) {
  60.             Hashtable h = new Hashtable();
  61.             scaleCache = new WeakReference(h);
  62.             return h;
  63.         }
  64.         Hashtable h = (Hashtable)scaleCache.get();
  65.         if(h == null) {
  66.             h = new Hashtable();
  67.             scaleCache = new WeakReference(h);
  68.         }
  69.         return h;
  70.     }
  71.     /**
  72.      * Returns a cached scaled image
  73.      *
  74.      * @param size the size of the cached image
  75.      * @return cached image
  76.      */
  77.     Image getCachedImage(Dimension size) {
  78.         WeakReference w = (WeakReference)getScaleCache().get(size);
  79.         if(w != null) {
  80.             return (Image)w.get();
  81.         }
  82.         return null;
  83.     } 
  84.     
  85.     /**
  86.      * Returns a cached scaled image
  87.      * 
  88.      * @param size the size of the cached image
  89.      * @return cached image
  90.      */
  91.     void cacheImage(Dimension size, Image i) {
  92.         WeakReference w = new WeakReference(i);
  93.         getScaleCache().put(size, w);
  94.     }
  95.     void setImage(Object image) {
  96.         this.image = image;
  97.     }
  98.     void setOpaque(boolean opaque) {
  99.         this.opaque = opaque;
  100.         opaqueTested = true;
  101.     }
  102.     
  103.     /**
  104.      * Indicates whether the underlying platform supports creating an SVG Image
  105.      *
  106.      * @return true if the method create SVG image would return a valid image object
  107.      * from an SVG Input stream
  108.      */
  109.     public static boolean isSVGSupported() {
  110.         return Display.getInstance().getImplementation().isSVGSupported();
  111.     }
  112.     /**
  113.      * Returns a platform specific DOM object that can be manipulated by the user
  114.      * to change the SVG Image
  115.      *
  116.      * @return Platform dependent object, when JSR 226 is supported an SVGSVGElement might
  117.      * be returned.
  118.      */
  119.     public Object getSVGDocument() {
  120.         return Display.getInstance().getImplementation().getSVGDocument(image);
  121.     }
  122.     /**
  123.      * Creates an SVG Image from the given byte array data and the base URL, this method
  124.      * will throw an exception if SVG is unsupported.
  125.      *
  126.      * @param baseURL URL which is used to resolve relative references within the SVG file
  127.      * @param animated indicates if the SVG features an animation
  128.      * @param data the conten of the SVG file
  129.      * @return an image object that can be used as any other image object.
  130.      * @throws IOException if resource lookup fail SVG is unsupported
  131.      */
  132.     public static Image createSVG(String baseURL, boolean animated, byte[] data) throws IOException {
  133.         Image i = new Image(Display.getInstance().getImplementation().createSVGImage(baseURL, data));
  134.         i.animated = animated;
  135.         i.svg = true;
  136.         return i;
  137.     }
  138.     /**
  139.      * Indicates if this image represents an SVG file or a bitmap file
  140.      *
  141.      * @return true if this is an SVG file
  142.      */
  143.     public boolean isSVG() {
  144.         return svg;
  145.     }
  146.     /**
  147.      * Creates a mask from the given image, a mask can be used to apply an arbitrary
  148.      * alpha channel to any image. A mask is derived from the blue channel (LSB) of
  149.      * the given image.
  150.      * The generated mask can be used with the apply mask method.
  151.      * 
  152.      * @return mask object that can be used with applyMask
  153.      */
  154.     public Object createMask() {
  155.         int[] rgb = getRGBCached();
  156.         byte[] mask = new byte[rgb.length];
  157.         for(int iter = 0 ; iter < rgb.length ; iter++) {
  158.             mask[iter] = (byte)(rgb[iter] & 0xff);
  159.         }
  160.         return new IndexedImage(getWidth(), getHeight(), null, mask);
  161.     }
  162.     /**
  163.      * Applies the given alpha mask onto this image and returns the resulting image
  164.      * see the createMask method for indication on how to convert an image into an alpha
  165.      * mask.
  166.      * 
  167.      * @param mask mask object created by the createMask() method.
  168.      * @param x starting x where to apply the mask
  169.      * @param y starting y where to apply the mask
  170.      * @return image masked based on the given object
  171.      */
  172.     public Image applyMask(Object mask, int x, int y) {
  173.         int[] rgb = getRGB();
  174.         byte[] maskData = ((IndexedImage)mask).getImageDataByte();
  175.         int mWidth = ((IndexedImage)mask).getWidth();
  176.         int mHeight = ((IndexedImage)mask).getHeight();
  177.         int imgWidth = getWidth();
  178.         int aWidth =  imgWidth - x;
  179.         int aHeight = getHeight() - y;
  180.         if(aWidth > mWidth) {
  181.             aWidth = mWidth;
  182.         }
  183.         if(aHeight > mHeight) {
  184.             aHeight = mHeight;
  185.         }
  186.         for(int xPos = 0 ; xPos < aWidth ; xPos++) {
  187.             for(int yPos = 0 ; yPos < aHeight ; yPos++) {
  188.                 int aX = x + xPos;
  189.                 int aY = y + yPos;
  190.                 int imagePos = aX + aY * imgWidth;
  191.                 int maskAlpha = maskData[aX + aY * mWidth] & 0xff;
  192.                 maskAlpha = (maskAlpha << 24) & 0xff000000;
  193.                 rgb[imagePos] = (rgb[imagePos] & 0xffffff) | maskAlpha;
  194.             }
  195.         }
  196.         return createImage(rgb, imgWidth, getHeight());
  197.     }
  198.     /**
  199.      * Applies the given alpha mask onto this image and returns the resulting image
  200.      * see the createMask method for indication on how to convert an image into an alpha
  201.      * mask.
  202.      *
  203.      * @param mask mask object created by the createMask() method.
  204.      * @return image masked based on the given object
  205.      * @throws IllegalArgumentException if the image size doesn't match the mask size
  206.      */
  207.     public Image applyMask(Object mask) {
  208.         int[] rgb = getRGB();
  209.         byte[] maskData = ((IndexedImage)mask).getImageDataByte();
  210.         int mWidth = ((IndexedImage)mask).getWidth();
  211.         int mHeight = ((IndexedImage)mask).getHeight();
  212.         if(mWidth != getWidth() || mHeight != getHeight()) {
  213.             throw new IllegalArgumentException("Mask and image sizes don't match");
  214.         }
  215.         for(int iter = 0 ; iter < maskData.length ; iter++) {
  216.             int maskAlpha = maskData[iter] & 0xff;
  217.             maskAlpha = (maskAlpha << 24) & 0xff000000;
  218.             rgb[iter] = (rgb[iter] & 0xffffff) | maskAlpha;
  219.         }
  220.         return createImage(rgb, mWidth, mHeight);
  221.     }
  222.     /**
  223.      * Extracts a subimage from the given image allowing us to breakdown a single large image
  224.      * into multiple smaller images in RAM, this actually creates a standalone version
  225.      * of the image for use. 
  226.      * 
  227.      * @param x the x offset from the image
  228.      * @param y the y offset from the image
  229.      * @param width the width of internal images
  230.      * @param height the height of internal images
  231.      * @param processAlpha whether alpha should be processed as well as part of the cutting
  232.      * @return An array of all the possible images that can be created from the source
  233.      */
  234.     public Image subImage(int x, int y, int width, int height, boolean processAlpha)  {
  235.         // we use the getRGB API rather than the mutable image API to allow translucency to
  236.         // be maintained in the newly created image
  237.         int[] arr = new int[width * height];
  238.         getRGB(arr, 0, x, y, width, height);
  239.         
  240.         Image i = new Image(Display.getInstance().getImplementation().createImage(arr, width, height));
  241.         i.opaque = opaque;
  242.         i.opaqueTested = opaqueTested;
  243.         return i;
  244.     }
  245.     
  246.     /**
  247.      * Returns an instance of this image rotated by the given number of degrees. By default 90 degree
  248.      * angle divisions are supported, anything else is implementation dependent. This method assumes 
  249.      * a square image. Notice that it is inefficient in the current implementation to rotate to
  250.      * non-square angles, 
  251.      * <p>E.g. rotating an image to 45, 90 and 135 degrees is inefficient. Use rotatate to 45, 90
  252.      * and then rotate the 45 to another 90 degrees to achieve the same effect with less memory.
  253.      * 
  254.      * @param degrees A degree in right angle must be larger than 0 and up to 359 degrees
  255.      * @return new image instance with the closest possible rotation
  256.      */
  257.     public Image rotate(int degrees) {
  258.         LWUITImplementation i = Display.getInstance().getImplementation();
  259.         if(i.isRotationDrawingSupported()) {
  260.             if(degrees >= 90) {
  261.                 int newTransform = 0;
  262.                 if(transform != 0) {
  263.                     newTransform = (transform + degrees) % 360;
  264.                 } else {
  265.                     newTransform = degrees % 360;
  266.                 }
  267.                 degrees %= 90;
  268.                 newTransform -= degrees;
  269.                 if(degrees != 0) {
  270.                     Image newImage = new Image(Display.getInstance().getImplementation().rotate(image, degrees));
  271.                     newImage.transform = newTransform;
  272.                     return newImage;
  273.                 } else {
  274.                     Image newImage = new Image(image);
  275.                     newImage.transform = newTransform;
  276.                     return newImage;
  277.                 }
  278.             }
  279.             if(degrees != 0) {
  280.                 return new Image(Display.getInstance().getImplementation().rotate(image, degrees));
  281.             } 
  282.             return this;
  283.         } else {
  284.             return new Image(Display.getInstance().getImplementation().rotate(image, degrees));
  285.         }
  286.     }
  287.     /**
  288.      * Creates an indexed image with byte data this method may return a native indexed image rather than
  289.      * an instance of the IndexedImage class
  290.      * 
  291.      * @param width image width
  292.      * @param height image height
  293.      * @param palette the color palette to use with the byte data
  294.      * @param data byte data containing palette offsets to map to ARGB colors
  295.      */
  296.     public static Image createIndexed(int width, int height, int[] palette, byte[] data) {
  297.         IndexedImage i = new IndexedImage(width, height, palette, data);
  298.         LWUITImplementation impl = Display.getInstance().getImplementation();
  299.         if(impl.isNativeIndexed()) {
  300.             return new Image(impl.createNativeIndexed(i));
  301.         }
  302.         return i;
  303.     }
  304.     
  305.     /**
  306.      * Creates a new image instance with the alpha channel of opaque/translucent 
  307.      * pixels within the image using the new alpha value. Transparent (alpha == 0)
  308.      * pixels remain transparent. All other pixels will have the new alpha value.
  309.      * 
  310.      * @param alpha New value for the entire alpha channel
  311.      * @return Translucent/Opaque image based on the alpha value and the pixels of 
  312.      * this image
  313.      */
  314.     public Image modifyAlpha(byte alpha) {
  315.         int w = getWidth();
  316.         int h = getHeight();
  317.         int size = w * h;
  318.         int[] arr = getRGB();
  319.         int alphaInt = (((int)alpha) << 24) & 0xff000000;
  320.         for(int iter = 0 ; iter < size ; iter++) {
  321.             int currentAlpha = (arr[iter] >> 24) & 0xff;
  322.             if(currentAlpha != 0) {
  323.                 arr[iter] = (arr[iter] & 0xffffff) | alphaInt;
  324.             }
  325.         }
  326.         Image i = new Image(arr, w, h);
  327.         i.opaqueTested = true;
  328.         i.opaque = false;
  329.         return i;
  330.     }
  331.     
  332.     /**
  333.      * Creates a new image instance with the alpha channel of opaque
  334.      * pixels within the image using the new alpha value. Transparent (alpha == 0)
  335.      * pixels remain transparent. Semi translucent pixels will be multiplied by the
  336.      * ratio difference and their translucency reduced appropriately.
  337.      *
  338.      * @param alpha New value for the entire alpha channel
  339.      * @return Translucent/Opaque image based on the alpha value and the pixels of
  340.      * this image
  341.      */
  342.     public Image modifyAlphaWithTranslucency(byte alpha) {
  343.         int w = getWidth();
  344.         int h = getHeight();
  345.         int size = w * h;
  346.         int[] arr = getRGB();
  347.         int alphaInt = (((int)alpha) << 24) & 0xff000000;
  348.         float alphaRatio = (alpha & 0xff);
  349.         alphaRatio = alpha / 255.0f;
  350.         for(int iter = 0 ; iter < size ; iter++) {
  351.             int currentAlpha = (arr[iter] >> 24) & 0xff;
  352.             if(currentAlpha != 0) {
  353.                 if(currentAlpha == 0xff) {
  354.                     arr[iter] = (arr[iter] & 0xffffff) | alphaInt;
  355.                 } else {
  356.                     int relative = (int)((((float)(currentAlpha)) / 255.0f * alphaRatio) * 255.0f);
  357.                     relative = (relative << 24) & 0xff000000;
  358.                     arr[iter] = (arr[iter] & 0xffffff) | relative;
  359.                 }
  360.             }
  361.         }
  362.         Image i = new Image(arr, w, h);
  363.         i.opaqueTested = true;
  364.         i.opaque = false;
  365.         return i;
  366.     }
  367.     /**
  368.      * Creates a new image instance with the alpha channel of opaque/translucent 
  369.      * pixels within the image using the new alpha value. Transparent (alpha == 0)
  370.      * pixels remain transparent. All other pixels will have the new alpha value.
  371.      * 
  372.      * @param alpha New value for the entire alpha channel
  373.      * @param removeColor pixels matching this color are made transparent (alpha channel ignored)
  374.      * @return Translucent/Opaque image based on the alpha value and the pixels of 
  375.      * this image
  376.      */
  377.     public Image modifyAlpha(byte alpha, int removeColor) {
  378.         removeColor = removeColor & 0xffffff;
  379.         int w = getWidth();
  380.         int h = getHeight();
  381.         int size = w * h;
  382.         int[] arr = new int[size];
  383.         getRGB(arr, 0, 0, 0, w, h);
  384.         int alphaInt = (((int)alpha) << 24) & 0xff000000;
  385.         for(int iter = 0 ; iter < size ; iter++) {
  386.             if((arr[iter] & 0xff000000) != 0) {
  387.                 arr[iter] = (arr[iter] & 0xffffff) | alphaInt;
  388.                 if(removeColor == (0xffffff & arr[iter])) {
  389.                     arr[iter] = 0;
  390.                 }
  391.             }   
  392.         }
  393.         Image i = new Image(arr, w, h);
  394.         i.opaqueTested = true;
  395.         i.opaque = false;
  396.         return i;
  397.     }
  398.     
  399.     /**
  400.      * creates an image from the given path based on MIDP's createImage(path)
  401.      * 
  402.      * @param path 
  403.      * @throws java.io.IOException 
  404.      * @return newly created image object
  405.      */
  406.     public static Image createImage(String path) throws IOException {
  407.         try {
  408.             return new Image(Display.getInstance().getImplementation().createImage(path));
  409.         } catch(OutOfMemoryError err) {
  410.             // Images have a major bug on many phones where they sometimes throw 
  411.             // an OOM with no reason. A system.gc followed by the same call over
  412.             // solves the problem. This has something to do with the fact that 
  413.             // there is no Image.dispose method in existance.
  414.             System.gc();System.gc();
  415.             return new Image(Display.getInstance().getImplementation().createImage(path));
  416.         }
  417.     }
  418.     
  419.     /**
  420.      * creates an image from an InputStream
  421.      * 
  422.      * @param stream a given InputStream
  423.      * @throws java.io.IOException 
  424.      * @return the newly created image
  425.      */
  426.     public static Image createImage(InputStream stream) throws IOException {
  427.         try {
  428.             return new Image(Display.getInstance().getImplementation().createImage(stream));
  429.         } catch(OutOfMemoryError err) {
  430.             // Images have a major bug on many phones where they sometimes throw 
  431.             // an OOM with no reason. A system.gc followed by the same call over
  432.             // solves the problem. This has something to do with the fact that 
  433.             // there is no Image.dispose method in existance.
  434.             System.gc();System.gc();
  435.             return new Image(Display.getInstance().getImplementation().createImage(stream));
  436.         }
  437.     }
  438.     
  439.     /**
  440.      * creates an image from an RGB image
  441.      * 
  442.      * @param rgb the RGB image array data
  443.      * @param width the image width
  444.      * @param height the image height
  445.      * @return an image from an RGB image
  446.      */
  447.     public static Image createImage(int[] rgb, int width, int height) {
  448.         try {
  449.             Image i = new Image(Display.getInstance().getImplementation().createImage(rgb, width, height));
  450.             return i;
  451.         } catch(OutOfMemoryError err) {
  452.             // Images have a major bug on many phones where they sometimes throw 
  453.             // an OOM with no reason. A system.gc followed by the same call over
  454.             // solves the problem. This has something to do with the fact that 
  455.             // there is no Image.dispose method in existance.
  456.             System.gc();System.gc();
  457.             return new Image(Display.getInstance().getImplementation().createImage(rgb, width, height));
  458.         }
  459.     }
  460.     /**
  461.      * Creates a mutable image that may be manipulated using getGraphics
  462.      * 
  463.      * @param width the image width
  464.      * @param height the image height
  465.      * @return an image in a given width and height dimension
  466.      */
  467.     public static Image createImage(int width, int height) {
  468.         return createImage(width, height, 0xffffffff);
  469.     }
  470.     
  471.     /**
  472.      * Returns true if mutable images support alpha transparency
  473.      * 
  474.      * @return true if mutable images support alpha in their fillColor argument
  475.      */
  476.     public static boolean isAlphaMutableImageSupported() {
  477.         return Display.getInstance().getImplementation().isAlphaMutableImageSupported();
  478.     }
  479.     
  480.     /**
  481.      * Creates a mutable image that may be manipulated using getGraphics
  482.      * 
  483.      * @param width the image width
  484.      * @param height the image height
  485.      * @param fillColor the color with which the image should be initially filled
  486.      * @return an image in a given width and height dimension
  487.      */
  488.     public static Image createImage(int width, int height, int fillColor) {
  489.         try {
  490.             return new Image(Display.getInstance().getImplementation().createMutableImage(width, height, fillColor));
  491.         } catch(OutOfMemoryError err) {
  492.             // Images have a major bug on many phones where they sometimes throw 
  493.             // an OOM with no reason. A system.gc followed by the same call over
  494.             // solves the problem. This has something to do with the fact that 
  495.             // there is no Image.dispose method in existance.
  496.             System.gc();System.gc();
  497.             return new Image(Display.getInstance().getImplementation().createMutableImage(width, height, fillColor));
  498.         }
  499.     }
  500.     
  501.     
  502.     /**
  503.      * creates an image from a given byte array data
  504.      * 
  505.      * @param bytes the array of image data in a supported image format
  506.      * @param offset the offset of the start of the data in the array
  507.      * @param len the length of the data in the array
  508.      * @return the newly created image
  509.      */
  510.     public static Image createImage(byte[] bytes,int offset,int len) {
  511.         try {
  512.             return new Image(Display.getInstance().getImplementation().createImage(bytes, offset, len));
  513.         } catch(OutOfMemoryError err) {
  514.             // Images have a major bug on many phones where they sometimes throw 
  515.             // an OOM with no reason. A system.gc followed by the same call over
  516.             // solves the problem. This has something to do with the fact that 
  517.             // there is no Image.dispose method in existance.
  518.             System.gc();System.gc();
  519.             return new Image(Display.getInstance().getImplementation().createImage(bytes, offset, len));
  520.         }
  521.     }
  522.     /**
  523.      * If this is a mutable image a graphics object allowing us to draw on it
  524.      * is returned.
  525.      * 
  526.      * @return Graphics object allowing us to manipulate the content of a mutable image
  527.      */
  528.     public Graphics getGraphics() {
  529.         return new Graphics(Display.getInstance().getImplementation().getNativeGraphics(image));
  530.     }
  531.     
  532.     /**
  533.      * Returns the width of the image
  534.      * 
  535.      * @return the width of the image
  536.      */
  537.     public int getWidth() {
  538.         return Display.getInstance().getImplementation().getImageWidth(image);
  539.     }
  540.     
  541.     /**
  542.      * Returns the height of the image
  543.      * 
  544.      * @return the height of the image
  545.      */
  546.     public int getHeight() {
  547.         return Display.getInstance().getImplementation().getImageHeight(image);
  548.     }
  549.     /**
  550.      * Callback invoked internally by LWUIT to draw the image/frame onto the display.
  551.      * Image subclasses can override this method to perform drawing of custom image types.
  552.      *
  553.      * @param g the graphics object
  554.      * @param nativeGraphics the underlying native graphics which might be essential for some image types
  555.      * @param x the x coordinate
  556.      * @param y the y coordinate
  557.      */
  558.     protected void drawImage(Graphics g, Object nativeGraphics, int x, int y) {
  559.         g.drawImage(image, x, y, transform);
  560.     }
  561.     
  562.     /**
  563.      * Callback invoked internally by LWUIT to draw a portion of the image onto the display.
  564.      * Image subclasses can override this method to perform drawing of custom image types.
  565.      *
  566.      * @param g the graphics object
  567.      * @param nativeGraphics the underlying native graphics which might be essential for some image types
  568.      * @param x the x coordinate
  569.      * @param y the y coordinate
  570.      * @param imageX location within the image to draw
  571.      * @param imageY location within the image to draw
  572.      * @param imageWidth size of the location within the image to draw
  573.      * @param imageHeight size of the location within the image to draw
  574.      */
  575.     void drawImageArea(Graphics g, Object nativeGraphics, int x, int y, int imageX, int imageY, int imageWidth, int imageHeight) {
  576.         Display.getInstance().getImplementation().drawImageArea(nativeGraphics, image, x, y, imageX, imageY, imageWidth, imageHeight);
  577.     }
  578.     /**
  579.      * Obtains ARGB pixel data from the specified region of this image and 
  580.      * stores it in the provided array of integers. Each pixel value is 
  581.      * stored in 0xAARRGGBB format, where the high-order byte contains the 
  582.      * alpha channel and the remaining bytes contain color components for red, 
  583.      * green and blue, respectively. The alpha channel specifies the opacity of 
  584.      * the pixel, where a value of 0x00  represents a pixel that is fully 
  585.      * transparent and a value of 0xFF  represents a fully opaque pixel. 
  586.      * The rgb information contained within the image, this method ignors 
  587.      * rotation and mirroring in some/most situations and cannot be 
  588.      * used in such cases.
  589.      * 
  590.      * @param rgbData an array of integers in which the ARGB pixel data is 
  591.      * stored
  592.      * @param offset the index into the array where the first ARGB value is 
  593.      * stored
  594.      * @param scanlength the relative offset in the array between 
  595.      * corresponding pixels in consecutive rows of the region
  596.      * @param x the x-coordinate of the upper left corner of the region
  597.      * @param y the y-coordinate of the upper left corner of the region
  598.      * @param width the width of the region
  599.      * @param height the height of the region
  600.      */
  601.     void getRGB(int[] rgbData,
  602.             int offset,
  603.             int x,
  604.             int y,
  605.             int width,
  606.             int height){
  607.         Display.getInstance().getImplementation().getRGB(image, rgbData, offset, x, y, width, height);
  608.     }
  609.     
  610.     
  611.     /**
  612.      * Extracts data from this image into the given RGBImage
  613.      * 
  614.      * @param image RGBImage that would receive pixel data
  615.      * @param destX x location within RGBImage into which the data will
  616.      *      be written
  617.      * @param destY y location within RGBImage into which the data will
  618.      *      be written
  619.      * @param x location within the source image
  620.      * @param y location within the source image
  621.      * @param width size of the image to extract from the source image
  622.      * @param height size of the image to extract from the source image
  623.      */
  624.     public void toRGB(RGBImage image,
  625.             int destX,
  626.             int destY,
  627.             int x,
  628.             int y,
  629.             int width,
  630.             int height){
  631.         getRGB(image.getRGB(), destX * destY, x, y, width, height);
  632.     }
  633.     
  634.     /**
  635.      * Returns the content of this image as a newly created ARGB array.
  636.      * 
  637.      * @return new array instance containing the ARGB data within this image
  638.      */
  639.     public int[] getRGB() {
  640.         return getRGBImpl();
  641.     }
  642.     /**
  643.      * Returns the content of this image as a newly created ARGB array or a cached
  644.      * instance if possible. Note that cached instances may be garbage collected.
  645.      *
  646.      * @return array instance containing the ARGB data within this image
  647.      */
  648.     public int[] getRGBCached() {
  649.         int[] r = getRGBCache();
  650.         if(r == null) {
  651.             r = getRGBImpl();
  652.             rgbCache = new WeakReference(r);
  653.         }
  654.         return r;
  655.     }
  656.     int[] getRGBCache() {
  657.         if(rgbCache != null) {
  658.             int[] rgb = (int[])rgbCache.get();
  659.             return rgb;
  660.         }
  661.         return null;
  662.     }
  663.     
  664.     int[] getRGBImpl() {
  665.         int width = getWidth();
  666.         int height = getHeight();
  667.         int[] rgbData = new int[width * height];
  668.         getRGB(rgbData, 0, 0, 0, width, height);
  669.         return rgbData;
  670.     }
  671.     
  672.     /**
  673.      * Scales the image to the given width while updating the height based on the
  674.      * aspect ratio of the width
  675.      * 
  676.      * @param width the given new image width
  677.      * @return the newly created image
  678.      */
  679.     public Image scaledWidth(int width) {
  680.         float ratio = ((float)width) / ((float)getWidth());
  681.         return scaled(width, (int)(getHeight() * ratio));
  682.     }
  683.     /**
  684.      * Scales the image to the given height while updating the width based on the
  685.      * aspect ratio of the height
  686.      * 
  687.      * @param height the given new image height
  688.      * @return the newly created image
  689.      */
  690.     public Image scaledHeight(int height) {
  691.         float ratio = ((float)height) / ((float)getHeight());
  692.         return scaled((int)(getWidth() * ratio), height);
  693.     }
  694.     
  695.     /**
  696.      * Scales the image while maintaining the aspect ratio to the smaller size 
  697.      * image
  698.      * 
  699.      * @param width the given new image width
  700.      * @param height the given new image height
  701.      * @return the newly created image
  702.      */
  703.     public Image scaledSmallerRatio(int width, int height) {
  704.         float hRatio = ((float)height) / ((float)getHeight());
  705.         float wRatio = ((float)width) / ((float)getWidth());
  706.         if(hRatio < wRatio) {
  707.             return scaled(width, (int)(getHeight() * hRatio));
  708.         } else {
  709.             return scaled((int)(getWidth() * wRatio), height);
  710.         }
  711.     }
  712.     /**
  713.      * Returns a scaled version of this image image using the given width and height, 
  714.      * this is a fast algorithm that preserves translucent information.
  715.      * The method accepts -1 to preserve aspect ratio in the given axis.
  716.      * 
  717.      * @param width width for the scaling
  718.      * @param height height of the scaled image
  719.      * @return new image instance scaled to the given height and width
  720.      */
  721.     public Image scaled(int width, int height) {
  722.         if(width == getWidth() && height == getHeight()) {
  723.             return this;
  724.         }
  725.         if(width == -1) {
  726.             return scaledHeight(height);
  727.         } 
  728.         if(height == -1) {
  729.             return scaledWidth(width);
  730.         }
  731.         Dimension d = new Dimension(width, height);
  732.         Image i = getCachedImage(d);
  733.         if(i != null) {
  734.             return i;
  735.         }
  736.         cacheImage(new Dimension(getWidth(), getHeight()), this);
  737.         i = new Image(this.image);
  738.         i.scaleCache = scaleCache;
  739.         i.scale(width, height);
  740.         i.transform = this.transform;
  741.         i.animated = animated;
  742.         i.svg = svg;
  743.                 
  744.         return i;
  745.     }
  746.     /**
  747.      * Returns the platform specific image implementation, <strong>warning</strong> the
  748.      * implementation class can change between revisions of LWUIT and platforms.
  749.      *
  750.      * @return platform specific native implementation for this image object
  751.      */
  752.     public Object getImage() {
  753.         return image;
  754.     }
  755.     
  756.     /**
  757.      * Scale the image to the given width and height, this is a fast algorithm
  758.      * that preserves translucent information
  759.      * 
  760.      * @param width width for the scaling
  761.      * @param height height of the scaled image
  762.      * 
  763.      * @deprecated scale should return an image rather than modify the image in place
  764.      * use scaled(int, int) instead
  765.      */
  766.     public void scale(int width, int height) {
  767.         image = Display.getInstance().getImplementation().scale(image, width, height);
  768.     }//resize image
  769.     
  770.     boolean scaleArray(int srcWidth, int srcHeight, int height, int width, int[] currentArray, int[] destinationArray) {
  771.         // Horizontal Resize
  772.         int yRatio = (srcHeight << 16) / height;
  773.         int xRatio = (srcWidth << 16) / width;
  774.         int xPos = xRatio / 2;
  775.         int yPos = yRatio / 2;
  776.         // if there is more than 16bit color there is no point in using mutable
  777.         // images since they won't save any memory
  778.         boolean testOpaque = Display.getInstance().numColors() <= 65536 && (!opaqueTested);
  779.         boolean currentOpaque = true;
  780.         for (int y = 0; y < height; y++) {
  781.             int srcY = yPos >> 16;
  782.             getRGB(currentArray, 0, 0, srcY, srcWidth, 1);
  783.             for (int x = 0; x < width; x++) {
  784.                 int srcX = xPos >> 16;
  785.                 int destPixel = x + y * width;
  786.                 if ((destPixel >= 0 && destPixel < destinationArray.length) && (srcX < currentArray.length)) {
  787.                     destinationArray[destPixel] = currentArray[srcX];
  788.                     // if all the pixels have an opaque alpha channel then the image is opaque
  789.                     currentOpaque = testOpaque && currentOpaque && (currentArray[srcX] & 0xff000000) == 0xff000000;
  790.                 }
  791.                 xPos += xRatio;
  792.             }
  793.             yPos += yRatio;
  794.             xPos = xRatio / 2;
  795.         }
  796.         if(testOpaque) {
  797.             this.opaque = currentOpaque;
  798.         }
  799.         return opaque;
  800.     }
  801.     
  802.     /**
  803.      * Returns true if this is an animated image
  804.      * 
  805.      * @return true if this image represents an animation
  806.      */
  807.     public boolean isAnimation() {
  808.         return animated;
  809.     }
  810.     /**
  811.      * @inheritDoc 
  812.      */
  813.     public boolean animate() {
  814.         if(imageTime == -1) {
  815.             imageTime = System.currentTimeMillis();
  816.         }
  817.         boolean val = Display.getInstance().getImplementation().animateImage(image, imageTime);
  818.         imageTime = System.currentTimeMillis();
  819.         return val;
  820.     }
  821.     /**
  822.      * Indicates whether this image is opaque or not
  823.      * 
  824.      * @return true if the image is completely opqaque which allows for some heavy optimizations
  825.      */
  826.     public boolean isOpaque() {
  827.         if(!opaqueTested) {
  828.             opaque = Display.getInstance().getImplementation().isOpaque(this, image);
  829.             opaqueTested = true;
  830.         }
  831.         return opaque;
  832.     }
  833. }