root/dwt/graphics/ImageData.d

Revision 246:fd9c62a2998e, 144.9 kB (checked in by Frank Benoit <benoit@tionex.de>, 6 months ago)

Updater SWT 3.4M7 to 3.4

Line 
1 /*******************************************************************************
2  * Copyright (c) 2000, 2008 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  * Port to the D programming language:
11  *     Frank Benoit <benoit@tionex.de>
12  *******************************************************************************/
13 module dwt.graphics.ImageData;
14
15
16 import dwt.graphics.PaletteData;
17 import dwt.graphics.RGB;
18 import dwt.graphics.Image;
19 import dwt.graphics.GC;
20 import dwt.graphics.Device;
21 import dwt.graphics.ImageDataLoader;
22 import dwt.DWT;
23 import dwt.internal.CloneableCompatibility;
24
25 public import dwt.dwthelper.InputStream;
26 import dwt.dwthelper.System;
27 import dwt.dwthelper.utils;
28
29
30 /**
31  * Instances of this class are device-independent descriptions
32  * of images. They are typically used as an intermediate format
33  * between loading from or writing to streams and creating an
34  * <code>Image</code>.
35  * <p>
36  * Note that the public fields <code>x</code>, <code>y</code>,
37  * <code>disposalMethod</code> and <code>delayTime</code> are
38  * typically only used when the image is in a set of images used
39  * for animation.
40  * </p>
41  *
42  * @see Image
43  * @see ImageLoader
44  * @see <a href="http://www.eclipse.org/swt/snippets/#image">ImageData snippets</a>
45  * @see <a href="http://www.eclipse.org/swt/examples.php">DWT Example: ImageAnalyzer</a>
46  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
47  */
48
49 public final class ImageData : CloneableCompatibility {
50
51     /**
52      * The width of the image, in pixels.
53      */
54     public int width;
55
56     /**
57      * The height of the image, in pixels.
58      */
59     public int height;
60
61     /**
62      * The color depth of the image, in bits per pixel.
63      * <p>
64      * Note that a depth of 8 or less does not necessarily
65      * mean that the image is palette indexed, or
66      * conversely that a depth greater than 8 means that
67      * the image is direct color.  Check the associated
68      * PaletteData's isDirect field for such determinations.
69      */
70     public int depth;
71
72     /**
73      * The scanline padding.
74      * <p>
75      * If one scanline of the image is not a multiple of
76      * this number, it will be padded with zeros until it is.
77      * </p>
78      */
79     public int scanlinePad;
80
81     /**
82      * The number of bytes per scanline.
83      * <p>
84      * This is a multiple of the scanline padding.
85      * </p>
86      */
87     public int bytesPerLine;
88
89     /**
90      * The pixel data of the image.
91      * <p>
92      * Note that for 16 bit depth images the pixel data is stored
93      * in least significant byte order; however, for 24bit and
94      * 32bit depth images the pixel data is stored in most
95      * significant byte order.
96      * </p>
97      */
98     public byte[] data;
99
100     /**
101      * The color table for the image.
102      */
103     public PaletteData palette;
104
105     /**
106      * The transparent pixel.
107      * <p>
108      * Pixels with this value are transparent.
109      * </p><p>
110      * The default is -1 which means 'no transparent pixel'.
111      * </p>
112      */
113     public int transparentPixel;
114
115     /**
116      * An icon-specific field containing the data from the icon mask.
117      * <p>
118      * This is a 1 bit bitmap stored with the most significant
119      * bit first.  The number of bytes per scanline is
120      * '((width + 7) / 8 + (maskPad - 1)) / maskPad * maskPad'.
121      * </p><p>
122      * The default is null which means 'no transparency mask'.
123      * </p>
124      */
125     public byte[] maskData;
126
127     /**
128      * An icon-specific field containing the scanline pad of the mask.
129      * <p>
130      * If one scanline of the transparency mask is not a
131      * multiple of this number, it will be padded with zeros until
132      * it is.
133      * </p>
134      */
135     public int maskPad;
136
137     /**
138      * The alpha data of the image.
139      * <p>
140      * Every pixel can have an <em>alpha blending</em> value that
141      * varies from 0, meaning fully transparent, to 255 meaning
142      * fully opaque.  The number of bytes per scanline is
143      * 'width'.
144      * </p>
145      */
146     public byte[] alphaData;
147
148     /**
149      * The global alpha value to be used for every pixel.
150      * <p>
151      * If this value is set, the <code>alphaData</code> field
152      * is ignored and when the image is rendered each pixel
153      * will be blended with the background an amount
154      * proportional to this value.
155      * </p><p>
156      * The default is -1 which means 'no global alpha value'
157      * </p>
158      */
159     public int alpha;
160
161     /**
162      * The type of file from which the image was read.
163      *
164      * It is expressed as one of the following values:
165      * <dl>
166      * <dt><code>IMAGE_BMP</code></dt>
167      * <dd>Windows BMP file format, no compression</dd>
168      * <dt><code>IMAGE_BMP_RLE</code></dt>
169      * <dd>Windows BMP file format, RLE compression if appropriate</dd>
170      * <dt><code>IMAGE_GIF</code></dt>
171      * <dd>GIF file format</dd>
172      * <dt><code>IMAGE_ICO</code></dt>
173      * <dd>Windows ICO file format</dd>
174      * <dt><code>IMAGE_JPEG</code></dt>
175      * <dd>JPEG file format</dd>
176      * <dt><code>IMAGE_PNG</code></dt>
177      * <dd>PNG file format</dd>
178      * </dl>
179      */
180     public int type;
181
182     /**
183      * The x coordinate of the top left corner of the image
184      * within the logical screen (this field corresponds to
185      * the GIF89a Image Left Position value).
186      */
187     public int x;
188
189     /**
190      * The y coordinate of the top left corner of the image
191      * within the logical screen (this field corresponds to
192      * the GIF89a Image Top Position value).
193      */
194     public int y;
195
196     /**
197      * A description of how to dispose of the current image
198      * before displaying the next.
199      *
200      * It is expressed as one of the following values:
201      * <dl>
202      * <dt><code>DM_UNSPECIFIED</code></dt>
203      * <dd>disposal method not specified</dd>
204      * <dt><code>DM_FILL_NONE</code></dt>
205      * <dd>do nothing - leave the image in place</dd>
206      * <dt><code>DM_FILL_BACKGROUND</code></dt>
207      * <dd>fill with the background color</dd>
208      * <dt><code>DM_FILL_PREVIOUS</code></dt>
209      * <dd>restore the previous picture</dd>
210      * </dl>
211      * (this field corresponds to the GIF89a Disposal Method value)
212      */
213     public int disposalMethod;
214
215     /**
216      * The time to delay before displaying the next image
217      * in an animation (this field corresponds to the GIF89a
218      * Delay Time value).
219      */
220     public int delayTime;
221
222     /**
223      * Arbitrary channel width data to 8-bit conversion table.
224      */
225     private static byte[][] ANY_TO_EIGHT;
226     private static byte[] ONE_TO_ONE_MAPPING;
227
228     private static bool static_this_completed = false;
229     private static void static_this() {
230         if( static_this_completed ) return;
231         synchronized {
232             if( static_this_completed ) return;
233             ANY_TO_EIGHT = new byte[][](9);
234             for (int b = 0; b < 9; ++b) {
235                 byte[] data = ANY_TO_EIGHT[b] = new byte[1 << b];
236                 if (b is 0) continue;
237                 int inc = 0;
238                 for (int bit = 0x10000; (bit >>= b) !is 0;) inc |= bit;
239                 for (int v = 0, p = 0; v < 0x10000; v+= inc) data[p++] = cast(byte)(v >> 8);
240             }
241             ONE_TO_ONE_MAPPING = ANY_TO_EIGHT[8];
242             static_this_completed = true;
243         }
244     }
245
246     /**
247      * Scaled 8x8 Bayer dither matrix.
248      */
249     static const int[][] DITHER_MATRIX = [
250         [ 0xfc0000, 0x7c0000, 0xdc0000, 0x5c0000, 0xf40000, 0x740000, 0xd40000, 0x540000 ],
251         [ 0x3c0000, 0xbc0000, 0x1c0000, 0x9c0000, 0x340000, 0xb40000, 0x140000, 0x940000 ],
252         [ 0xcc0000, 0x4c0000, 0xec0000, 0x6c0000, 0xc40000, 0x440000, 0xe40000, 0x640000 ],
253         [ 0x0c0000, 0x8c0000, 0x2c0000, 0xac0000, 0x040000, 0x840000, 0x240000, 0xa40000 ],
254         [ 0xf00000, 0x700000, 0xd00000, 0x500000, 0xf80000, 0x780000, 0xd80000, 0x580000 ],
255         [ 0x300000, 0xb00000, 0x100000, 0x900000, 0x380000, 0xb80000, 0x180000, 0x980000 ],
256         [ 0xc00000, 0x400000, 0xe00000, 0x600000, 0xc80000, 0x480000, 0xe80000, 0x680000 ],
257         [ 0x000000, 0x800000, 0x200000, 0xa00000, 0x080000, 0x880000, 0x280000, 0xa80000 ]
258     ];
259
260 /**
261  * Constructs a new, empty ImageData with the given width, height,
262  * depth and palette. The data will be initialized to an (all zero)
263  * array of the appropriate size.
264  *
265  * @param width the width of the image
266  * @param height the height of the image
267  * @param depth the depth of the image
268  * @param palette the palette of the image (must not be null)
269  *
270  * @exception IllegalArgumentException <ul>
271  *    <li>ERROR_INVALID_ARGUMENT - if the width or height is negative, or if the depth is not
272  *          one of 1, 2, 4, 8, 16, 24 or 32</li>
273  *    <li>ERROR_NULL_ARGUMENT - if the palette is null</li>
274  * </ul>
275  */
276 public this(int width, int height, int depth, PaletteData palette) {
277     this(width, height, depth, palette,
278         4, null, 0, null,
279         null, -1, -1, DWT.IMAGE_UNDEFINED,
280         0, 0, 0, 0);
281 }
282
283 /**
284  * Constructs a new, empty ImageData with the given width, height,
285  * depth, palette, scanlinePad and data.
286  *
287  * @param width the width of the image
288  * @param height the height of the image
289  * @param depth the depth of the image
290  * @param palette the palette of the image
291  * @param scanlinePad the padding of each line, in bytes
292  * @param data the data of the image
293  *
294  * @exception IllegalArgumentException <ul>
295  *    <li>ERROR_INVALID_ARGUMENT - if the width or height is negative, or if the depth is not
296  *          one of 1, 2, 4, 8, 16, 24 or 32, or the data array is too small to contain the image data</li>
297  *    <li>ERROR_NULL_ARGUMENT - if the palette or data is null</li>
298  *    <li>ERROR_CANNOT_BE_ZERO - if the scanlinePad is zero</li>
299  * </ul>
300  */
301 public this(int width, int height, int depth, PaletteData palette, int scanlinePad, byte[] data) {
302     this(width, height, depth, palette,
303         scanlinePad, checkData(data), 0, null,
304         null, -1, -1, DWT.IMAGE_UNDEFINED,
305         0, 0, 0, 0);
306 }
307
308 /**
309  * Constructs an <code>ImageData</code> loaded from the specified
310  * input stream. Throws an error if an error occurs while loading
311  * the image, or if the image has an unsupported type.  Application
312  * code is still responsible for closing the input stream.
313  * <p>
314  * This constructor is provided for convenience when loading a single
315  * image only. If the stream contains multiple images, only the first
316  * one will be loaded. To load multiple images, use
317  * <code>ImageLoader.load()</code>.
318  * </p><p>
319  * This constructor may be used to load a resource as follows:
320  * </p>
321  * <pre>
322  *     static ImageData loadImageData (Class clazz, String string) {
323  *          InputStream stream = clazz.getResourceAsStream (string);
324  *          if (stream is null) return null;
325  *          ImageData imageData = null;
326  *          try {
327  *               imageData = new ImageData (stream);
328  *          } catch (DWTException ex) {
329  *          } finally {
330  *               try {
331  *                    stream.close ();
332  *               } catch (IOException ex) {}
333  *          }
334  *          return imageData;
335  *     }
336  * </pre>
337  *
338  * @param stream the input stream to load the image from (must not be null)
339  *
340  * @exception IllegalArgumentException <ul>
341  *    <li>ERROR_NULL_ARGUMENT - if the stream is null</li>
342  * </ul>
343  * @exception DWTException <ul>
344  *    <li>ERROR_IO - if an IO error occurs while reading from the stream</li>
345  *    <li>ERROR_INVALID_IMAGE - if the image stream contains invalid data</li>
346  *    <li>ERROR_UNSUPPORTED_FORMAT - if the image stream contains an unrecognized format</li>
347  * </ul>
348  *
349  * @see ImageLoader#load(InputStream)
350  */
351 public this(InputStream stream) {
352     ImageData[] data = ImageDataLoader.load(stream);
353     if (data.length < 1) DWT.error(DWT.ERROR_INVALID_IMAGE);
354     ImageData i = data[0];
355     setAllFields(
356         i.width,
357         i.height,
358         i.depth,
359         i.scanlinePad,
360         i.bytesPerLine,
361         i.data,
362         i.palette,
363         i.transparentPixel,
364         i.maskData,
365         i.maskPad,
366         i.alphaData,
367         i.alpha,
368         i.type,
369         i.x,
370         i.y,
371         i.disposalMethod,
372         i.delayTime);
373 }
374
375 /**
376  * Constructs an <code>ImageData</code> loaded from a file with the
377  * specified name. Throws an error if an error occurs loading the
378  * image, or if the image has an unsupported type.
379  * <p>
380  * This constructor is provided for convenience when loading a single
381  * image only. If the file contains multiple images, only the first
382  * one will be loaded. To load multiple images, use
383  * <code>ImageLoader.load()</code>.
384  * </p>
385  *
386  * @param filename the name of the file to load the image from (must not be null)
387  *
388  * @exception IllegalArgumentException <ul>
389  *    <li>ERROR_NULL_ARGUMENT - if the file name is null</li>
390  * </ul>
391  * @exception DWTException <ul>
392  *    <li>ERROR_IO - if an IO error occurs while reading from the file</li>
393  *    <li>ERROR_INVALID_IMAGE - if the image file contains invalid data</li>
394  *    <li>ERROR_UNSUPPORTED_FORMAT - if the image file contains an unrecognized format</li>
395  * </ul>
396  */
397 public this(String filename) {
398     ImageData[] data = ImageDataLoader.load(filename);
399     if (data.length < 1) DWT.error(DWT.ERROR_INVALID_IMAGE);
400     ImageData i = data[0];
401     setAllFields(
402         i.width,
403         i.height,
404         i.depth,
405         i.scanlinePad,
406         i.bytesPerLine,
407         i.data,
408         i.palette,
409         i.transparentPixel,
410         i.maskData,
411         i.maskPad,
412         i.alphaData,
413         i.alpha,
414         i.type,
415         i.x,
416         i.y,
417         i.disposalMethod,
418         i.delayTime);
419 }
420
421 /**
422  * Prevents uninitialized instances from being created outside the package.
423  */
424 private this() {
425 }
426
427 /**
428  * Constructs an image data by giving values for all non-computable fields.
429  * <p>
430  * This method is for internal use, and is not described further.
431  * </p>
432  */
433 this(
434     int width, int height, int depth, PaletteData palette,
435     int scanlinePad, byte[] data, int maskPad, byte[] maskData,
436     byte[] alphaData, int alpha, int transparentPixel, int type,
437     int x, int y, int disposalMethod, int delayTime)
438 {
439     if (palette is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
440     if (!(depth is 1 || depth is 2 || depth is 4 || depth is 8
441         || depth is 16 || depth is 24 || depth is 32)) {
442         DWT.error(DWT.ERROR_INVALID_ARGUMENT);
443     }
444     if (width <= 0 || height <= 0) {
445         DWT.error(DWT.ERROR_INVALID_ARGUMENT);
446     }
447     if (scanlinePad is 0) DWT.error (DWT.ERROR_CANNOT_BE_ZERO);
448
449     int bytesPerLine = (((width * depth + 7) / 8) + (scanlinePad - 1))
450         / scanlinePad * scanlinePad;
451    
452     /*
453      * When the image is being loaded from a PNG, we need to use the theoretical minimum
454      * number of bytes per line to check whether there is enough data, because the actual
455      * number of bytes per line is calculated based on the given depth, which may be larger
456      * than the actual depth of the PNG.
457      */
458     int minBytesPerLine = type is DWT.IMAGE_PNG ? ((((width + 7) / 8) + 3) / 4) * 4 : bytesPerLine;
459     if (data !is null && data.length < minBytesPerLine * height) {
460         DWT.error(DWT.ERROR_INVALID_ARGUMENT);
461     }
462     setAllFields(
463         width,
464         height,
465         depth,
466         scanlinePad,
467         bytesPerLine,
468         data !is null ? data : new byte[bytesPerLine * height],
469         palette,
470         transparentPixel,
471         maskData,
472         maskPad,
473         alphaData,
474         alpha,
475         type,
476         x,
477         y,
478         disposalMethod,
479         delayTime);
480 }
481
482 /**
483  * Initializes all fields in the receiver. This method must be called
484  * by all public constructors to ensure that all fields are initialized
485  * for a new ImageData object. If a new field is added to the class,
486  * then it must be added to this method.
487  * <p>
488  * This method is for internal use, and is not described further.
489  * </p>
490  */
491 void setAllFields(int width, int height, int depth, int scanlinePad,
492     int bytesPerLine, byte[] data, PaletteData palette, int transparentPixel,
493     byte[] maskData, int maskPad, byte[] alphaData, int alpha,
494     int type, int x, int y, int disposalMethod, int delayTime) {
495
496     this.width = width;
497     this.height = height;
498     this.depth = depth;
499     this.scanlinePad = scanlinePad;
500     this.bytesPerLine = bytesPerLine;
501     this.data = data;
502     this.palette = palette;
503     this.transparentPixel = transparentPixel;
504     this.maskData = maskData;
505     this.maskPad = maskPad;
506     this.alphaData = alphaData;
507     this.alpha = alpha;
508     this.type = type;
509     this.x = x;
510     this.y = y;
511     this.disposalMethod = disposalMethod;
512     this.delayTime = delayTime;
513 }
514
515 /**
516  * Invokes internal DWT functionality to create a new instance of
517  * this class.
518  * <p>
519  * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
520  * API for <code>ImageData</code>. It is marked public only so that it
521  * can be shared within the packages provided by DWT. It is subject
522  * to change without notice, and should never be called from
523  * application code.
524  * </p>
525  * <p>
526  * This method is for internal use, and is not described further.
527  * </p>
528  */
529 public static ImageData internal_new(
530     int width, int height, int depth, PaletteData palette,
531     int scanlinePad, byte[] data, int maskPad, byte[] maskData,
532     byte[] alphaData, int alpha, int transparentPixel, int type,
533     int x, int y, int disposalMethod, int delayTime)
534 {
535     return new ImageData(
536         width, height, depth, palette, scanlinePad, data, maskPad, maskData,
537         alphaData, alpha, transparentPixel, type, x, y, disposalMethod, delayTime);
538 }
539
540 ImageData colorMaskImage(int pixel) {
541     ImageData mask = new ImageData(width, height, 1, bwPalette(),
542         2, null, 0, null, null, -1, -1, DWT.IMAGE_UNDEFINED,
543         0, 0, 0, 0);
544     int[] row = new int[width];
545     for (int y = 0; y < height; y++) {
546         getPixels(0, y, width, row, 0);
547         for (int i = 0; i < width; i++) {
548             if (pixel !is -1 && row[i] is pixel) {
549                 row[i] = 0;
550             } else {
551                 row[i] = 1;
552             }
553         }
554         mask.setPixels(0, y, width, row, 0);
555     }
556     return mask;
557 }
558
559 static byte[] checkData(byte [] data) {
560     if (data is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
561     return data;
562 }
563
564 /**
565  * Returns a new instance of the same class as the receiver,
566  * whose slots have been filled in with <em>copies</em> of
567  * the values in the slots of the receiver. That is, the
568  * returned object is a <em>deep copy</em> of the receiver.
569  *
570  * @return a copy of the receiver.
571  */
572 public Object clone() {
573     byte[] cloneData = new byte[data.length];
574     System.arraycopy(data, 0, cloneData, 0, data.length);
575     byte[] cloneMaskData = null;
576     if (maskData !is null) {
577         cloneMaskData = new byte[maskData.length];
578         System.arraycopy(maskData, 0, cloneMaskData, 0, maskData.length);
579     }
580     byte[] cloneAlphaData = null;
581     if (alphaData !is null) {
582         cloneAlphaData = new byte[alphaData.length];
583         System.arraycopy(alphaData, 0, cloneAlphaData, 0, alphaData.length);
584     }
585     return new ImageData(
586         width,
587         height,
588         depth,
589         palette,
590         scanlinePad,
591         cloneData,
592         maskPad,
593         cloneMaskData,
594         cloneAlphaData,
595         alpha,
596         transparentPixel,
597         type,
598         x,
599         y,
600         disposalMethod,
601         delayTime);
602 }
603
604 /**
605  * Returns the alpha value at offset <code>x</code> in
606  * scanline <code>y</code> in the receiver's alpha data.
607  * The alpha value is between 0 (transparent) and
608  * 255 (opaque).
609  *
610  * @param x the x coordinate of the pixel to get the alpha value of
611  * @param y the y coordinate of the pixel to get the alpha value of
612  * @return the alpha value at the given coordinates
613  *
614  * @exception IllegalArgumentException <ul>
615  *    <li>ERROR_INVALID_ARGUMENT - if either argument is out of range</li>
616  * </ul>
617  */
618 public int getAlpha(int x, int y) {
619     if (x >= width || y >= height || x < 0 || y < 0) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
620
621     if (alphaData is null) return 255;
622     return alphaData[y * width + x] & 0xFF;
623 }
624
625 /**
626  * Returns <code>getWidth</code> alpha values starting at offset
627  * <code>x</code> in scanline <code>y</code> in the receiver's alpha
628  * data starting at <code>startIndex</code>. The alpha values
629  * are unsigned, between <code>(byte)0</code> (transparent) and
630  * <code>(byte)255</code> (opaque).
631  *
632  * @param x the x position of the pixel to begin getting alpha values
633  * @param y the y position of the pixel to begin getting alpha values
634  * @param getWidth the width of the data to get
635  * @param alphas the buffer in which to put the alpha values
636  * @param startIndex the offset into the image to begin getting alpha values
637  *
638  * @exception IndexOutOfBoundsException if getWidth is too large
639  * @exception IllegalArgumentException <ul>
640  *    <li>ERROR_NULL_ARGUMENT - if pixels is null</li>
641  *    <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
642  *    <li>ERROR_INVALID_ARGUMENT - if getWidth is negative</li>
643  * </ul>
644  */
645 public void getAlphas(int x, int y, int getWidth, byte[] alphas, int startIndex) {
646     if (alphas is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
647     if (getWidth < 0 || x >= width || y >= height || x < 0 || y < 0) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
648     if (getWidth is 0) return;
649
650     if (alphaData is null) {
651         int endIndex = startIndex + getWidth;
652         for (int i = startIndex; i < endIndex; i++) {
653             alphas[i] = cast(byte)255;
654         }
655         return;
656     }
657     // may throw an IndexOutOfBoundsException
658     System.arraycopy(alphaData, y * width + x, alphas, startIndex, getWidth);
659 }
660
661 /**
662  * Returns the pixel value at offset <code>x</code> in
663  * scanline <code>y</code> in the receiver's data.
664  *
665  * @param x the x position of the pixel to get
666  * @param y the y position of the pixel to get
667  * @return the pixel at the given coordinates
668  *
669  * @exception IllegalArgumentException <ul>
670  *    <li>ERROR_INVALID_ARGUMENT - if either argument is out of bounds</li>
671  * </ul>
672  * @exception DWTException <ul>
673  *    <li>ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8, 16, 24 or 32</li>
674  * </ul>
675  */
676 public int getPixel(int x, int y) {
677     if (x >= width || y >= height || x < 0 || y < 0) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
678     int index;
679     int theByte;