javauis/eswt_akn/org.eclipse.ercp.swt.s60/src/org/eclipse/swt/graphics/Image.java
branchRCL_3
changeset 19 04becd199f91
child 60 6c158198356e
equal deleted inserted replaced
16:f5050f1da672 19:04becd199f91
       
     1 /*******************************************************************************
       
     2  * Copyright (c) 2000, 2004 IBM Corporation and others.
       
     3  * All rights reserved. This program and the accompanying materials
       
     4  * are made available under the terms of the Eclipse Public License v1.0
       
     5  * which accompanies this distribution, and is available at
       
     6  * http://www.eclipse.org/legal/epl-v10.html
       
     7  *
       
     8  * Contributors:
       
     9  *     IBM Corporation - initial API and implementation
       
    10  *     Lynne Kues (IBM Corp) - modified to reflect eSWT API subset
       
    11  *     Nokia Corporation - S60 implementation
       
    12  *******************************************************************************/
       
    13 package org.eclipse.swt.graphics;
       
    14 
       
    15 
       
    16 import java.io.*;
       
    17 import org.eclipse.swt.*;
       
    18 import org.eclipse.swt.internal.symbian.*;
       
    19 import org.eclipse.swt.internal.FileCompatibility;
       
    20 
       
    21 
       
    22 /**
       
    23  * Instances of this class are graphics which have been prepared
       
    24  * for display on a specific device. That is, they are ready
       
    25  * to paint using methods such as <code>GC.drawImage()</code>
       
    26  * and display on widgets with, for example, <code>Button.setImage()</code>.
       
    27  * <p>
       
    28  * If loaded from a file format that supports it, an
       
    29  * <code>Image</code> may have transparency, meaning that certain
       
    30  * pixels are specified as being transparent when drawn. Examples
       
    31  * of file formats that support transparency are GIF and PNG.
       
    32  * </p><p>
       
    33  * There are two primary ways to use <code>Images</code>.
       
    34  * The first is to load a graphic file from disk and create an
       
    35  * <code>Image</code> from it. This is done using an <code>Image</code>
       
    36  * constructor, for example:
       
    37  * <pre>
       
    38  *    Image i = new Image(device, "C:\\graphic.png");
       
    39  * </pre>
       
    40  * A graphic file may contain a color table specifying which
       
    41  * colors the image was intended to possess. In the above example,
       
    42  * these colors will be mapped to the closest available color in
       
    43  * SWT. It is possible to get more control over the mapping of
       
    44  * colors as the image is being created, using code of the form:
       
    45  * <pre>
       
    46  *    ImageData data = new ImageData("C:\\graphic.png");
       
    47  *    RGB[] rgbs = data.getRGBs();
       
    48  *    // At this point, rgbs contains specifications of all
       
    49  *    // the colors contained within this image. You may
       
    50  *    // allocate as many of these colors as you wish by
       
    51  *    // using the Color constructor Color(RGB), then
       
    52  *    // create the image:
       
    53  *    Image i = new Image(device, data);
       
    54  * </pre>
       
    55  * <p>
       
    56  * Application code must explicitely invoke the <code>Image.dispose()</code>
       
    57  * method to release the operating system resources managed by each instance
       
    58  * when those instances are no longer required.
       
    59  * </p>
       
    60  *
       
    61  * @see Color
       
    62  * @see ImageData
       
    63  */
       
    64 
       
    65 public final class Image implements Drawable
       
    66 {
       
    67 
       
    68     /**
       
    69      * specifies whether the receiver is a bitmap or an icon
       
    70      * (one of <code>SWT.BITMAP</code>, <code>SWT.ICON</code>)
       
    71      */
       
    72     public int type;
       
    73 
       
    74     /**
       
    75      * the handle to the OS image resource
       
    76      * (Warning: This field is platform dependent)
       
    77      */
       
    78     public int handle;
       
    79 
       
    80     /**
       
    81      * the device where this image was created
       
    82      */
       
    83     Device device;
       
    84 
       
    85     /**
       
    86      * specifies the transparent pixel
       
    87      * (Warning: This field is platform dependent)
       
    88      */
       
    89     Color transparentPixel;
       
    90 
       
    91     /**
       
    92      * Whether this image is currently selected in a GC
       
    93      * (Warning: This field is platform dependent)
       
    94      */
       
    95     boolean owningGc = false;
       
    96 
       
    97     /**
       
    98      * the global alpha value to be used for every pixel
       
    99      * (Warning: This field is platform dependent)
       
   100      */
       
   101     int alpha = -1;
       
   102 
       
   103     /**
       
   104      * specifies the default scanline padding
       
   105      * (Warning: This field is platform dependent)
       
   106      */
       
   107     static final int DEFAULT_SCANLINE_PAD = 4;
       
   108 
       
   109     /**
       
   110      * Prevents uninitialized instances from being created outside the package.
       
   111      */
       
   112     Image()
       
   113     {
       
   114     }
       
   115 
       
   116     /**
       
   117      * Constructs an empty instance of this class with the
       
   118      * specified width and height. The result may be drawn upon
       
   119      * by creating a GC and using any of its drawing operations,
       
   120      * as shown in the following example:
       
   121      * <pre>
       
   122      *    Image i = new Image(device, width, height);
       
   123      *    GC gc = new GC(i);
       
   124      *    gc.drawRectangle(0, 0, 50, 50);
       
   125      *    gc.dispose();
       
   126      * </pre>
       
   127      * <p>
       
   128      * Note: Some platforms may have a limitation on the size
       
   129      * of image that can be created (size depends on width, height,
       
   130      * and depth). For example, Windows 95, 98, and ME do not allow
       
   131      * images larger than 16M.
       
   132      * </p>
       
   133      *
       
   134      * @param device the device on which to create the image
       
   135      * @param width the width of the new image
       
   136      * @param height the height of the new image
       
   137      *
       
   138      * @exception IllegalArgumentException <ul>
       
   139      *    <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
       
   140      *    <li>ERROR_INVALID_ARGUMENT - if either the width or height is negative or zero</li>
       
   141      * </ul>
       
   142      * @exception SWTError <ul>
       
   143      *    <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
       
   144      * </ul>
       
   145      */
       
   146     public Image(Device device, int width, int height)
       
   147     {
       
   148         if (device == null) device = Device.getDevice();
       
   149         if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
       
   150         init(device, width, height);
       
   151     }
       
   152 
       
   153     /**
       
   154      * Constructs an empty instance of this class with the
       
   155      * width and height of the specified rectangle. The result
       
   156      * may be drawn upon by creating a GC and using any of its
       
   157      * drawing operations, as shown in the following example:
       
   158      * <pre>
       
   159      *    Image i = new Image(device, boundsRectangle);
       
   160      *    GC gc = new GC(i);
       
   161      *    gc.drawRectangle(0, 0, 50, 50);
       
   162      *    gc.dispose();
       
   163      * </pre>
       
   164      * <p>
       
   165      * Note: Some platforms may have a limitation on the size
       
   166      * of image that can be created (size depends on width, height,
       
   167      * and depth). For example, Windows 95, 98, and ME do not allow
       
   168      * images larger than 16M.
       
   169      * </p>
       
   170      *
       
   171      * @param device the device on which to create the image
       
   172      * @param bounds a rectangle specifying the image's width and height (must not be null)
       
   173      *
       
   174      * @exception IllegalArgumentException <ul>
       
   175      *    <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
       
   176      *    <li>ERROR_NULL_ARGUMENT - if the bounds rectangle is null</li>
       
   177      *    <li>ERROR_INVALID_ARGUMENT - if either the rectangle's width or height is negative</li>
       
   178      * </ul>
       
   179      * @exception SWTError <ul>
       
   180      *    <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
       
   181      * </ul>
       
   182      */
       
   183     public Image(Device device, Rectangle bounds)
       
   184     {
       
   185         if (device == null) device = Device.getDevice();
       
   186         if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
       
   187         if (bounds == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
       
   188         init(device, bounds.width, bounds.height);
       
   189     }
       
   190 
       
   191     /**
       
   192      * Constructs an instance of this class from the given
       
   193      * <code>ImageData</code>.
       
   194      *
       
   195      * @param device the device on which to create the image
       
   196      * @param data the image data to create the image from (must not be null)
       
   197      *
       
   198      * @exception IllegalArgumentException <ul>
       
   199      *    <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
       
   200      *    <li>ERROR_NULL_ARGUMENT - if the image data is null</li>
       
   201      * </ul>
       
   202      * @exception SWTException <ul>
       
   203      *    <li>ERROR_UNSUPPORTED_DEPTH - if the depth of the ImageData is not supported</li>
       
   204      * </ul>
       
   205      * @exception SWTError <ul>
       
   206      *    <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
       
   207      * </ul>
       
   208      */
       
   209     public Image(Device device, ImageData data)
       
   210     {
       
   211         if (device == null) device = Device.getDevice();
       
   212         if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
       
   213         init(device, data);
       
   214     }
       
   215 
       
   216     /**
       
   217      * Constructs an instance of this class by loading its representation
       
   218      * from the specified input stream. Throws an error if an error
       
   219      * occurs while loading the image, or if the result is an image
       
   220      * of an unsupported type.  Application code is still responsible
       
   221      * for closing the input stream.
       
   222      * <p>
       
   223      * This constructor may be used to load a resource as follows:
       
   224      * </p>
       
   225      * <pre>
       
   226      *     new Image(device, clazz.getResourceAsStream("file.png"));
       
   227      * </pre>
       
   228      *
       
   229      * @param device the device on which to create the image
       
   230      * @param stream the input stream to load the image from
       
   231      *
       
   232      * @exception IllegalArgumentException <ul>
       
   233      *    <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
       
   234      *    <li>ERROR_NULL_ARGUMENT - if the stream is null</li>
       
   235      * </ul>
       
   236      * @exception SWTException <ul>
       
   237      *    <li>ERROR_INVALID_IMAGE - if the image file contains invalid data </li>
       
   238      *    <li>ERROR_IO - if an IO error occurs while reading data</li>
       
   239      *    <li>ERROR_UNSUPPORTED_DEPTH - if the InputStream describes an image with an unsupported depth</li>
       
   240      *    <li>ERROR_UNSUPPORTED_FORMAT - if the image file contains an unrecognized format</li>
       
   241      *  * </ul>
       
   242      * </ul>
       
   243      * @exception SWTError <ul>
       
   244      *    <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
       
   245      * </ul>
       
   246      */
       
   247     public Image(Device device, InputStream stream)
       
   248     {
       
   249         if (device == null) device = Device.getDevice();
       
   250         if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
       
   251         init(device, new ImageData(stream));
       
   252     }
       
   253 
       
   254     /**
       
   255      * Constructs an instance of this class by loading its representation
       
   256      * from the file with the specified name. Throws an error if an error
       
   257      * occurs while loading the image, or if the result is an image
       
   258      * of an unsupported type.
       
   259      * <p>
       
   260      * This constructor is provided for convenience when loading
       
   261      * a single image only. If the specified file contains
       
   262      * multiple images, only the first one will be used.
       
   263      *
       
   264      * @param device the device on which to create the image
       
   265      * @param filename the name of the file to load the image from
       
   266      *
       
   267      * @exception IllegalArgumentException <ul>
       
   268      *    <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
       
   269      *    <li>ERROR_NULL_ARGUMENT - if the file name is null</li>
       
   270      * </ul>
       
   271      * @exception SWTException <ul>
       
   272      *    <li>ERROR_INVALID_IMAGE - if the image file contains invalid data </li>
       
   273      *    <li>ERROR_IO - if an IO error occurs while reading data</li>
       
   274      *    <li>ERROR_UNSUPPORTED_DEPTH - if the image file has an unsupported depth</li>
       
   275      *    <li>ERROR_UNSUPPORTED_FORMAT - if the image file contains an unrecognized format</li>
       
   276      * </ul>
       
   277      * @exception SWTError <ul>
       
   278      *    <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
       
   279      * </ul>
       
   280      */
       
   281     public Image(Device device, String filename)
       
   282     {
       
   283         if (device == null) device = Device.getDevice();
       
   284         if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
       
   285         init(device, new ImageData(filename));
       
   286     }
       
   287 
       
   288     /**
       
   289      * Disposes of the operating system resources associated with
       
   290      * the image. Applications must dispose of all images which
       
   291      * they allocate.
       
   292      */
       
   293     public void dispose()
       
   294     {
       
   295         if (handle == 0) return;
       
   296         if (device.isDisposed()) return;
       
   297         OS.Image_Dispose(device.handle, handle);
       
   298         handle = 0;
       
   299         if (transparentPixel != null) transparentPixel.dispose();
       
   300         if (device.tracking) device.dispose_Object(this);
       
   301         device = null;
       
   302     }
       
   303 
       
   304     /**
       
   305      * Compares the argument to the receiver, and returns true
       
   306      * if they represent the <em>same</em> object using a class
       
   307      * specific comparison.
       
   308      *
       
   309      * @param object the object to compare with this object
       
   310      * @return <code>true</code> if the object is the same as this object and <code>false</code> otherwise
       
   311      *
       
   312      * @see #hashCode
       
   313      */
       
   314     public boolean equals(Object object)
       
   315     {
       
   316         if (object == this) return true;
       
   317         if (!(object instanceof Image)) return false;
       
   318         Image image = (Image) object;
       
   319         return device == image.device && handle == image.handle;
       
   320     }
       
   321 
       
   322     /**
       
   323      * Returns the bounds of the receiver. The rectangle will always
       
   324      * have x and y values of 0, and the width and height of the
       
   325      * image.
       
   326      *
       
   327      * @return a rectangle specifying the image's bounds
       
   328      *
       
   329      * @exception SWTException <ul>
       
   330      *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
       
   331      *    <li>ERROR_INVALID_IMAGE - if the image is not a bitmap or an icon</li>
       
   332      * </ul>
       
   333      */
       
   334     public Rectangle getBounds()
       
   335     {
       
   336         if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
       
   337         switch (type)
       
   338         {
       
   339         case SWT.BITMAP:
       
   340         case SWT.ICON:
       
   341             return OS.Image_GetBounds(handle);
       
   342         default:
       
   343             SWT.error(SWT.ERROR_INVALID_IMAGE);
       
   344             return null;
       
   345         }
       
   346     }
       
   347 
       
   348     /**
       
   349      * Returns an <code>ImageData</code> based on the receiver
       
   350      * Modifications made to this <code>ImageData</code> will not
       
   351      * affect the Image.
       
   352      *
       
   353      * @return an <code>ImageData</code> containing the image's data and attributes
       
   354      *
       
   355      * @exception SWTException <ul>
       
   356      *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
       
   357      *    <li>ERROR_INVALID_IMAGE - if the image is not a bitmap or an icon</li>
       
   358      * </ul>
       
   359      *
       
   360      * @see ImageData
       
   361      */
       
   362     public ImageData getImageData()
       
   363     {
       
   364         if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
       
   365         switch (type)
       
   366         {
       
   367         case SWT.BITMAP:
       
   368         case SWT.ICON:
       
   369             return OS.Image_GetData(handle);
       
   370         default:
       
   371             SWT.error(SWT.ERROR_INVALID_IMAGE);
       
   372             return null;
       
   373         }
       
   374     }
       
   375 
       
   376     /**
       
   377      * Returns an integer hash code for the receiver. Any two
       
   378      * objects which return <code>true</code> when passed to
       
   379      * <code>equals</code> must return the same value for this
       
   380      * method.
       
   381      *
       
   382      * @return the receiver's hash
       
   383      *
       
   384      * @see #equals
       
   385      */
       
   386     public int hashCode()
       
   387     {
       
   388         return handle;
       
   389     }
       
   390 
       
   391     void init(Device device, int width, int height)
       
   392     {
       
   393         if (width <= 0 || height <= 0)
       
   394         {
       
   395             SWT.error(SWT.ERROR_INVALID_ARGUMENT);
       
   396         }
       
   397         this.device = device;
       
   398         type = SWT.BITMAP;
       
   399         handle = OS.Image_New(device.handle, width, height);
       
   400         if (handle == 0)
       
   401         {
       
   402             SWT.error(SWT.ERROR_NO_HANDLES, null, device.getLastError());
       
   403         }
       
   404         try
       
   405         {
       
   406             if (device.tracking) device.new_Object(this);
       
   407         }
       
   408         catch (Error e)
       
   409         {
       
   410             OS.Image_Dispose(device.handle, handle);
       
   411             throw e;
       
   412         }
       
   413     }
       
   414 
       
   415     static void init(Device device, Image image, ImageData i)
       
   416     {
       
   417         if (image != null) image.device = device;
       
   418         image.handle = OS.Image_NewFromData(device.handle, i);
       
   419         image.alpha = i.alpha;
       
   420 
       
   421         try
       
   422         {
       
   423             if (i.transparentPixel != -1)
       
   424             {
       
   425                 image.transparentPixel = new Color(device, i.palette.getRGB(i.transparentPixel));
       
   426             }
       
   427             if (device.tracking) device.new_Object(image);
       
   428         }
       
   429         catch (Error e)
       
   430         {
       
   431             OS.Image_Dispose(device.handle, image.handle);
       
   432             throw e;
       
   433         }
       
   434     }
       
   435 
       
   436     static void init(Device device, Image image, ImageData source, ImageData mask)
       
   437     {
       
   438         /* Create a temporary image and locate the black pixel */
       
   439         ImageData imageData;
       
   440         int blackIndex = 0;
       
   441         if (source.palette.isDirect)
       
   442         {
       
   443             imageData = new ImageData(source.width, source.height, source.depth, source.palette);
       
   444         }
       
   445         else
       
   446         {
       
   447             RGB black = new RGB(0, 0, 0);
       
   448             RGB[] rgbs = source.getRGBs();
       
   449             if (source.transparentPixel != -1)
       
   450             {
       
   451                 /*
       
   452                  * The source had transparency, so we can use the transparent pixel
       
   453                  * for black.
       
   454                  */
       
   455                 RGB[] newRGBs = new RGB[rgbs.length];
       
   456                 System.arraycopy(rgbs, 0, newRGBs, 0, rgbs.length);
       
   457                 if (source.transparentPixel >= newRGBs.length)
       
   458                 {
       
   459                     /* Grow the palette with black */
       
   460                     rgbs = new RGB[source.transparentPixel + 1];
       
   461                     System.arraycopy(newRGBs, 0, rgbs, 0, newRGBs.length);
       
   462                     for (int i = newRGBs.length; i <= source.transparentPixel; i++)
       
   463                     {
       
   464                         rgbs[i] = new RGB(0, 0, 0);
       
   465                     }
       
   466                 }
       
   467                 else
       
   468                 {
       
   469                     newRGBs[source.transparentPixel] = black;
       
   470                     rgbs = newRGBs;
       
   471                 }
       
   472                 blackIndex = source.transparentPixel;
       
   473                 imageData = new ImageData(source.width, source.height, source.depth, new PaletteData(rgbs));
       
   474             }
       
   475             else
       
   476             {
       
   477                 while (blackIndex < rgbs.length)
       
   478                 {
       
   479                     if (rgbs[blackIndex].equals(black)) break;
       
   480                     blackIndex++;
       
   481                 }
       
   482                 if (blackIndex == rgbs.length)
       
   483                 {
       
   484                     /*
       
   485                      * We didn't find black in the palette, and there is no transparent
       
   486                      * pixel we can use.
       
   487                      */
       
   488                     if ((1 << source.depth) > rgbs.length)
       
   489                     {
       
   490                         /* We can grow the palette and add black */
       
   491                         RGB[] newRGBs = new RGB[rgbs.length + 1];
       
   492                         System.arraycopy(rgbs, 0, newRGBs, 0, rgbs.length);
       
   493                         newRGBs[rgbs.length] = black;
       
   494                         rgbs = newRGBs;
       
   495                     }
       
   496                     else
       
   497                     {
       
   498                         /* No room to grow the palette */
       
   499                         blackIndex = -1;
       
   500                     }
       
   501                 }
       
   502                 imageData = new ImageData(source.width, source.height, source.depth, new PaletteData(rgbs));
       
   503             }
       
   504         }
       
   505         if (blackIndex == -1)
       
   506         {
       
   507             /* There was no black in the palette, so just copy the data over */
       
   508             System.arraycopy(source.data, 0, imageData.data, 0, imageData.data.length);
       
   509         }
       
   510         else
       
   511         {
       
   512             /* Modify the source image to contain black wherever the mask is 0 */
       
   513             int[] imagePixels = new int[imageData.width];
       
   514             int[] maskPixels = new int[mask.width];
       
   515             for (int y = 0; y < imageData.height; y++)
       
   516             {
       
   517                 source.getPixels(0, y, imageData.width, imagePixels, 0);
       
   518                 mask.getPixels(0, y, mask.width, maskPixels, 0);
       
   519                 for (int i = 0; i < imagePixels.length; i++)
       
   520                 {
       
   521                     if (maskPixels[i] == 0) imagePixels[i] = blackIndex;
       
   522                 }
       
   523                 imageData.setPixels(0, y, source.width, imagePixels, 0);
       
   524             }
       
   525         }
       
   526         imageData.maskPad = mask.scanlinePad;
       
   527         imageData.maskData = mask.data;
       
   528         init(device, image, imageData);
       
   529     }
       
   530 
       
   531     void init(Device device, ImageData i)
       
   532     {
       
   533         if (i == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
       
   534         init(device, this, i);
       
   535     }
       
   536 
       
   537     /**
       
   538      * Invokes platform specific functionality to allocate a new GC handle.
       
   539      * <p>
       
   540      * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
       
   541      * API for <code>Image</code>. It is marked public only so that it
       
   542      * can be shared within the packages provided by SWT. It is not
       
   543      * available on all platforms, and should never be called from
       
   544      * application code.
       
   545      * </p>
       
   546      *
       
   547      * @param data the platform specific GC data
       
   548      * @return the platform specific GC handle
       
   549      */
       
   550     public int internal_new_GC(GCData data)
       
   551     {
       
   552         synchronized (this)
       
   553         {
       
   554             if (owningGc)
       
   555             {
       
   556                 SWT.error(SWT.ERROR_INVALID_ARGUMENT);
       
   557             }
       
   558             owningGc = true;
       
   559         }
       
   560 
       
   561         if ((type != SWT.BITMAP) && (type != SWT.ICON))
       
   562         {
       
   563             SWT.error(SWT.ERROR_INVALID_ARGUMENT);
       
   564         }
       
   565 
       
   566         return OS.Drawable_NewGc(handle);
       
   567     }
       
   568 
       
   569     /**
       
   570      * Invokes platform specific functionality to dispose a GC handle.
       
   571      * <p>
       
   572      * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
       
   573      * API for <code>Image</code>. It is marked public only so that it
       
   574      * can be shared within the packages provided by SWT. It is not
       
   575      * available on all platforms, and should never be called from
       
   576      * application code.
       
   577      * </p>
       
   578      *
       
   579      * @param hDC the platform specific GC handle
       
   580      * @param data the platform specific GC data
       
   581      */
       
   582     public void internal_dispose_GC(int gcHandle, GCData data)
       
   583     {
       
   584         OS.GC_Dispose(gcHandle);
       
   585 
       
   586         synchronized (this)
       
   587         {
       
   588             owningGc = false;
       
   589         }
       
   590     }
       
   591 
       
   592     /**
       
   593      * Returns <code>true</code> if the receiver is visible, and
       
   594      * <code>false</code> otherwise.
       
   595      * <p>
       
   596      * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
       
   597      * API for <code>Drawable</code>. It is marked public only so that it
       
   598      * can be shared within the packages provided by SWT. It is not
       
   599      * available on all platforms, and should never be called from
       
   600      * application code.
       
   601      * </p>
       
   602      *
       
   603      * @return the receiver's visibility state
       
   604      */
       
   605     public boolean internal_isVisible()
       
   606     {
       
   607         return true;
       
   608     }
       
   609 
       
   610     /**
       
   611      * Returns <code>true</code> if the receiver has been disposed,
       
   612      * and <code>false</code> otherwise.
       
   613      * <p>
       
   614      * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
       
   615      * API for <code>Drawable</code>. It is marked public only so that it
       
   616      * can be shared within the packages provided by SWT. It is not
       
   617      * available on all platforms, and should never be called from
       
   618      * application code.
       
   619      * </p>
       
   620      *
       
   621      * @return <code>true</code> when the receiver is disposed and <code>false</code> otherwise
       
   622      */
       
   623     public boolean internal_isDisposed()
       
   624     {
       
   625         return isDisposed();
       
   626     }
       
   627 
       
   628     /**
       
   629      * Returns <code>true</code> if the image has been disposed,
       
   630      * and <code>false</code> otherwise.
       
   631      * <p>
       
   632      * This method gets the dispose state for the image.
       
   633      * When an image has been disposed, it is an error to
       
   634      * invoke any other method using the image.
       
   635      *
       
   636      * @return <code>true</code> when the image is disposed and <code>false</code> otherwise
       
   637      */
       
   638     public boolean isDisposed()
       
   639     {
       
   640         return handle == 0;
       
   641     }
       
   642 
       
   643     /**
       
   644      * Returns a string containing a concise, human-readable
       
   645      * description of the receiver.
       
   646      *
       
   647      * @return a string representation of the receiver
       
   648      */
       
   649     public String toString()
       
   650     {
       
   651         if (isDisposed()) return "Image {*DISPOSED*}";
       
   652         return "Image {" + handle + "}";
       
   653     }
       
   654 
       
   655 
       
   656 
       
   657 
       
   658     /**
       
   659      * The following functions are not part of the eSWT public api
       
   660      * @param fileName
       
   661      * @return
       
   662      */
       
   663     static int imageFormat(String fileName)
       
   664     {
       
   665         InputStream stream = null;
       
   666         try
       
   667         {
       
   668             stream = FileCompatibility.getInputStreamFromFile(fileName);
       
   669             byte[] buffer = new byte[32];
       
   670             stream.read(buffer, 0, buffer.length);
       
   671             stream.close();
       
   672             return Image.imageFormat(buffer);
       
   673         }
       
   674         catch (IOException e)
       
   675         {
       
   676             SWT.error(SWT.ERROR_IO, e);
       
   677         }
       
   678         finally
       
   679         {
       
   680             try
       
   681             {
       
   682                 if (stream != null) stream.close();
       
   683             }
       
   684             catch (IOException e)
       
   685             {
       
   686                 // Ignore error
       
   687             }
       
   688         }
       
   689         return SWT.IMAGE_UNDEFINED;
       
   690     }
       
   691     static int imageFormat(byte[] streamBytes)
       
   692     {
       
   693         if (isPNGFormat(streamBytes)) return SWT.IMAGE_PNG;
       
   694         if (isGIFFormat(streamBytes)) return SWT.IMAGE_GIF;
       
   695         if (isJPEGFormat(streamBytes)) return SWT.IMAGE_JPEG;
       
   696         return SWT.IMAGE_UNDEFINED;
       
   697     }
       
   698     static boolean isPNGFormat(byte[] streamBytes)
       
   699     {
       
   700         if (streamBytes.length < 8) return false;
       
   701         if ((streamBytes[0] & 0xFF) != 137) return false; //137
       
   702         if ((streamBytes[1] & 0xFF) != 80) return false; //P
       
   703         if ((streamBytes[2] & 0xFF) != 78) return false; //N
       
   704         if ((streamBytes[3] & 0xFF) != 71) return false; //G
       
   705         if ((streamBytes[4] & 0xFF) != 13) return false; //<RETURN>
       
   706         if ((streamBytes[5] & 0xFF) != 10) return false; //<LINEFEED>
       
   707         if ((streamBytes[6] & 0xFF) != 26) return false; //<CTRL/Z>
       
   708         if ((streamBytes[7] & 0xFF) != 10) return false; //<LINEFEED>
       
   709         return true;
       
   710     }
       
   711     static boolean isGIFFormat(byte[] streamBytes)
       
   712     {
       
   713         if (streamBytes.length < 3) return false;
       
   714         if (streamBytes[0] != 'G') return false;
       
   715         if (streamBytes[1]  != 'I') return false;
       
   716         if (streamBytes[2]  != 'F') return false;
       
   717         return true;
       
   718     }
       
   719     static boolean isJPEGFormat(byte[] streamBytes)
       
   720     {
       
   721         if (streamBytes.length < 2) return false;
       
   722         if ((streamBytes[0] & 0xFF) != 0xFF) return false;
       
   723         if ((streamBytes[1] & 0xFF) != 0xD8) return false;
       
   724         return true;
       
   725     }
       
   726     /**
       
   727      * Reads the specified stream and returns the contents as a byte
       
   728      * array.
       
   729      *
       
   730      * @param stream the raw image data stream
       
   731      * @return image data buffer
       
   732      */
       
   733     static byte[] readImageStream(InputStream stream)
       
   734     {
       
   735         byte[] buffer = new byte[512];
       
   736         ByteArrayOutputStream baoStream = new ByteArrayOutputStream();
       
   737         if (buffer == null || baoStream == null)
       
   738         {
       
   739             SWT.error(SWT.ERROR_IO);
       
   740         }
       
   741         try
       
   742         {
       
   743             boolean done = false;
       
   744             while (!done)
       
   745             {
       
   746                 int length = stream.read(buffer);
       
   747                 if (-1 == length)
       
   748                 {
       
   749                     done = true;
       
   750                 }
       
   751                 else
       
   752                 {
       
   753                     baoStream.write(buffer,0,length);
       
   754                 }
       
   755             }
       
   756         }
       
   757         catch (IOException e)
       
   758         {
       
   759             SWT.error(SWT.ERROR_IO, e);
       
   760         }
       
   761         finally
       
   762         {
       
   763             try
       
   764             {
       
   765                 baoStream.close();
       
   766             }
       
   767             catch (IOException e)
       
   768             {
       
   769                 // ignore for the close
       
   770             }
       
   771         }
       
   772 
       
   773         return baoStream.toByteArray();
       
   774     }
       
   775 }