KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > swt > graphics > ImageData


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 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  *******************************************************************************/

11 package org.eclipse.swt.graphics;
12
13
14 import java.io.*;
15 import org.eclipse.swt.*;
16 import org.eclipse.swt.internal.CloneableCompatibility;
17
18 /**
19  * Instances of this class are device-independent descriptions
20  * of images. They are typically used as an intermediate format
21  * between loading from or writing to streams and creating an
22  * <code>Image</code>.
23  * <p>
24  * Note that the public fields <code>x</code>, <code>y</code>,
25  * <code>disposalMethod</code> and <code>delayTime</code> are
26  * typically only used when the image is in a set of images used
27  * for animation.
28  * </p>
29  *
30  * @see Image
31  * @see ImageLoader
32  */

33
34 public final class ImageData implements CloneableCompatibility {
35     
36     /**
37      * The width of the image, in pixels.
38      */

39     public int width;
40
41     /**
42      * The height of the image, in pixels.
43      */

44     public int height;
45
46     /**
47      * The color depth of the image, in bits per pixel.
48      * <p>
49      * Note that a depth of 8 or less does not necessarily
50      * mean that the image is palette indexed, or
51      * conversely that a depth greater than 8 means that
52      * the image is direct color. Check the associated
53      * PaletteData's isDirect field for such determinations.
54      */

55     public int depth;
56
57     /**
58      * The scanline padding.
59      * <p>
60      * If one scanline of the image is not a multiple of
61      * this number, it will be padded with zeros until it is.
62      * </p>
63      */

64     public int scanlinePad;
65
66     /**
67      * The number of bytes per scanline.
68      * <p>
69      * This is a multiple of the scanline padding.
70      * </p>
71      */

72     public int bytesPerLine;
73
74     /**
75      * The pixel data of the image.
76      * <p>
77      * Note that for 16 bit depth images the pixel data is stored
78      * in least significant byte order; however, for 24bit and
79      * 32bit depth images the pixel data is stored in most
80      * significant byte order.
81      * </p>
82      */

83     public byte[] data;
84
85     /**
86      * The color table for the image.
87      */

88     public PaletteData palette;
89
90     /**
91      * The transparent pixel.
92      * <p>
93      * Pixels with this value are transparent.
94      * </p><p>
95      * The default is -1 which means 'no transparent pixel'.
96      * </p>
97      */

98     public int transparentPixel;
99
100     /**
101      * An icon-specific field containing the data from the icon mask.
102      * <p>
103      * This is a 1 bit bitmap stored with the most significant
104      * bit first. The number of bytes per scanline is
105      * '((width + 7) / 8 + (maskPad - 1)) / maskPad * maskPad'.
106      * </p><p>
107      * The default is null which means 'no transparency mask'.
108      * </p>
109      */

110     public byte[] maskData;
111
112     /**
113      * An icon-specific field containing the scanline pad of the mask.
114      * <p>
115      * If one scanline of the transparency mask is not a
116      * multiple of this number, it will be padded with zeros until
117      * it is.
118      * </p>
119      */

120     public int maskPad;
121     
122     /**
123      * The alpha data of the image.
124      * <p>
125      * Every pixel can have an <em>alpha blending</em> value that
126      * varies from 0, meaning fully transparent, to 255 meaning
127      * fully opaque. The number of bytes per scanline is
128      * 'width'.
129      * </p>
130      */

131     public byte[] alphaData;
132     
133     /**
134      * The global alpha value to be used for every pixel.
135      * <p>
136      * If this value is set, the <code>alphaData</code> field
137      * is ignored and when the image is rendered each pixel
138      * will be blended with the background an amount
139      * proportional to this value.
140      * </p><p>
141      * The default is -1 which means 'no global alpha value'
142      * </p>
143      */

144     public int alpha;
145
146     /**
147      * The type of file from which the image was read.
148      *
149      * It is expressed as one of the following values:
150      * <dl>
151      * <dt><code>IMAGE_BMP</code></dt>
152      * <dd>Windows BMP file format, no compression</dd>
153      * <dt><code>IMAGE_BMP_RLE</code></dt>
154      * <dd>Windows BMP file format, RLE compression if appropriate</dd>
155      * <dt><code>IMAGE_GIF</code></dt>
156      * <dd>GIF file format</dd>
157      * <dt><code>IMAGE_ICO</code></dt>
158      * <dd>Windows ICO file format</dd>
159      * <dt><code>IMAGE_JPEG</code></dt>
160      * <dd>JPEG file format</dd>
161      * <dt><code>IMAGE_PNG</code></dt>
162      * <dd>PNG file format</dd>
163      * </dl>
164      */

165     public int type;
166
167     /**
168      * The x coordinate of the top left corner of the image
169      * within the logical screen (this field corresponds to
170      * the GIF89a Image Left Position value).
171      */

172     public int x;
173
174     /**
175      * The y coordinate of the top left corner of the image
176      * within the logical screen (this field corresponds to
177      * the GIF89a Image Top Position value).
178      */

179     public int y;
180
181     /**
182      * A description of how to dispose of the current image
183      * before displaying the next.
184      *
185      * It is expressed as one of the following values:
186      * <dl>
187      * <dt><code>DM_UNSPECIFIED</code></dt>
188      * <dd>disposal method not specified</dd>
189      * <dt><code>DM_FILL_NONE</code></dt>
190      * <dd>do nothing - leave the image in place</dd>
191      * <dt><code>DM_FILL_BACKGROUND</code></dt>
192      * <dd>fill with the background color</dd>
193      * <dt><code>DM_FILL_PREVIOUS</code></dt>
194      * <dd>restore the previous picture</dd>
195      * </dl>
196      * (this field corresponds to the GIF89a Disposal Method value)
197      */

198     public int disposalMethod;
199
200     /**
201      * The time to delay before displaying the next image
202      * in an animation (this field corresponds to the GIF89a
203      * Delay Time value).
204      */

205     public int delayTime;
206
207     /**
208      * Arbitrary channel width data to 8-bit conversion table.
209      */

210     static final byte[][] ANY_TO_EIGHT = new byte[9][];
211     static {
212         for (int b = 0; b < 9; ++b) {
213             byte[] data = ANY_TO_EIGHT[b] = new byte[1 << b];
214             if (b == 0) continue;
215             int inc = 0;
216             for (int bit = 0x10000; (bit >>= b) != 0;) inc |= bit;
217             for (int v = 0, p = 0; v < 0x10000; v+= inc) data[p++] = (byte)(v >> 8);
218         }
219     }
220     static final byte[] ONE_TO_ONE_MAPPING = ANY_TO_EIGHT[8];
221
222     /**
223      * Scaled 8x8 Bayer dither matrix.
224      */

225     static final int[][] DITHER_MATRIX = {
226         { 0xfc0000, 0x7c0000, 0xdc0000, 0x5c0000, 0xf40000, 0x740000, 0xd40000, 0x540000 },
227         { 0x3c0000, 0xbc0000, 0x1c0000, 0x9c0000, 0x340000, 0xb40000, 0x140000, 0x940000 },
228         { 0xcc0000, 0x4c0000, 0xec0000, 0x6c0000, 0xc40000, 0x440000, 0xe40000, 0x640000 },
229         { 0x0c0000, 0x8c0000, 0x2c0000, 0xac0000, 0x040000, 0x840000, 0x240000, 0xa40000 },
230         { 0xf00000, 0x700000, 0xd00000, 0x500000, 0xf80000, 0x780000, 0xd80000, 0x580000 },
231         { 0x300000, 0xb00000, 0x100000, 0x900000, 0x380000, 0xb80000, 0x180000, 0x980000 },
232         { 0xc00000, 0x400000, 0xe00000, 0x600000, 0xc80000, 0x480000, 0xe80000, 0x680000 },
233         { 0x000000, 0x800000, 0x200000, 0xa00000, 0x080000, 0x880000, 0x280000, 0xa80000 }
234     };
235
236 /**
237  * Constructs a new, empty ImageData with the given width, height,
238  * depth and palette. The data will be initialized to an (all zero)
239  * array of the appropriate size.
240  *
241  * @param width the width of the image
242  * @param height the height of the image
243  * @param depth the depth of the image
244  * @param palette the palette of the image (must not be null)
245  *
246  * @exception IllegalArgumentException <ul>
247  * <li>ERROR_INVALID_ARGUMENT - if the width or height is negative, or if the depth is not
248  * one of 1, 2, 4, 8, 16, 24 or 32</li>
249  * <li>ERROR_NULL_ARGUMENT - if the palette is null</li>
250  * </ul>
251  */

252 public ImageData(int width, int height, int depth, PaletteData palette) {
253     this(width, height, depth, palette,
254         4, null, 0, null,
255         null, -1, -1, SWT.IMAGE_UNDEFINED,
256         0, 0, 0, 0);
257 }
258
259 /**
260  * Constructs a new, empty ImageData with the given width, height,
261  * depth, palette, scanlinePad and data.
262  *
263  * @param width the width of the image
264  * @param height the height of the image
265  * @param depth the depth of the image
266  * @param palette the palette of the image
267  * @param scanlinePad the padding of each line, in bytes
268  * @param data the data of the image
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 or data is null</li>
274  * <li>ERROR_CANNOT_BE_ZERO - if the scanlinePad is zero</li>
275  * </ul>
276  */

277 public ImageData(int width, int height, int depth, PaletteData palette, int scanlinePad, byte[] data) {
278     this(width, height, depth, palette,
279         scanlinePad, checkData(data), 0, null,
280         null, -1, -1, SWT.IMAGE_UNDEFINED,
281         0, 0, 0, 0);
282 }
283
284 /**
285  * Constructs an <code>ImageData</code> loaded from the specified
286  * input stream. Throws an error if an error occurs while loading
287  * the image, or if the image has an unsupported type. Application
288  * code is still responsible for closing the input stream.
289  * <p>
290  * This constructor is provided for convenience when loading a single
291  * image only. If the stream contains multiple images, only the first
292  * one will be loaded. To load multiple images, use
293  * <code>ImageLoader.load()</code>.
294  * </p><p>
295  * This constructor may be used to load a resource as follows:
296  * </p>
297  * <pre>
298  * static ImageData loadImageData (Class clazz, String string) {
299  * InputStream stream = clazz.getResourceAsStream (string);
300  * if (stream == null) return null;
301  * ImageData imageData = null;
302  * try {
303  * imageData = new ImageData (stream);
304  * } catch (SWTException ex) {
305  * } finally {
306  * try {
307  * stream.close ();
308  * } catch (IOException ex) {}
309  * }
310  * return imageData;
311  * }
312  * </pre>
313  *
314  * @param stream the input stream to load the image from (must not be null)
315  *
316  * @exception IllegalArgumentException <ul>
317  * <li>ERROR_NULL_ARGUMENT - if the stream is null</li>
318  * </ul>
319  * @exception SWTException <ul>
320  * <li>ERROR_IO - if an IO error occurs while reading from the stream</li>
321  * <li>ERROR_INVALID_IMAGE - if the image stream contains invalid data</li>
322  * <li>ERROR_UNSUPPORTED_FORMAT - if the image stream contains an unrecognized format</li>
323  * </ul>
324  *
325  * @see ImageLoader#load(InputStream)
326  */

327 public ImageData(InputStream stream) {
328     ImageData[] data = ImageDataLoader.load(stream);
329     if (data.length < 1) SWT.error(SWT.ERROR_INVALID_IMAGE);
330     ImageData i = data[0];
331     setAllFields(
332         i.width,
333         i.height,
334         i.depth,
335         i.scanlinePad,
336         i.bytesPerLine,
337         i.data,
338         i.palette,
339         i.transparentPixel,
340         i.maskData,
341         i.maskPad,
342         i.alphaData,
343         i.alpha,
344         i.type,
345         i.x,
346         i.y,
347         i.disposalMethod,
348         i.delayTime);
349 }
350
351 /**
352  * Constructs an <code>ImageData</code> loaded from a file with the
353  * specified name. Throws an error if an error occurs loading the
354  * image, or if the image has an unsupported type.
355  * <p>
356  * This constructor is provided for convenience when loading a single
357  * image only. If the file contains multiple images, only the first
358  * one will be loaded. To load multiple images, use
359  * <code>ImageLoader.load()</code>.
360  * </p>
361  *
362  * @param filename the name of the file to load the image from (must not be null)
363  *
364  * @exception IllegalArgumentException <ul>
365  * <li>ERROR_NULL_ARGUMENT - if the file name is null</li>
366  * </ul>
367  * @exception SWTException <ul>
368  * <li>ERROR_IO - if an IO error occurs while reading from the file</li>
369  * <li>ERROR_INVALID_IMAGE - if the image file contains invalid data</li>
370  * <li>ERROR_UNSUPPORTED_FORMAT - if the image file contains an unrecognized format</li>
371  * </ul>
372  */

373 public ImageData(String JavaDoc filename) {
374     ImageData[] data = ImageDataLoader.load(filename);
375     if (data.length < 1) SWT.error(SWT.ERROR_INVALID_IMAGE);
376     ImageData i = data[0];
377     setAllFields(
378         i.width,
379         i.height,
380         i.depth,
381         i.scanlinePad,
382         i.bytesPerLine,
383         i.data,
384         i.palette,
385         i.transparentPixel,
386         i.maskData,
387         i.maskPad,
388         i.alphaData,
389         i.alpha,
390         i.type,
391         i.x,
392         i.y,
393         i.disposalMethod,
394         i.delayTime);
395 }
396
397 /**
398  * Prevents uninitialized instances from being created outside the package.
399  */

400 ImageData() {
401 }
402
403 /**
404  * Constructs an image data by giving values for all non-computable fields.
405  * <p>
406  * This method is for internal use, and is not described further.
407  * </p>
408  */

409 ImageData(
410     int width, int height, int depth, PaletteData palette,
411     int scanlinePad, byte[] data, int maskPad, byte[] maskData,
412     byte[] alphaData, int alpha, int transparentPixel, int type,
413     int x, int y, int disposalMethod, int delayTime)
414 {
415
416     if (palette == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
417     if (!(depth == 1 || depth == 2 || depth == 4 || depth == 8
418         || depth == 16 || depth == 24 || depth == 32)) {
419         SWT.error(SWT.ERROR_INVALID_ARGUMENT);
420     }
421     if (width <= 0 || height <= 0) {
422         SWT.error(SWT.ERROR_INVALID_ARGUMENT);
423     }
424     if (scanlinePad == 0) SWT.error (SWT.ERROR_CANNOT_BE_ZERO);
425
426     int bytesPerLine = (((width * depth + 7) / 8) + (scanlinePad - 1))
427         / scanlinePad * scanlinePad;
428     setAllFields(
429         width,
430         height,
431         depth,
432         scanlinePad,
433         bytesPerLine,
434         data != null ? data : new byte[bytesPerLine * height],
435         palette,
436         transparentPixel,
437         maskData,
438         maskPad,
439         alphaData,
440         alpha,
441         type,
442         x,
443         y,
444         disposalMethod,
445         delayTime);
446 }
447
448 /**
449  * Initializes all fields in the receiver. This method must be called
450  * by all public constructors to ensure that all fields are initialized
451  * for a new ImageData object. If a new field is added to the class,
452  * then it must be added to this method.
453  * <p>
454  * This method is for internal use, and is not described further.
455  * </p>
456  */

457 void setAllFields(int width, int height, int depth, int scanlinePad,
458     int bytesPerLine, byte[] data, PaletteData palette, int transparentPixel,
459     byte[] maskData, int maskPad, byte[] alphaData, int alpha,
460     int type, int x, int y, int disposalMethod, int delayTime) {
461
462     this.width = width;
463     this.height = height;
464     this.depth = depth;
465     this.scanlinePad = scanlinePad;
466     this.bytesPerLine = bytesPerLine;
467     this.data = data;
468     this.palette = palette;
469     this.transparentPixel = transparentPixel;
470     this.maskData = maskData;
471     this.maskPad = maskPad;
472     this.alphaData = alphaData;
473     this.alpha = alpha;
474     this.type = type;
475     this.x = x;
476     this.y = y;
477     this.disposalMethod = disposalMethod;
478     this.delayTime = delayTime;
479 }
480
481 /**
482  * Invokes internal SWT functionality to create a new instance of
483  * this class.
484  * <p>
485  * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
486  * API for <code>ImageData</code>. It is marked public only so that it
487  * can be shared within the packages provided by SWT. It is subject
488  * to change without notice, and should never be called from
489  * application code.
490  * </p>
491  * <p>
492  * This method is for internal use, and is not described further.
493  * </p>
494  */

495 public static ImageData internal_new(
496     int width, int height, int depth, PaletteData palette,
497     int scanlinePad, byte[] data, int maskPad, byte[] maskData,
498     byte[] alphaData, int alpha, int transparentPixel, int type,
499     int x, int y, int disposalMethod, int delayTime)
500 {
501     return new ImageData(
502         width, height, depth, palette, scanlinePad, data, maskPad, maskData,
503         alphaData, alpha, transparentPixel, type, x, y, disposalMethod, delayTime);
504 }
505
506 ImageData colorMaskImage(int pixel) {
507     ImageData mask = new ImageData(width, height, 1, bwPalette(),
508         2, null, 0, null, null, -1, -1, SWT.IMAGE_UNDEFINED,
509         0, 0, 0, 0);
510     int[] row = new int[width];
511     for (int y = 0; y < height; y++) {
512         getPixels(0, y, width, row, 0);
513         for (int i = 0; i < width; i++) {
514             if (pixel != -1 && row[i] == pixel) {
515                 row[i] = 0;
516             } else {
517                 row[i] = 1;
518             }
519         }
520         mask.setPixels(0, y, width, row, 0);
521     }
522     return mask;
523 }
524
525 static byte[] checkData(byte [] data) {
526     if (data == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
527     return data;
528 }
529
530 /**
531  * Returns a new instance of the same class as the receiver,
532  * whose slots have been filled in with <em>copies</em> of
533  * the values in the slots of the receiver. That is, the
534  * returned object is a <em>deep copy</em> of the receiver.
535  *
536  * @return a copy of the receiver.
537  */

538 public Object JavaDoc clone() {
539     byte[] cloneData = new byte[data.length];
540     System.arraycopy(data, 0, cloneData, 0, data.length);
541     byte[] cloneMaskData = null;
542     if (maskData != null) {
543         cloneMaskData = new byte[maskData.length];
544         System.arraycopy(maskData, 0, cloneMaskData, 0, maskData.length);
545     }
546     byte[] cloneAlphaData = null;
547     if (alphaData != null) {
548         cloneAlphaData = new byte[alphaData.length];
549         System.arraycopy(alphaData, 0, cloneAlphaData, 0, alphaData.length);
550     }
551     return new ImageData(
552         width,
553         height,
554         depth,
555         palette,
556         scanlinePad,
557         cloneData,
558         maskPad,
559         cloneMaskData,
560         cloneAlphaData,
561         alpha,
562         transparentPixel,
563         type,
564         x,
565         y,
566         disposalMethod,
567         delayTime);
568 }
569
570 /**
571  * Returns the alpha value at offset <code>x</code> in
572  * scanline <code>y</code> in the receiver's alpha data.
573  *
574  * @param x the x coordinate of the pixel to get the alpha value of
575  * @param y the y coordinate of the pixel to get the alpha value of
576  * @return the alpha value at the given coordinates
577  *
578  * @exception IllegalArgumentException <ul>
579  * <li>ERROR_INVALID_ARGUMENT - if either argument is out of range</li>
580  * </ul>
581  */

582 public int getAlpha(int x, int y) {
583     if (x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
584
585     if (alphaData == null) return 255;
586     return alphaData[y * width + x] & 0xFF;
587 }
588
589 /**
590  * Returns <code>getWidth</code> alpha values starting at offset
591  * <code>x</code> in scanline <code>y</code> in the receiver's alpha
592  * data starting at <code>startIndex</code>.
593  *
594  * @param x the x position of the pixel to begin getting alpha values
595  * @param y the y position of the pixel to begin getting alpha values
596  * @param getWidth the width of the data to get
597  * @param alphas the buffer in which to put the alpha values
598  * @param startIndex the offset into the image to begin getting alpha values
599  *
600  * @exception IndexOutOfBoundsException if getWidth is too large
601  * @exception IllegalArgumentException <ul>
602  * <li>ERROR_NULL_ARGUMENT - if pixels is null</li>
603  * <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
604  * <li>ERROR_INVALID_ARGUMENT - if getWidth is negative</li>
605  * </ul>
606  */

607 public void getAlphas(int x, int y, int getWidth, byte[] alphas, int startIndex) {
608     if (alphas == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
609     if (getWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
610     if (getWidth == 0) return;
611
612     if (alphaData == null) {
613         int endIndex = startIndex + getWidth;
614         for (int i = startIndex; i < endIndex; i++) {
615             alphas[i] = (byte)255;
616         }
617         return;
618     }
619     // may throw an IndexOutOfBoundsException
620
System.arraycopy(alphaData, y * width + x, alphas, startIndex, getWidth);
621 }
622
623 /**
624  * Returns the pixel value at offset <code>x</code> in
625  * scanline <code>y</code> in the receiver's data.
626  *
627  * @param x the x position of the pixel to get
628  * @param y the y position of the pixel to get
629  * @return the pixel at the given coordinates
630  *
631  * @exception IllegalArgumentException <ul>
632  * <li>ERROR_INVALID_ARGUMENT - if either argument is out of bounds</li>
633  * </ul>
634  * @exception SWTException <ul>
635  * <li>ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8, 16, 24 or 32</li>
636  * </ul>
637  */

638 public int getPixel(int x, int y) {
639     if (x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
640     int index;
641     int theByte;
642     int mask;
643     switch (depth) {
644         case 32:
645             index = (y * bytesPerLine) + (x * 4);
646             return ((data[index] & 0xFF) << 24) + ((data[index+1] & 0xFF) << 16) +
647                     ((data[index+2] & 0xFF) << 8) + (data[index+3] & 0xFF);
648         case 24:
649             index = (y * bytesPerLine) + (x * 3);
650             return ((data[index] & 0xFF) << 16) + ((data[index+1] & 0xFF) << 8) +
651                 (data[index+2] & 0xFF);
652         case 16:
653             index = (y * bytesPerLine) + (x * 2);
654             return ((data[index+1] & 0xFF) << 8) + (data[index] & 0xFF);
655         case 8:
656             index = (y * bytesPerLine) + x ;
657             return data[index] & 0xFF;
658         case 4:
659             index = (y * bytesPerLine) + (x >> 1);
660             theByte = data[index] & 0xFF;
661             if ((x & 0x1) == 0) {
662                 return theByte >> 4;
663             } else {
664                 return theByte & 0x0F;
665             }
666         case 2:
667             index = (y * bytesPerLine) + (x >> 2);
668             theByte = data[index] & 0xFF;
669             int offset = 3 - (x % 4);
670             mask = 3 << (offset * 2);
671             return (theByte & mask) >> (offset * 2);
672         case 1:
673             index = (y * bytesPerLine) + (x >> 3);
674             theByte = data[index] & 0xFF;
675             mask = 1 << (7 - (x & 0x7));
676             if ((theByte & mask) == 0) {
677                 return 0;
678             } else {
679                 return 1;
680             }
681     }
682     SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
683     return 0;
684 }
685
686 /**
687  * Returns <code>getWidth</code> pixel values starting at offset
688  * <code>x</code> in scanline <code>y</code> in the receiver's
689  * data starting at <code>startIndex</code>.
690  *
691  * @param x the x position of the first pixel to get
692  * @param y the y position of the first pixel to get
693  * @param getWidth the width of the data to get
694  * @param pixels the buffer in which to put the pixels
695  * @param startIndex the offset into the byte array to begin storing pixels
696  *
697  * @exception IndexOutOfBoundsException if getWidth is too large
698  * @exception IllegalArgumentException <ul>
699  * <li>ERROR_NULL_ARGUMENT - if pixels is null</li>
700  * <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
701  * <li>ERROR_INVALID_ARGUMENT - if getWidth is negative</li>
702  * </ul>
703  * @exception SWTException <ul>
704  * <li>ERROR_UNSUPPORTED_DEPTH - if the depth is not one of 1, 2, 4 or 8
705  * (For higher depths, use the int[] version of this method.)</li>
706  * </ul>
707  */

708 public void getPixels(int x, int y, int getWidth, byte[] pixels, int startIndex) {
709     if (pixels == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
710     if (getWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
711     if (getWidth == 0) return;
712     int index;
713     int theByte;
714     int mask = 0;
715     int n = getWidth;
716     int i = startIndex;
717     int srcX = x, srcY = y;
718     switch (depth) {
719         case 8:
720             index = (y * bytesPerLine) + x;
721             for (int j = 0; j < getWidth; j++) {
722                 pixels[i] = data[index];
723                 i++;
724                 srcX++;
725                 if (srcX >= width) {
726                     srcY++;
727                     index = srcY * bytesPerLine;
728                     srcX = 0;
729                 } else {
730                     index++;
731                 }
732             }
733             return;
734         case 4:
735             index = (y * bytesPerLine) + (x >> 1);
736             if ((x & 0x1) == 1) {
737                 theByte = data[index] & 0xFF;
738                 pixels[i] = (byte)(theByte & 0x0F);
739                 i++;
740                 n--;
741                 srcX++;
742                 if (srcX >= width) {
743                     srcY++;
744                     index = srcY * bytesPerLine;
745                     srcX = 0;
746                 } else {
747                     index++;
748                 }
749             }
750             while (n > 1) {
751                 theByte = data[index] & 0xFF;
752                 pixels[i] = (byte)(theByte >> 4);
753                 i++;
754                 n--;
755                 srcX++;
756                 if (srcX >= width) {
757                     srcY++;
758                     index = srcY * bytesPerLine;
759                     srcX = 0;
760                 } else {
761                     pixels[i] = (byte)(theByte & 0x0F);
762                     i++;
763                     n--;
764                     srcX++;
765                     if (srcX >= width) {
766                         srcY++;
767                         index = srcY * bytesPerLine;
768                         srcX = 0;
769                     } else {
770                         index++;
771                     }
772                 }
773             }
774             if (n > 0) {
775                 theByte = data[index] & 0xFF;
776                 pixels[i] = (byte)(theByte >> 4);
777             }
778             return;
779         case 2:
780             index = (y * bytesPerLine) + (x >> 2);
781             theByte = data[index] & 0xFF;
782             int offset;
783             while (n > 0) {
784                 offset = 3 - (srcX % 4);
785                 mask = 3 << (offset * 2);
786                 pixels[i] = (byte)((theByte & mask) >> (offset * 2));
787                 i++;
788                 n--;
789                 srcX++;
790                 if (srcX >= width) {
791                     srcY++;
792                     index = srcY * bytesPerLine;
793                     if (n > 0) theByte = data[index] & 0xFF;
794                     srcX = 0;
795                 } else {
796                     if (offset == 0) {
797                         index++;
798                         theByte = data[index] & 0xFF;
799                     }
800                 }
801             }
802             return;
803         case 1:
804             index = (y * bytesPerLine) + (x >> 3);
805             theByte = data[index] & 0xFF;
806             while (n > 0) {
807                 mask = 1 << (7 - (srcX & 0x7));
808                 if ((theByte & mask) == 0) {
809                     pixels[i] = 0;
810                 } else {
811                     pixels[i] = 1;
812                 }
813                 i++;
814                 n--;
815                 srcX++;
816                 if (srcX >= width) {
817                     srcY++;
818                     index = srcY * bytesPerLine;
819                     if (n > 0) theByte = data[index] & 0xFF;
820                     srcX = 0;
821                 } else {
822                     if (mask == 1) {
823                         index++;
824                         if (n > 0) theByte = data[index] & 0xFF;
825                     }
826                 }
827             }
828             return;
829     }
830     SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
831 }
832
833 /**
834  * Returns <code>getWidth</code> pixel values starting at offset
835  * <code>x</code> in scanline <code>y</code> in the receiver's
836  * data starting at <code>startIndex</code>.
837  *
838  * @param x the x position of the first pixel to get
839  * @param y the y position of the first pixel to get
840  * @param getWidth the width of the data to get
841  * @param pixels the buffer in which to put the pixels
842  * @param startIndex the offset into the buffer to begin storing pixels
843  *
844  * @exception IndexOutOfBoundsException if getWidth is too large
845  * @exception IllegalArgumentException <ul>
846  * <li>ERROR_NULL_ARGUMENT - if pixels is null</li>
847  * <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
848  * <li>ERROR_INVALID_ARGUMENT - if getWidth is negative</li>
849  * </ul>
850  * @exception SWTException <ul>
851  * <li>ERROR_UNSUPPORTED_DEPTH - if the depth is not one of 1, 2, 4, 8, 16, 24 or 32</li>
852  * </ul>
853  */

854 public void getPixels(int x, int y, int getWidth, int[] pixels, int startIndex) {
855     if (pixels == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
856     if (getWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
857     if (getWidth == 0) return;
858     int index;
859     int theByte;
860     int mask;
861     int n = getWidth;
862     int i = startIndex;
863     int srcX = x, srcY = y;
864     switch (depth) {
865         case 32:
866             index = (y * bytesPerLine) + (x * 4);
867             i = startIndex;
868             for (int j = 0; j < getWidth; j++) {
869                 pixels[i] = ((data[index] & 0xFF) << 24) | ((data[index+1] & 0xFF) << 16)
870                     | ((data[index+2] & 0xFF) << 8) | (data[index+3] & 0xFF);
871                 i++;
872                 srcX++;
873                 if (srcX >= width) {
874                     srcY++;
875                     index = srcY * bytesPerLine;
876                     srcX = 0;
877                 } else {
878                     index += 4;
879                 }
880             }
881             return;
882         case 24:
883             index = (y * bytesPerLine) + (x * 3);
884             for (int j = 0; j < getWidth; j++) {
885                 pixels[i] = ((data[index] & 0xFF) << 16) | ((data[index+1] & 0xFF) << 8)
886                     | (data[index+2] & 0xFF);
887                 i++;
888                 srcX++;
889                 if (srcX >= width) {
890                     srcY++;
891                     index = srcY * bytesPerLine;
892                     srcX = 0;
893                 } else {
894                     index += 3;
895                 }
896             }
897             return;
898         case 16:
899             index = (y * bytesPerLine) + (x * 2);
900             for (int j = 0; j < getWidth; j++) {
901                 pixels[i] = ((data[index+1] & 0xFF) << 8) + (data[index] & 0xFF);
902                 i++;
903                 srcX++;
904                 if (srcX >= width) {
905                     srcY++;
906                     index = srcY * bytesPerLine;
907                     srcX = 0;
908                 } else {
909                     index += 2;
910                 }
911             }
912             return;
913         case 8:
914             index = (y * bytesPerLine) + x;
915             for (int j = 0; j < getWidth; j++) {
916                 pixels[i] = data[index] & 0xFF;
917                 i++;
918                 srcX++;
919                 if (srcX >= width) {
920                     srcY++;
921                     index = srcY * bytesPerLine;
922                     srcX = 0;
923                 } else {
924                     index++;
925                 }
926             }
927             return;
928         case 4:
929             index = (y * bytesPerLine) + (x >> 1);
930             if ((x & 0x1) == 1) {
931                 theByte = data[index] & 0xFF;
932                 pixels[i] = theByte & 0x0F;
933                 i++;
934                 n--;
935                 srcX++;
936                 if (srcX >= width) {
937                     srcY++;
938                     index = srcY * bytesPerLine;
939                     srcX = 0;
940                 } else {
941                     index++;
942                 }
943             }
944             while (n > 1) {
945                 theByte = data[index] & 0xFF;
946                 pixels[i] = theByte >> 4;
947                 i++;
948                 n--;
949                 srcX++;
950                 if (srcX >= width) {
951                     srcY++;
952                     index = srcY * bytesPerLine;
953                     srcX = 0;
954                 } else {
955                     pixels[i] = theByte & 0x0F;
956                     i++;
957                     n--;
958                     srcX++;
959                     if (srcX >= width) {
960                         srcY++;
961                         index = srcY * bytesPerLine;
962                         srcX = 0;
963                     } else {
964                         index++;
965                     }
966                 }
967             }
968             if (n > 0) {
969                 theByte = data[index] & 0xFF;
970                 pixels[i] = theByte >> 4;
971             }
972             return;
973         case 2:
974             index = (y * bytesPerLine) + (x >> 2);
975             theByte = data[index] & 0xFF;
976             int offset;
977             while (n > 0) {
978                 offset = 3 - (srcX % 4);
979                 mask = 3 << (offset * 2);
980                 pixels[i] = (byte)((theByte & mask) >> (offset * 2));
981                 i++;
982                 n--;
983                 srcX++;
984                 if (srcX >= width) {
985                     srcY++;
986                     index = srcY * bytesPerLine;
987                     if (n > 0) theByte = data[index] & 0xFF;
988                     srcX = 0;
989                 } else {
990                     if (offset == 0) {
991                         index++;
992                         theByte = data[index] & 0xFF;
993                     }
994                 }
995             }
996             return;
997         case 1:
998             index = (y * bytesPerLine) + (x >> 3);
999             theByte = data[index] & 0xFF;
1000            while (n > 0) {
1001                mask = 1 << (7 - (srcX & 0x7));
1002                if ((theByte & mask) == 0) {
1003                    pixels[i] = 0;
1004                } else {
1005                    pixels[i] = 1;
1006                }
1007                i++;
1008                n--;
1009                srcX++;
1010                if (srcX >= width) {
1011                    srcY++;
1012                    index = srcY * bytesPerLine;
1013                    if (n > 0) theByte = data[index] & 0xFF;
1014                    srcX = 0;
1015                } else {
1016                    if (mask == 1) {
1017                        index++;
1018                        if (n > 0) theByte = data[index] & 0xFF;
1019                    }
1020                }
1021            }
1022            return;
1023    }
1024    SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
1025}
1026
1027/**
1028 * Returns an array of <code>RGB</code>s which comprise the
1029 * indexed color table of the receiver, or null if the receiver
1030 * has a direct color model.
1031 *
1032 * @return the RGB values for the image or null if direct color
1033 *
1034 * @see PaletteData#getRGBs()
1035 */

1036public RGB[] getRGBs() {
1037    return palette.getRGBs();
1038}
1039
1040/**
1041 * Returns an <code>ImageData</code> which specifies the
1042 * transparency mask information for the receiver. If the
1043 * receiver has no transparency or is not an icon, returns
1044 * an opaque mask.
1045 *
1046 * @return the transparency mask
1047 */

1048public ImageData getTransparencyMask() {
1049    if (getTransparencyType() == SWT.TRANSPARENCY_MASK) {
1050        return new ImageData(width, height, 1, bwPalette(), maskPad, maskData);
1051    } else {
1052        return colorMaskImage(transparentPixel);
1053    }
1054}
1055
1056/**
1057 * Returns the image transparency type, which will be one of
1058 * <code>SWT.TRANSPARENCY_NONE</code>, <code>SWT.TRANSPARENCY_MASK</code>,
1059 * <code>SWT.TRANSPARENCY_PIXEL</code> or <code>SWT.TRANSPARENCY_ALPHA</code>.
1060 *
1061 * @return the receiver's transparency type
1062 */

1063public int getTransparencyType() {
1064    if (maskData != null) return SWT.TRANSPARENCY_MASK;
1065    if (transparentPixel != -1) return SWT.TRANSPARENCY_PIXEL;
1066    if (alphaData != null) return SWT.TRANSPARENCY_ALPHA;
1067    return SWT.TRANSPARENCY_NONE;
1068}
1069
1070/**
1071 * Returns the byte order of the receiver.
1072 *
1073 * @return MSB_FIRST or LSB_FIRST
1074 */

1075int getByteOrder() {
1076    return depth != 16 ? MSB_FIRST : LSB_FIRST;
1077}
1078
1079/**
1080 * Returns a copy of the receiver which has been stretched or
1081 * shrunk to the specified size. If either the width or height
1082 * is negative, the resulting image will be inverted in the
1083 * associated axis.
1084 *
1085 * @param width the width of the new ImageData
1086 * @param height the height of the new ImageData
1087 * @return a scaled copy of the image
1088 */

1089public ImageData scaledTo(int width, int height) {
1090    /* Create a destination image with no data */
1091    final boolean flipX = (width < 0);
1092    if (flipX) width = - width;
1093    final boolean flipY = (height < 0);
1094    if (flipY) height = - height;
1095
1096    ImageData dest = new ImageData(
1097        width, height, depth, palette,
1098        scanlinePad, null, 0, null,
1099        null, -1, transparentPixel, type,
1100        x, y, disposalMethod, delayTime);
1101
1102    /* Scale the image contents */
1103    if (palette.isDirect) blit(BLIT_SRC,
1104        this.data, this.depth, this.bytesPerLine, this.getByteOrder(), 0, 0, this.width, this.height, 0, 0, 0,
1105        ALPHA_OPAQUE, null, 0, 0, 0,
1106        dest.data, dest.depth, dest.bytesPerLine, dest.getByteOrder(), 0, 0, dest.width, dest.height, 0, 0, 0,
1107        flipX, flipY);
1108    else blit(BLIT_SRC,
1109        this.data, this.depth, this.bytesPerLine, this.getByteOrder(), 0, 0, this.width, this.height, null, null, null,
1110        ALPHA_OPAQUE, null, 0, 0, 0,
1111        dest.data, dest.depth, dest.bytesPerLine, dest.getByteOrder(), 0, 0, dest.width, dest.height, null, null, null,
1112        flipX, flipY);
1113    
1114    /* Scale the image mask or alpha */
1115    if (maskData != null) {
1116        dest.maskPad = this.maskPad;
1117        int destBpl = (dest.width + 7) / 8;
1118        destBpl = (destBpl + (dest.maskPad - 1)) / dest.maskPad * dest.maskPad;
1119        dest.maskData = new byte[destBpl * dest.height];
1120        int srcBpl = (this.width + 7) / 8;
1121        srcBpl = (srcBpl + (this.maskPad - 1)) / this.maskPad * this.maskPad;
1122        blit(BLIT_SRC,
1123            this.maskData, 1, srcBpl, MSB_FIRST, 0, 0, this.width, this.height, null, null, null,
1124            ALPHA_OPAQUE, null, 0, 0, 0,
1125            dest.maskData, 1, destBpl, MSB_FIRST, 0, 0, dest.width, dest.height, null, null, null,
1126            flipX, flipY);
1127    } else if (alpha != -1) {
1128        dest.alpha = this.alpha;
1129    } else if (alphaData != null) {
1130        dest.alphaData = new byte[dest.width * dest.height];
1131        blit(BLIT_SRC,
1132            this.alphaData, 8, this.width, MSB_FIRST, 0, 0, this.width, this.height, null, null, null,
1133            ALPHA_OPAQUE, null, 0, 0, 0,
1134            dest.alphaData, 8, dest.width, MSB_FIRST, 0, 0, dest.width, dest.height, null, null, null,
1135            flipX, flipY);
1136    }
1137    return dest;
1138}
1139
1140/**
1141 * Sets the alpha value at offset <code>x</code> in
1142 * scanline <code>y</code> in the receiver's alpha data.
1143 *
1144 * @param x the x coordinate of the alpha value to set
1145 * @param y the y coordinate of the alpha value to set
1146 * @param alpha the value to set the alpha to
1147 *
1148 * @exception IllegalArgumentException <ul>
1149 * <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
1150 * </ul>
1151 */

1152public void setAlpha(int x, int y, int alpha) {
1153    if (x >= width || y >= height || x < 0 || y < 0 || alpha < 0 || alpha > 255)
1154        SWT.error(SWT.ERROR_INVALID_ARGUMENT);
1155    
1156    if (alphaData == null) alphaData = new byte[width * height];
1157    alphaData[y * width + x] = (byte)alpha;
1158}
1159
1160/**
1161 * Sets the alpha values starting at offset <code>x</code> in
1162 * scanline <code>y</code> in the receiver's alpha data to the
1163 * values from the array <code>alphas</code> starting at
1164 * <code>startIndex</code>.
1165 *
1166 * @param x the x coordinate of the pixel to being setting the alpha values
1167 * @param y the y coordinate of the pixel to being setting the alpha values
1168 * @param putWidth the width of the alpha values to set
1169 * @param alphas the alpha values to set
1170 * @param startIndex the index at which to begin setting
1171 *
1172 * @exception IndexOutOfBoundsException if putWidth is too large
1173 * @exception IllegalArgumentException <ul>
1174 * <li>ERROR_NULL_ARGUMENT - if pixels is null</li>
1175 * <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
1176 * <li>ERROR_INVALID_ARGUMENT - if putWidth is negative</li>
1177 * </ul>
1178 */

1179public void setAlphas(int x, int y, int putWidth, byte[] alphas, int startIndex) {
1180    if (alphas == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
1181    if (putWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
1182    if (putWidth == 0) return;
1183    
1184    if (alphaData == null) alphaData = new byte[width * height];
1185    // may throw an IndexOutOfBoundsException
1186
System.arraycopy(alphas, startIndex, alphaData, y * width + x, putWidth);
1187}
1188
1189/**
1190 * Sets the pixel value at offset <code>x</code> in
1191 * scanline <code>y</code> in the receiver's data.
1192 *
1193 * @param x the x coordinate of the pixel to set
1194 * @param y the y coordinate of the pixel to set
1195 * @param pixelValue the value to set the pixel to
1196 *
1197 * @exception IllegalArgumentException <ul>
1198 * <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
1199 * </ul>
1200 * @exception SWTException <ul>
1201 * <li>ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8, 16, 24 or 32</li>
1202 * </ul>
1203 */

1204public void setPixel(int x, int y, int pixelValue) {
1205    if (x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
1206    int index;
1207    byte theByte;
1208    int mask;
1209    switch (depth) {
1210        case 32:
1211            index = (y * bytesPerLine) + (x * 4);
1212            data[index] = (byte)((pixelValue >> 24) & 0xFF);
1213            data[index + 1] = (byte)((pixelValue >> 16) & 0xFF);
1214            data[index + 2] = (byte)((pixelValue >> 8) & 0xFF);
1215            data[index + 3] = (byte)(pixelValue & 0xFF);
1216            return;
1217        case 24:
1218            index = (y * bytesPerLine) + (x * 3);
1219            data[index] = (byte)((pixelValue >> 16) & 0xFF);
1220            data[index + 1] = (byte)((pixelValue >> 8) & 0xFF);
1221            data[index + 2] = (byte)(pixelValue & 0xFF);
1222            return;
1223        case 16:
1224            index = (y * bytesPerLine) + (x * 2);
1225            data[index + 1] = (byte)((pixelValue >> 8) & 0xFF);
1226            data[index] = (byte)(pixelValue & 0xFF);
1227            return;
1228        case 8:
1229            index = (y * bytesPerLine) + x ;
1230            data[index] = (byte)(pixelValue & 0xFF);
1231            return;
1232        case 4:
1233            index = (y * bytesPerLine) + (x >> 1);
1234            if ((x & 0x1) == 0) {
1235                data[index] = (byte)((data[index] & 0x0F) | ((pixelValue & 0x0F) << 4));
1236            } else {
1237                data[index] = (byte)((data[index] & 0xF0) | (pixelValue & 0x0F));
1238            }
1239            return;
1240        case 2:
1241            index = (y * bytesPerLine) + (x >> 2);
1242            theByte = data[index];
1243            int offset = 3 - (x % 4);
1244            mask = 0xFF ^ (3 << (offset * 2));
1245            data[index] = (byte)((data[index] & mask) | (pixelValue << (offset * 2)));
1246            return;
1247        case 1:
1248            index = (y * bytesPerLine) + (x >> 3);
1249            theByte = data[index];
1250            mask = 1 << (7 - (x & 0x7));
1251            if ((pixelValue & 0x1) == 1) {
1252                data[index] = (byte)(theByte | mask);
1253            } else {
1254                data[index] = (byte)(theByte & (mask ^ -1));
1255            }
1256            return;
1257    }
1258    SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
1259}
1260
1261/**
1262 * Sets the pixel values starting at offset <code>x</code> in
1263 * scanline <code>y</code> in the receiver's data to the
1264 * values from the array <code>pixels</code> starting at
1265 * <code>startIndex</code>.
1266 *
1267 * @param x the x position of the pixel to set
1268 * @param y the y position of the pixel to set
1269 * @param putWidth the width of the pixels to set
1270 * @param pixels the pixels to set
1271 * @param startIndex the index at which to begin setting
1272 *
1273 * @exception IndexOutOfBoundsException if putWidth is too large
1274 * @exception IllegalArgumentException <ul>
1275 * <li>ERROR_NULL_ARGUMENT - if pixels is null</li>
1276 * <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
1277 * <li>ERROR_INVALID_ARGUMENT - if putWidth is negative</li>
1278 * </ul>
1279 * @exception SWTException <ul>
1280 * <li>ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8
1281 * (For higher depths, use the int[] version of this method.)</li>
1282 * </ul>
1283 */

1284public void setPixels(int x, int y, int putWidth, byte[] pixels, int startIndex) {
1285    if (pixels == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
1286    if (putWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
1287    if (putWidth == 0) return;
1288    int index;
1289    int theByte;
1290    int mask;
1291    int n = putWidth;
1292    int i = startIndex;
1293    int srcX = x, srcY = y;
1294    switch (depth) {
1295        case 8:
1296            index = (y * bytesPerLine) + x;
1297            for (int j = 0; j < putWidth; j++) {
1298                data[index] = (byte)(pixels[i] & 0xFF);
1299                i++;
1300                srcX++;
1301                if (srcX >= width) {
1302                    srcY++;
1303                    index = srcY * bytesPerLine;
1304                    srcX = 0;
1305                } else {
1306                    index++;
1307                }
1308            }
1309            return;
1310        case 4:
1311            index = (y * bytesPerLine) + (x >> 1);
1312            boolean high = (x & 0x1) == 0;
1313            while (n > 0) {
1314                theByte = pixels[i] & 0x0F;
1315                if (high) {
1316                    data[index] = (byte)((data[index] & 0x0F) | (theByte << 4));
1317                } else {
1318                    data[index] = (byte)((data[index] & 0xF0) | theByte);
1319                }
1320                i++;
1321                n--;
1322                srcX++;
1323                if (srcX >= width) {
1324                    srcY++;
1325                    index = srcY * bytesPerLine;
1326                    high = true;
1327                    srcX = 0;
1328                } else {
1329                    if (!high) index++;
1330                    high = !high;
1331                }
1332            }
1333            return;
1334        case 2:
1335            byte [] masks = { (byte)0xFC, (byte)0xF3, (byte)0xCF, (byte)0x3F };
1336            index = (y * bytesPerLine) + (x >> 2);
1337            int offset = 3 - (x % 4);
1338            while (n > 0) {
1339                theByte = pixels[i] & 0x3;
1340                data[index] = (byte)((data[index] & masks[offset]) | (theByte << (offset * 2)));
1341                i++;
1342                n--;
1343                srcX++;
1344                if (srcX >= width) {
1345                    srcY++;
1346                    index = srcY * bytesPerLine;
1347                    offset = 0;
1348                    srcX = 0;
1349                } else {
1350                    if (offset == 0) {
1351                        index++;
1352                        offset = 3;
1353                    } else {
1354                        offset--;
1355                    }
1356                }
1357            }
1358            return;
1359        case 1:
1360            index = (y * bytesPerLine) + (x >> 3);
1361            while (n > 0) {
1362                mask = 1 << (7 - (srcX & 0x7));
1363                if ((pixels[i] & 0x1) == 1) {
1364                    data[index] = (byte)((data[index] & 0xFF) | mask);
1365                } else {
1366                    data[index] = (byte)((data[index] & 0xFF) & (mask ^ -1));
1367                }
1368                i++;
1369                n--;
1370                srcX++;
1371                if (srcX >= width) {
1372                    srcY++;
1373                    index = srcY * bytesPerLine;
1374                    srcX = 0;
1375                } else {
1376                    if (mask == 1) {
1377                        index++;
1378                    }
1379                }
1380            }
1381            return;
1382    }
1383    SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
1384}
1385
1386/**
1387 * Sets the pixel values starting at offset <code>x</code> in
1388 * scanline <code>y</code> in the receiver's data to the
1389 * values from the array <code>pixels</code> starting at
1390 * <code>startIndex</code>.
1391 *
1392 * @param x the x position of the pixel to set
1393 * @param y the y position of the pixel to set
1394 * @param putWidth the width of the pixels to set
1395 * @param pixels the pixels to set
1396 * @param startIndex the index at which to begin setting
1397 *
1398 * @exception IndexOutOfBoundsException if putWidth is too large
1399 * @exception IllegalArgumentException <ul>
1400 * <li>ERROR_NULL_ARGUMENT - if pixels is null</li>
1401 * <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
1402 * <li>ERROR_INVALID_ARGUMENT - if putWidth is negative</li>
1403 * </ul>
1404 * @exception SWTException <ul>
1405 * <li>ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8, 16, 24 or 32</li>
1406 * </ul>
1407 */

1408public void setPixels(int x, int y, int putWidth, int[] pixels, int startIndex) {
1409    if (pixels == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
1410    if (putWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
1411    if (putWidth == 0) return;
1412    int index;
1413    int theByte;
1414    int mask;
1415    int n = putWidth;
1416    int i = startIndex;
1417    int pixel;
1418    int srcX = x, srcY = y;
1419    switch (depth) {
1420        case 32:
1421            index = (y * bytesPerLine) + (x * 4);
1422            for (int j = 0; j < putWidth; j++) {
1423                pixel = pixels[i];
1424                data[index] = (byte)((pixel >> 24) & 0xFF);
1425                data[index + 1] = (byte)((pixel >> 16) & 0xFF);
1426                data[index + 2] = (byte)((pixel >> 8) & 0xFF);
1427                data[index + 3] = (byte)(pixel & 0xFF);
1428                i++;
1429                srcX++;
1430                if (srcX >= width) {
1431                    srcY++;
1432                    index = srcY * bytesPerLine;
1433                    srcX = 0;
1434                } else {
1435                    index += 4;
1436                }
1437            }
1438            return;
1439        case 24:
1440            index = (y * bytesPerLine) + (x * 3);
1441            for (int j = 0; j < putWidth; j++) {
1442                pixel = pixels[i];
1443                data[index] = (byte)((pixel >> 16) & 0xFF);
1444                data[index + 1] = (byte)((pixel >> 8) & 0xFF);
1445                data[index + 2] = (byte)(pixel & 0xFF);
1446                i++;
1447                srcX++;
1448                if (srcX >= width) {
1449                    srcY++;
1450                    index = srcY * bytesPerLine;
1451                    srcX = 0;
1452                } else {
1453                    index += 3;
1454                }
1455            }
1456            return;
1457        case 16:
1458            index = (y * bytesPerLine) + (x * 2);
1459            for (int j = 0; j < putWidth; j++) {
1460                pixel = pixels[i];
1461                data[index] = (byte)(pixel & 0xFF);
1462                data[index + 1] = (byte)((pixel >> 8) & 0xFF);
1463                i++;
1464                srcX++;
1465                if (srcX >= width) {
1466                    srcY++;
1467                    index = srcY * bytesPerLine;
1468                    srcX = 0;
1469                } else {
1470                    index += 2;
1471                }
1472            }
1473            return;
1474        case 8:
1475            index = (y * bytesPerLine) + x;
1476            for (int j = 0; j < putWidth; j++) {
1477                data[index] = (byte)(pixels[i] & 0xFF);
1478                i++;
1479                srcX++;
1480                if (srcX >= width) {
1481                    srcY++;
1482                    index = srcY * bytesPerLine;
1483                    srcX = 0;
1484                } else {
1485                    index++;
1486                }
1487            }
1488            return;
1489        case 4:
1490            index = (y * bytesPerLine) + (x >> 1);
1491            boolean high = (x & 0x1) == 0;
1492            while (n > 0) {
1493                theByte = pixels[i] & 0x0F;
1494                if (high) {
1495                    data[index] = (byte)((data[index] & 0x0F) | (theByte << 4));
1496                } else {
1497                    data[index] = (byte)((data[index] & 0xF0) | theByte);
1498                }
1499                i++;
1500                n--;
1501                srcX++;
1502                if (srcX >= width) {
1503                    srcY++;
1504                    index = srcY * bytesPerLine;
1505                    high = true;
1506                    srcX = 0;
1507                } else {
1508                    if (!high) index++;
1509                    high = !high;
1510                }
1511            }
1512            return;
1513        case 2:
1514            byte [] masks = { (byte)0xFC, (byte)0xF3, (byte)0xCF, (byte)0x3F };
1515            index = (y * bytesPerLine) + (x >> 2);
1516            int offset = 3 - (x % 4);
1517            while (n > 0) {
1518                theByte = pixels[i] & 0x3;
1519                data[index] = (byte)((data[index] & masks[offset]) | (theByte << (offset * 2)));
1520                i++;
1521                n--;
1522                srcX++;
1523                if (srcX >= width) {
1524                    srcY++;
1525                    index = srcY * bytesPerLine;
1526                    offset = 3;
1527                    srcX = 0;
1528                } else {
1529                    if (offset == 0) {
1530                        index++;
1531                        offset = 3;
1532                    } else {
1533                        offset--;
1534                    }
1535                }
1536            }
1537            return;
1538        case 1:
1539            index = (y * bytesPerLine) + (x >> 3);
1540            while (n > 0) {
1541                mask = 1 << (7 - (srcX & 0x7));
1542                if ((pixels[i] & 0x1) == 1) {
1543                    data[index] = (byte)((data[index] & 0xFF) | mask);
1544                } else {
1545                    data[index] = (byte)((data[index] & 0xFF) & (mask ^ -1));
1546                }
1547                i++;
1548                n--;
1549                srcX++;
1550                if (srcX >= width) {
1551                    srcY++;
1552                    index = srcY * bytesPerLine;
1553                    srcX = 0;
1554                } else {
1555                    if (mask == 1) {
1556                        index++;
1557                    }
1558                }
1559            }
1560            return;
1561    }
1562    SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
1563}
1564
1565/**
1566 * Returns a palette with 2 colors: black & white.
1567 */

1568static PaletteData bwPalette() {
1569    return new PaletteData(new RGB[] {new RGB(0, 0, 0), new RGB(255, 255, 255)});
1570}
1571
1572/**
1573 * Gets the offset of the most significant bit for
1574 * the given mask.
1575 */

1576static int getMSBOffset(int mask) {
1577    for (int i = 31; i >= 0; i--) {
1578        if (((mask >> i) & 0x1) != 0) return i + 1;
1579    }
1580    return 0;
1581}
1582
1583/**
1584 * Finds the closest match.
1585 */

1586static int closestMatch(int depth, byte red, byte green, byte blue, int redMask, int greenMask, int blueMask, byte[] reds, byte[] greens, byte[] blues) {
1587    if (depth > 8) {
1588        int rshift = 32 - getMSBOffset(redMask);
1589        int gshift = 32 - getMSBOffset(greenMask);
1590        int bshift = 32 - getMSBOffset(blueMask);
1591        return (((red << 24) >>> rshift) & redMask) |
1592            (((green << 24) >>> gshift) & greenMask) |
1593            (((blue << 24) >>> bshift) & blueMask);
1594    }
1595    int r, g, b;
1596    int minDistance = 0x7fffffff;
1597    int nearestPixel = 0;
1598    int n = reds.length;
1599    for (int j = 0; j < n; j++) {
1600        r = (reds[j] & 0xFF) - (red & 0xFF);
1601        g = (greens[j] & 0xFF) - (green & 0xFF);
1602        b = (blues[j] & 0xFF) - (blue & 0xFF);
1603        int distance = r*r + g*g + b*b;
1604        if (distance < minDistance) {
1605            nearestPixel = j;
1606            if (distance == 0) break;
1607            minDistance = distance;
1608        }
1609    }
1610    return nearestPixel;
1611}
1612
1613static final ImageData convertMask(ImageData mask) {
1614    if (mask.depth == 1) return mask;
1615    PaletteData palette = new PaletteData(new RGB[] {new RGB(0, 0, 0), new RGB(255,255,255)});
1616    ImageData newMask = new ImageData(mask.width, mask.height, 1, palette);
1617    /* Find index of black in mask palette */
1618    int blackIndex = 0;
1619    RGB[] rgbs = mask.getRGBs();
1620    if (rgbs != null) {
1621        while (blackIndex < rgbs.length) {
1622            if (rgbs[blackIndex].equals(palette.colors[0])) break;
1623            blackIndex++;
1624        }
1625    }
1626    int[] pixels = new int[mask.width];
1627    for (int y = 0; y < mask.height; y++) {
1628        mask.getPixels(0, y, mask.width, pixels, 0);
1629        for (int i = 0; i < pixels.length; i++) {
1630            if (pixels[i] == blackIndex) {
1631                pixels[i] = 0;
1632            } else {
1633                pixels[i] = 1;
1634            }
1635        }
1636        newMask.setPixels(0, y, mask.width, pixels, 0);
1637    }
1638    return newMask;
1639}
1640
1641static final byte[] convertPad(byte[] data, int width, int height, int depth, int pad, int newPad) {
1642    if (pad == newPad) return data;
1643    int stride = (width * depth + 7) / 8;
1644    int bpl = (stride + (pad - 1)) / pad * pad;
1645    int newBpl = (stride + (newPad - 1)) / newPad * newPad;
1646    byte[] newData = new byte[height * newBpl];
1647    int srcIndex = 0, destIndex = 0;
1648    for (int y = 0; y < height; y++) {
1649        System.arraycopy(data, srcIndex, newData, destIndex, stride);
1650        srcIndex += bpl;
1651        destIndex += newBpl;
1652    }
1653    return newData;
1654}
1655
1656/**
1657 * Blit operation bits to be OR'ed together to specify the desired operation.
1658 */

1659static final int
1660    BLIT_SRC = 1, // copy source directly, else applies logic operations
1661
BLIT_ALPHA = 2, // enable alpha blending
1662
BLIT_DITHER = 4; // enable dithering in low color modes
1663

1664/**
1665 * Alpha mode, values 0 - 255 specify global alpha level
1666 */

1667static final int
1668    ALPHA_OPAQUE = 255, // Fully opaque (ignores any alpha data)
1669
ALPHA_TRANSPARENT = 0, // Fully transparent (ignores any alpha data)
1670
ALPHA_CHANNEL_SEPARATE = -1, // Use alpha channel from separate alphaData
1671
ALPHA_CHANNEL_SOURCE = -2, // Use alpha channel embedded in sourceData
1672
ALPHA_MASK_UNPACKED = -3, // Use transparency mask formed by bytes in alphaData (non-zero is opaque)
1673
ALPHA_MASK_PACKED = -4, // Use transparency mask formed by packed bits in alphaData
1674
ALPHA_MASK_INDEX = -5, // Consider source palette indices transparent if in alphaData array
1675
ALPHA_MASK_RGB = -6; // Consider source RGBs transparent if in RGB888 format alphaData array
1676

1677/**
1678 * Byte and bit order constants.
1679 */

1680static final int LSB_FIRST = 0;
1681static final int MSB_FIRST = 1;
1682
1683/**
1684 * Data types (internal)
1685 */

1686private static final int
1687    // direct / true color formats with arbitrary masks & shifts
1688
TYPE_GENERIC_8 = 0,
1689    TYPE_GENERIC_16_MSB = 1,
1690    TYPE_GENERIC_16_LSB = 2,
1691    TYPE_GENERIC_24 = 3,
1692    TYPE_GENERIC_32_MSB = 4,
1693    TYPE_GENERIC_32_LSB = 5,
1694    // palette indexed color formats
1695
TYPE_INDEX_8 = 6,
1696    TYPE_INDEX_4 = 7,
1697    TYPE_INDEX_2 = 8,
1698    TYPE_INDEX_1_MSB = 9,
1699    TYPE_INDEX_1_LSB = 10;
1700
1701/**
1702 * Blits a direct palette image into a direct palette image.
1703 * <p>
1704 * Note: When the source and destination depth, order and masks
1705 * are pairwise equal and the blitter operation is BLIT_SRC,
1706 * the masks are ignored. Hence when not changing the image
1707 * data format, 0 may be specified for the masks.
1708 * </p>
1709 *
1710 * @param op the blitter operation: a combination of BLIT_xxx flags
1711 * (see BLIT_xxx constants)
1712 * @param srcData the source byte array containing image data
1713 * @param srcDepth the source depth: one of 8, 16, 24, 32
1714 * @param srcStride the source number of bytes per line
1715 * @param srcOrder the source byte ordering: one of MSB_FIRST or LSB_FIRST;
1716 * ignored if srcDepth is not 16 or 32
1717 * @param srcX the top-left x-coord of the source blit region
1718 * @param srcY the top-left y-coord of the source blit region
1719 * @param srcWidth the width of the source blit region
1720 * @param srcHeight the height of the source blit region
1721 * @param srcRedMask the source red channel mask
1722 * @param srcGreenMask the source green channel mask
1723 * @param srcBlueMask the source blue channel mask
1724 * @param alphaMode the alpha blending or mask mode, may be
1725 * an integer 0-255 for global alpha; ignored if BLIT_ALPHA
1726 * not specified in the blitter operations
1727 * (see ALPHA_MODE_xxx constants)
1728 * @param alphaData the alpha blending or mask data, varies depending
1729 * on the value of alphaMode and sometimes ignored
1730 * @param alphaStride the alpha data number of bytes per line
1731 * @param alphaX the top-left x-coord of the alpha blit region
1732 * @param alphaY the top-left y-coord of the alpha blit region
1733 * @param destData the destination byte array containing image data
1734 * @param destDepth the destination depth: one of 8, 16, 24, 32
1735 * @param destStride the destination number of bytes per line
1736 * @param destOrder the destination byte ordering: one of MSB_FIRST or LSB_FIRST;
1737 * ignored if destDepth is not 16 or 32
1738 * @param destX the top-left x-coord of the destination blit region
1739 * @param destY the top-left y-coord of the destination blit region
1740 * @param destWidth the width of the destination blit region
1741 * @param destHeight the height of the destination blit region
1742 * @param destRedMask the destination red channel mask
1743 * @param destGreenMask the destination green channel mask
1744 * @param destBlueMask the destination blue channel mask
1745 * @param flipX if true the resulting image is flipped along the vertical axis
1746 * @param flipY if true the resulting image is flipped along the horizontal axis
1747 */

1748static void blit(int op,
1749    byte[] srcData, int srcDepth, int srcStride, int srcOrder,
1750    int srcX, int srcY, int srcWidth, int srcHeight,
1751    int srcRedMask, int srcGreenMask, int srcBlueMask,
1752    int alphaMode, byte[] alphaData, int alphaStride, int alphaX, int alphaY,
1753    byte[] destData, int destDepth, int destStride, int destOrder,
1754    int destX, int destY, int destWidth, int destHeight,
1755    int destRedMask, int destGreenMask, int destBlueMask,
1756    boolean flipX, boolean flipY) {
1757    if ((destWidth <= 0) || (destHeight <= 0) || (alphaMode == ALPHA_TRANSPARENT)) return;
1758
1759    // these should be supplied as params later
1760
final int srcAlphaMask = 0, destAlphaMask = 0;
1761
1762    /*** Prepare scaling data ***/
1763    final int dwm1 = destWidth - 1;
1764    final int sfxi = (dwm1 != 0) ? (int)((((long)srcWidth << 16) - 1) / dwm1) : 0;
1765    final int dhm1 = destHeight - 1;
1766    final int sfyi = (dhm1 != 0) ? (int)((((long)srcHeight << 16) - 1) / dhm1) : 0;
1767
1768    /*** Prepare source-related data ***/
1769    final int sbpp, stype;
1770    switch (srcDepth) {
1771        case 8:
1772            sbpp = 1;
1773            stype = TYPE_GENERIC_8;
1774            break;
1775        case 16:
1776            sbpp = 2;
1777            stype = (srcOrder == MSB_FIRST) ? TYPE_GENERIC_16_MSB : TYPE_GENERIC_16_LSB;
1778            break;
1779        case 24:
1780            sbpp = 3;
1781            stype = TYPE_GENERIC_24;
1782            break;
1783        case 32:
1784            sbpp = 4;
1785            stype = (srcOrder == MSB_FIRST) ? TYPE_GENERIC_32_MSB : TYPE_GENERIC_32_LSB;
1786            break;
1787        default:
1788            //throw new IllegalArgumentException("Invalid source type");
1789
return;
1790    }
1791    int spr = srcY * srcStride + srcX * sbpp;
1792
1793    /*** Prepare destination-related data ***/
1794    final int dbpp, dtype;
1795    switch (destDepth) {
1796        case 8:
1797            dbpp = 1;
1798            dtype = TYPE_GENERIC_8;
1799            break;
1800        case 16:
1801            dbpp = 2;
1802            dtype = (destOrder == MSB_FIRST) ? TYPE_GENERIC_16_MSB : TYPE_GENERIC_16_LSB;
1803            break;
1804        case 24:
1805            dbpp = 3;
1806            dtype = TYPE_GENERIC_24;
1807            break;
1808        case 32:
1809            dbpp = 4;
1810            dtype = (destOrder == MSB_FIRST) ? TYPE_GENERIC_32_MSB : TYPE_GENERIC_32_LSB;
1811            break;
1812        default:
1813            //throw new IllegalArgumentException("Invalid destination type");
1814
return;
1815    }
1816    int dpr = ((flipY) ? destY + dhm1 : destY) * destStride + ((flipX) ? destX + dwm1 : destX) * dbpp;
1817    final int dprxi = (flipX) ? -dbpp : dbpp;
1818    final int dpryi = (flipY) ? -destStride : destStride;
1819
1820    /*** Prepare special processing data ***/
1821    int apr;
1822    if ((op & BLIT_ALPHA) != 0) {
1823        switch (alphaMode) {
1824            case ALPHA_MASK_UNPACKED:
1825            case ALPHA_CHANNEL_SEPARATE:
1826                if (alphaData == null) alphaMode = 0x10000;
1827                apr = alphaY * alphaStride + alphaX;
1828                break;
1829            case ALPHA_MASK_PACKED:
1830                if (alphaData == null) alphaMode = 0x10000;
1831                alphaStride <<= 3;
1832                apr = alphaY * alphaStride + alphaX;
1833                break;
1834            case ALPHA_MASK_INDEX:
1835                //throw new IllegalArgumentException("Invalid alpha type");
1836
return;
1837            case ALPHA_MASK_RGB:
1838                if (alphaData == null) alphaMode = 0x10000;
1839                apr = 0;
1840                break;
1841            default:
1842                alphaMode = (alphaMode << 16) / 255; // prescale
1843
case ALPHA_CHANNEL_SOURCE:
1844                apr = 0;
1845                break;
1846        }
1847    } else {
1848        alphaMode = 0x10000;
1849        apr = 0;
1850    }
1851
1852    /*** Blit ***/
1853    int dp = dpr;
1854    int sp = spr;
1855    if ((alphaMode == 0x10000) && (stype == dtype) &&
1856        (srcRedMask == destRedMask) && (srcGreenMask == destGreenMask) &&
1857        (srcBlueMask == destBlueMask) && (srcAlphaMask == destAlphaMask)) {
1858        /*** Fast blit (straight copy) ***/
1859        switch (sbpp) {
1860            case 1:
1861                for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
1862                    for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
1863                        destData[dp] = srcData[sp];
1864                        sp += (sfx >>> 16);
1865                    }
1866                }
1867                break;
1868            case 2:
1869                for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
1870                    for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
1871                        destData[dp] = srcData[sp];
1872                        destData[dp + 1] = srcData[sp + 1];
1873                        sp += (sfx >>> 16) * 2;
1874                    }
1875                }
1876                break;
1877            case 3:
1878                for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
1879                    for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
1880                        destData[dp] = srcData[sp];
1881                        destData[dp + 1] = srcData[sp + 1];
1882                        destData[dp + 2] = srcData[sp + 2];
1883                        sp += (sfx >>> 16) * 3;
1884                    }
1885                }
1886                break;
1887            case 4:
1888                for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
1889                    for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
1890                        destData[dp] = srcData[sp];
1891                        destData[dp + 1] = srcData[sp + 1];
1892                        destData[dp + 2] = srcData[sp + 2];
1893                        destData[dp + 3] = srcData[sp + 3];
1894                        sp += (sfx >>> 16) * 4;
1895                    }
1896                }
1897                break;
1898        }
1899        return;
1900    }
1901    /*** Comprehensive blit (apply transformations) ***/
1902    final int srcRedShift = getChannelShift(srcRedMask);
1903    final byte[] srcReds = ANY_TO_EIGHT[getChannelWidth(srcRedMask, srcRedShift)];
1904    final int srcGreenShift = getChannelShift(srcGreenMask);
1905    final byte[] srcGreens = ANY_TO_EIGHT[getChannelWidth(srcGreenMask, srcGreenShift)];
1906    final int srcBlueShift = getChannelShift(srcBlueMask);
1907    final byte[] srcBlues = ANY_TO_EIGHT[getChannelWidth(srcBlueMask, srcBlueShift)];
1908    final int srcAlphaShift = getChannelShift(srcAlphaMask);
1909    final byte[] srcAlphas = ANY_TO_EIGHT[getChannelWidth(srcAlphaMask, srcAlphaShift)];
1910
1911    final int destRedShift = getChannelShift(destRedMask);
1912    final int destRedWidth = getChannelWidth(destRedMask, destRedShift);
1913    final byte[] destReds = ANY_TO_EIGHT[destRedWidth];
1914    final int destRedPreShift = 8 - destRedWidth;
1915    final int destGreenShift = getChannelShift(destGreenMask);
1916    final int destGreenWidth = getChannelWidth(destGreenMask, destGreenShift);
1917    final byte[] destGreens = ANY_TO_EIGHT[destGreenWidth];
1918    final int destGreenPreShift = 8 - destGreenWidth;
1919    final int destBlueShift = getChannelShift(destBlueMask);
1920    final int destBlueWidth = getChannelWidth(destBlueMask, destBlueShift);
1921    final byte[] destBlues = ANY_TO_EIGHT[destBlueWidth];
1922    final int destBluePreShift = 8 - destBlueWidth;
1923    final int destAlphaShift = getChannelShift(destAlphaMask);
1924    final int destAlphaWidth = getChannelWidth(destAlphaMask, destAlphaShift);
1925    final byte[] destAlphas = ANY_TO_EIGHT[destAlphaWidth];
1926    final int destAlphaPreShift = 8 - destAlphaWidth;
1927
1928    int ap = apr, alpha = alphaMode;
1929    int r = 0, g = 0, b = 0, a = 0;
1930    int rq = 0, gq = 0, bq = 0, aq = 0;
1931    for (int dy = destHeight, sfy = sfyi; dy > 0; --dy,
1932            sp = spr += (sfy >>> 16) * srcStride,
1933            ap = apr += (sfy >>> 16) * alphaStride,
1934            sfy = (sfy & 0xffff) + sfyi,
1935            dp = dpr += dpryi) {
1936        for (int dx = destWidth, sfx = sfxi; dx > 0; --dx,
1937                dp += dprxi,
1938                sfx = (sfx & 0xffff) + sfxi) {
1939            /*** READ NEXT PIXEL ***/
1940            switch (stype) {
1941                case TYPE_GENERIC_8: {
1942                    final int data = srcData[sp] & 0xff;
1943                    sp += (sfx >>> 16);
1944                    r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
1945                    g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
1946                    b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
1947                    a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
1948                } break;
1949                case TYPE_GENERIC_16_MSB: {
1950                    final int data = ((srcData[sp] & 0xff) << 8) | (srcData[sp + 1] & 0xff);
1951                    sp += (sfx >>> 16) * 2;
1952                    r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
1953                    g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
1954                    b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
1955                    a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
1956                } break;
1957                case TYPE_GENERIC_16_LSB: {
1958                    final int data = ((srcData[sp + 1] & 0xff) << 8) | (srcData[sp] & 0xff);
1959                    sp += (sfx >>> 16) * 2;
1960                    r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
1961                    g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
1962                    b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
1963                    a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
1964                } break;
1965                case TYPE_GENERIC_24: {
1966                    final int data = (( ((srcData[sp] & 0xff) << 8) |
1967                        (srcData[sp + 1] & 0xff)) << 8) |
1968                        (srcData[sp + 2] & 0xff);
1969                    sp += (sfx >>> 16) * 3;
1970                    r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
1971                    g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
1972                    b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
1973                    a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
1974                } break;
1975                case TYPE_GENERIC_32_MSB: {
1976                    final int data = (( (( ((srcData[sp] & 0xff) << 8) |
1977                        (srcData[sp + 1] & 0xff)) << 8) |
1978                        (srcData[sp + 2] & 0xff)) << 8) |
1979                        (srcData[sp + 3] & 0xff);
1980                    sp += (sfx >>> 16) * 4;
1981                    r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
1982                    g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
1983                    b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
1984                    a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
1985                } break;
1986                case TYPE_GENERIC_32_LSB: {
1987                    final int data = (( (( ((srcData[sp + 3] & 0xff) << 8) |
1988                        (srcData[sp + 2] & 0xff)) << 8) |
1989                        (srcData[sp + 1] & 0xff)) << 8) |
1990                        (srcData[sp] & 0xff);
1991                    sp += (sfx >>> 16) * 4;
1992                    r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
1993                    g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
1994                    b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
1995                    a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
1996                } break;
1997            }
1998
1999            /*** DO SPECIAL PROCESSING IF REQUIRED ***/
2000            switch (alphaMode) {
2001                case ALPHA_CHANNEL_SEPARATE:
2002                    alpha = ((alphaData[ap] & 0xff) << 16) / 255;
2003                    ap += (sfx >> 16);
2004                    break;
2005                case ALPHA_CHANNEL_SOURCE:
2006                    alpha = (a << 16) / 255;
2007                    break;
2008                case ALPHA_MASK_UNPACKED:
2009                    alpha = (alphaData[ap] != 0) ? 0x10000 : 0;
2010                    ap += (sfx >> 16);
2011                    break;
2012                case ALPHA_MASK_PACKED:
2013                    alpha = (alphaData[ap >> 3] << ((ap & 7) + 9)) & 0x10000;
2014                    ap += (sfx >> 16);
2015                    break;
2016                case ALPHA_MASK_RGB:
2017                    alpha = 0x10000;
2018                    for (int i = 0; i < alphaData.length; i += 3) {
2019                        if ((r == alphaData[i]) && (g == alphaData[i + 1]) && (b == alphaData[i + 2])) {
2020                            alpha = 0x0000;
2021                            break;
2022                        }
2023                    }
2024                    break;
2025            }
2026            if (alpha != 0x10000) {
2027                if (alpha == 0x0000) continue;
2028                switch (dtype) {
2029                    case TYPE_GENERIC_8: {
2030                        final int data = destData[dp] & 0xff;
2031                        rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
2032                        gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
2033                        bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
2034                        aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
2035                    } break;
2036                    case TYPE_GENERIC_16_MSB: {
2037                        final int data = ((destData[dp] & 0xff) << 8) | (destData[dp + 1] & 0xff);
2038                        rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
2039                        gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
2040                        bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
2041                        aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
2042                    } break;
2043                    case TYPE_GENERIC_16_LSB: {
2044                        final int data = ((destData[dp + 1] & 0xff) << 8) | (destData[dp] & 0xff);
2045                        rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
2046                        gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
2047                        bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
2048                        aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
2049                    } break;
2050                    case TYPE_GENERIC_24: {
2051                        final int data = (( ((destData[dp] & 0xff) << 8) |
2052                            (destData[dp + 1] & 0xff)) << 8) |
2053                            (destData[dp + 2] & 0xff);
2054                        rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
2055                        gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
2056                        bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
2057                        aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
2058                    } break;
2059                    case TYPE_GENERIC_32_MSB: {
2060                        final int data = (( (( ((destData[dp] & 0xff) << 8) |
2061                            (destData[dp + 1] & 0xff)) << 8) |
2062                            (destData[dp + 2] & 0xff)) << 8) |
2063                            (destData[dp + 3] & 0xff);
2064                        rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
2065                        gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
2066                        bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
2067                        aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
2068                    } break;
2069                    case TYPE_GENERIC_32_LSB: {
2070                        final int data = (( (( ((destData[dp + 3] & 0xff) << 8) |
2071                            (destData[dp + 2] & 0xff)) << 8) |
2072                            (destData[dp + 1] & 0xff)) << 8) |
2073                            (destData[dp] & 0xff);
2074                        rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
2075                        gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
2076                        bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
2077                        aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
2078                    } break;
2079                }
2080                // Perform alpha blending
2081
a = aq + ((a - aq) * alpha >> 16);
2082                r = rq + ((r - rq) * alpha >> 16);
2083                g = gq + ((g - gq) * alpha >> 16);
2084                b = bq + ((b - bq) * alpha >> 16);
2085            }
2086
2087            /*** WRITE NEXT PIXEL ***/
2088            final int data =
2089                (r >>> destRedPreShift << destRedShift) |
2090                (g >>> destGreenPreShift << destGreenShift) |
2091                (b >>> destBluePreShift << destBlueShift) |
2092                (a >>> destAlphaPreShift << destAlphaShift);
2093            switch (dtype) {
2094                case TYPE_GENERIC_8: {
2095                    destData[dp] = (byte) data;
2096                } break;
2097                case TYPE_GENERIC_16_MSB: {
2098                    destData[dp] = (byte) (data >>> 8);
2099                    destData[dp + 1] = (byte) (data & 0xff);
2100                } break;
2101                case TYPE_GENERIC_16_LSB: {
2102                    destData[dp] = (byte) (data & 0xff);
2103                    destData[dp + 1] = (byte) (data >>> 8);
2104                } break;
2105                case TYPE_GENERIC_24: {
2106                    destData[dp] = (byte) (data >>> 16);
2107                    destData[dp + 1] = (byte) (data >>> 8);
2108                    destData[dp + 2] = (byte) (data & 0xff);
2109                } break;
2110                case TYPE_GENERIC_32_MSB: {
2111                    destData[dp] = (byte) (data >>> 24);
2112                    destData[dp + 1] = (byte) (data >>> 16);
2113                    destData[dp + 2] = (byte) (data >>> 8);
2114                    destData[dp + 3] = (byte) (data & 0xff);
2115                } break;
2116                case TYPE_GENERIC_32_LSB: {
2117                    destData[dp] = (byte) (data & 0xff);
2118                    destData[dp + 1] = (byte) (data >>> 8);
2119                    destData[dp + 2] = (byte) (data >>> 16);
2120                    destData[dp + 3] = (byte) (data >>> 24);
2121                } break;
2122            }
2123        }
2124    }
2125}
2126
2127/**
2128 * Blits an index palette image into an index palette image.
2129 * <p>
2130 * Note: The source and destination red, green, and blue
2131 * arrays may be null if no alpha blending or dither is to be
2132 * performed.
2133 * </p>
2134 *
2135 * @param op the blitter operation: a combination of BLIT_xxx flags
2136 * (see BLIT_xxx constants)
2137 * @param srcData the source byte array containing image data
2138 * @param srcDepth the source depth: one of 1, 2, 4, 8
2139 * @param srcStride the source number of bytes per line
2140 * @param srcOrder the source byte ordering: one of MSB_FIRST or LSB_FIRST;
2141 * ignored if srcDepth is not 1
2142 * @param srcX the top-left x-coord of the source blit region
2143 * @param srcY the top-left y-coord of the source blit region
2144 * @param srcWidth the width of the source blit region
2145 * @param srcHeight the height of the source blit region
2146 * @param srcReds the source palette red component intensities
2147 * @param srcGreens the source palette green component intensities
2148 * @param srcBlues the source palette blue component intensities
2149 * @param alphaMode the alpha blending or mask mode, may be
2150 * an integer 0-255 for global alpha; ignored if BLIT_ALPHA
2151 * not specified in the blitter operations
2152 * (see ALPHA_MODE_xxx constants)
2153 * @param alphaData the alpha blending or mask data, varies depending
2154 * on the value of alphaMode and sometimes ignored
2155 * @param alphaStride the alpha data number of bytes per line
2156 * @param alphaX the top-left x-coord of the alpha blit region
2157 * @param alphaY the top-left y-coord of the alpha blit region
2158 * @param destData the destination byte array containing image data
2159 * @param destDepth the destination depth: one of 1, 2, 4, 8
2160 * @param destStride the destination number of bytes per line
2161 * @param destOrder the destination byte ordering: one of MSB_FIRST or LSB_FIRST;
2162 * ignored if destDepth is not 1
2163 * @param destX the top-left x-coord of the destination blit region
2164 * @param destY the top-left y-coord of the destination blit region
2165 * @param destWidth the width of the destination blit region
2166 * @param destHeight the height of the destination blit region
2167 * @param destReds the destination palette red component intensities
2168 * @param destGreens the destination palette green component intensities
2169 * @param destBlues the destination palette blue component intensities
2170 * @param flipX if true the resulting image is flipped along the vertical axis
2171 * @param flipY if true the resulting image is flipped along the horizontal axis
2172 */

2173static void blit(int op,
2174    byte[] srcData, int srcDepth, int srcStride, int srcOrder,
2175    int srcX, int srcY, int srcWidth, int srcHeight,
2176    byte[] srcReds, byte[] srcGreens, byte[] srcBlues,
2177    int alphaMode, byte[] alphaData, int alphaStride, int alphaX, int alphaY,
2178    byte[] destData, int destDepth, int destStride, int destOrder,
2179    int destX, int destY, int destWidth, int destHeight,
2180    byte[] destReds, byte[] destGreens, byte[] destBlues,
2181    boolean flipX, boolean flipY) {
2182    if ((destWidth <= 0) || (destHeight <= 0) || (alphaMode == ALPHA_TRANSPARENT)) return;
2183
2184    /*** Prepare scaling data ***/
2185    final int dwm1 = destWidth - 1;
2186    final int sfxi = (dwm1 != 0) ? (int)((((long)srcWidth << 16) - 1) / dwm1) : 0;
2187    final int dhm1 = destHeight - 1;
2188    final int sfyi = (dhm1 != 0) ? (int)((((long)srcHeight << 16) - 1) / dhm1) : 0;
2189
2190    /*** Prepare source-related data ***/
2191    final int stype;
2192    switch (srcDepth) {
2193        case 8:
2194            stype = TYPE_INDEX_8;
2195            break;
2196        case 4:
2197            srcStride <<= 1;
2198            stype = TYPE_INDEX_4;
2199            break;
2200        case 2:
2201            srcStride <<= 2;
2202            stype = TYPE_INDEX_2;
2203            break;
2204        case 1:
2205            srcStride <<= 3;
2206            stype = (srcOrder == MSB_FIRST) ? TYPE_INDEX_1_MSB : TYPE_INDEX_1_LSB;
2207            break;
2208        default:
2209            //throw new IllegalArgumentException("Invalid source type");
2210
return;
2211    }
2212    int spr = srcY * srcStride + srcX;
2213
2214    /*** Prepare destination-related data ***/
2215    final int dtype;
2216    switch (destDepth) {
2217        case 8:
2218            dtype = TYPE_INDEX_8;
2219            break;
2220        case 4:
2221            destStride <<= 1;
2222            dtype = TYPE_INDEX_4;
2223            break;
2224        case 2:
2225            destStride <<= 2;
2226            dtype = TYPE_INDEX_2;
2227            break;
2228        case 1:
2229            destStride <<= 3;
2230            dtype = (destOrder == MSB_FIRST) ? TYPE_INDEX_1_MSB : TYPE_INDEX_1_LSB;
2231            break;
2232        default:
2233            //throw new IllegalArgumentException("Invalid source type");
2234
return;
2235    }
2236    int dpr = ((flipY) ? destY + dhm1 : destY) * destStride + ((flipX) ? destX + dwm1 : destX);
2237    final int dprxi = (flipX) ? -1 : 1;
2238    final int dpryi = (flipY) ? -destStride : destStride;
2239
2240    /*** Prepare special processing data ***/
2241    int apr;
2242    if ((op & BLIT_ALPHA) != 0) {
2243        switch (alphaMode) {
2244            case ALPHA_MASK_UNPACKED:
2245            case ALPHA_CHANNEL_SEPARATE:
2246                if (alphaData == null) alphaMode = 0x10000;
2247                apr = alphaY * alphaStride + alphaX;
2248                break;
2249            case ALPHA_MASK_PACKED:
2250                if (alphaData == null) alphaMode = 0x10000;
2251                alphaStride <<= 3;
2252                apr = alphaY * alphaStride + alphaX;
2253                break;
2254            case ALPHA_MASK_INDEX:
2255            case ALPHA_MASK_RGB:
2256                if (alphaData == null) alphaMode = 0x10000;
2257                apr = 0;
2258                break;
2259            default:
2260                alphaMode = (alphaMode << 16) / 255; // prescale
2261
case ALPHA_CHANNEL_SOURCE:
2262                apr = 0;
2263                break;
2264        }
2265    } else {
2266        alphaMode = 0x10000;
2267        apr = 0;
2268    }
2269    final boolean ditherEnabled = (op & BLIT_DITHER) != 0;
2270
2271    /*** Blit ***/
2272    int dp = dpr;
2273    int sp = spr;
2274    int ap = apr;
2275    int destPaletteSize = 1 << destDepth;
2276    if ((destReds != null) && (destReds.length < destPaletteSize)) destPaletteSize = destReds.length;
2277    byte[] paletteMapping = null;
2278    boolean isExactPaletteMapping = true;
2279    switch (alphaMode) {
2280        case 0x10000:
2281            /*** If the palettes and formats are equivalent use a one-to-one mapping ***/
2282            if ((stype == dtype) &&
2283                (srcReds == destReds) && (srcGreens == destGreens) && (srcBlues == destBlues)) {
2284                paletteMapping = ONE_TO_ONE_MAPPING;
2285                break;
2286            /*** If palettes have not been supplied, supply a suitable mapping ***/
2287            } else if ((srcReds == null) || (destReds == null)) {
2288                if (srcDepth <= destDepth) {
2289                    paletteMapping = ONE_TO_ONE_MAPPING;
2290                } else {
2291                    paletteMapping = new byte[1 << srcDepth];
2292                    int mask = (0xff << destDepth) >>> 8;
2293                    for (int i = 0; i < paletteMapping.length; ++i) paletteMapping[i] = (byte)(i & mask);
2294                }
2295                break;
2296            }
2297        case ALPHA_MASK_UNPACKED:
2298        case ALPHA_MASK_PACKED:
2299        case ALPHA_MASK_INDEX:
2300        case ALPHA_MASK_RGB:
2301            /*** Generate a palette mapping ***/
2302            int srcPaletteSize = 1 << srcDepth;
2303            paletteMapping = new byte[srcPaletteSize];
2304            if ((srcReds != null) && (srcReds.length < srcPaletteSize)) srcPaletteSize = srcReds.length;
2305            for (int i = 0, r, g, b, index; i < srcPaletteSize; ++i) {
2306                r = srcReds[i] & 0xff;
2307                g = srcGreens[i] & 0xff;
2308                b = srcBlues[i] & 0xff;
2309                index = 0;
2310                int minDistance = 0x7fffffff;
2311                for (int j = 0, dr, dg, db, distance; j < destPaletteSize; ++j) {
2312                    dr = (destReds[j] & 0xff) - r;
2313                    dg = (destGreens[j] & 0xff) - g;
2314                    db = (destBlues[j] & 0xff) - b;
2315                    distance = dr * dr + dg * dg + db * db;
2316                    if (distance < minDistance) {
2317                        index = j;
2318                        if (distance == 0) break;
2319                        minDistance = distance;
2320                    }
2321                }
2322                paletteMapping[i] = (byte)index;
2323                if (minDistance != 0) isExactPaletteMapping = false;
2324            }
2325            break;
2326    }
2327    if ((paletteMapping != null) && (isExactPaletteMapping || ! ditherEnabled)) {
2328        if ((stype == dtype) && (alphaMode == 0x10000)) {
2329            /*** Fast blit (copy w/ mapping) ***/
2330            switch (stype) {
2331                case TYPE_INDEX_8:
2332                    for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
2333                        for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
2334                            destData[dp] = paletteMapping[srcData[sp] & 0xff];
2335                            sp += (sfx >>> 16);
2336                        }
2337                    }
2338                    break;
2339                case TYPE_INDEX_4:
2340                    for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
2341                        for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
2342                            final int v;
2343                            if ((sp & 1) != 0) v = paletteMapping[srcData[sp >> 1] & 0x0f];
2344                            else v = (srcData[sp >> 1] >>> 4) & 0x0f;
2345                            sp += (sfx >>> 16);
2346                            if ((dp & 1) != 0) destData[dp >> 1] = (byte)((destData[dp >> 1] & 0xf0) | v);
2347                            else destData[dp >> 1] = (byte)((destData[dp >> 1] & 0x0f) | (v << 4));
2348                        }
2349                    }
2350                    break;
2351                case TYPE_INDEX_2:
2352                    for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
2353                        for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
2354                            final int index = paletteMapping[(srcData[sp >> 2] >>> (6 - (sp & 3) * 2)) & 0x03];
2355                            sp += (sfx >>> 16);
2356                            final int shift = 6 - (dp & 3) * 2;
2357                            destData[dp >> 2] = (byte)(destData[dp >> 2] & ~(0x03 << shift) | (index << shift));
2358                        }
2359                    }
2360                    break;
2361                case TYPE_INDEX_1_MSB:
2362                    for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
2363                        for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
2364                            final int index = paletteMapping[(srcData[sp >> 3] >>> (7 - (sp & 7))) & 0x01];
2365                            sp += (sfx >>> 16);
2366                            final int shift = 7 - (dp & 7);
2367                            destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (index << shift));
2368                        }
2369                    }
2370                    break;
2371                case TYPE_INDEX_1_LSB:
2372                    for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
2373                        for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
2374                            final int index = paletteMapping[(srcData[sp >> 3] >>> (sp & 7)) & 0x01];
2375                            sp += (sfx >>> 16);
2376                            final int shift = dp & 7;
2377                            destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (index << shift));
2378                        }
2379                    }
2380                    break;
2381            }
2382        } else {
2383            /*** Convert between indexed modes using mapping and mask ***/
2384            for (int dy = destHeight, sfy = sfyi; dy > 0; --dy,
2385                    sp = spr += (sfy >>> 16) * srcStride,
2386                    sfy = (sfy & 0xffff) + sfyi,
2387                    dp = dpr += dpryi) {
2388                for (int dx = destWidth, sfx = sfxi; dx > 0; --dx,
2389                        dp += dprxi,
2390                        sfx = (sfx & 0xffff) + sfxi) {
2391                    int index;
2392                    /*** READ NEXT PIXEL ***/
2393                    switch (stype) {
2394                        case TYPE_INDEX_8:
2395                            index = srcData[sp] & 0xff;
2396                            sp += (sfx >>> 16);
2397                            break;
2398                        case TYPE_INDEX_4:
2399                            if ((sp & 1) != 0) index = srcData[sp >> 1] & 0x0f;
2400                            else index = (srcData[sp >> 1] >>> 4) & 0x0f;
2401                            sp += (sfx >>> 16);
2402                            break;
2403                        case TYPE_INDEX_2:
2404                            index = (srcData[sp >> 2] >>> (6 - (sp & 3) * 2)) & 0x03;
2405                            sp += (sfx >>> 16);
2406                            break;
2407                        case TYPE_INDEX_1_MSB:
2408                            index = (srcData[sp >> 3] >>> (7 - (sp & 7))) & 0x01;
2409                            sp += (sfx >>> 16);
2410                            break;
2411                        case TYPE_INDEX_1_LSB:
2412                            index = (srcData[sp >> 3] >>> (sp & 7)) & 0x01;
2413                            sp += (sfx >>> 16);
2414                            break;
2415                        default:
2416                            return;
2417                    }
2418                    /*** APPLY MASK ***/
2419                    switch (alphaMode) {
2420                        case ALPHA_MASK_UNPACKED: {
2421                            final byte mask = alphaData[ap];
2422                            ap += (sfx >> 16);
2423                            if (mask == 0) continue;
2424                        } break;
2425                        case ALPHA_MASK_PACKED: {
2426                            final int mask = alphaData[ap >> 3] & (1 << (ap & 7));
2427                            ap += (sfx >> 16);
2428                            if (mask == 0) continue;
2429                        } break;
2430                        case ALPHA_MASK_INDEX: {
2431                            int i = 0;
2432                            while (i < alphaData.length) {
2433                                if (index == (alphaData[i] & 0xff)) break;
2434                            }
2435                            if (i < alphaData.length) continue;
2436                        } break;
2437                        case ALPHA_MASK_RGB: {
2438                            final byte r = srcReds[index], g = srcGreens[index], b = srcBlues[index];
2439                            int i = 0;
2440                            while (i < alphaData.length) {
2441                                if ((r == alphaData[i]) && (g == alphaData[i + 1]) && (b == alphaData[i + 2])) break;
2442                                i += 3;
2443                            }
2444                            if (i < alphaData.length) continue;
2445                        } break;
2446                    }
2447                    index = paletteMapping[index] & 0xff;
2448            
2449                    /*** WRITE NEXT PIXEL ***/
2450                    switch (dtype) {
2451                        case TYPE_INDEX_8:
2452                            destData[dp] = (byte) index;
2453                            break;
2454                        case TYPE_INDEX_4:
2455                            if ((dp & 1) != 0) destData[dp >> 1] = (byte)((destData[dp >> 1] & 0xf0) | index);
2456                            else destData[dp >> 1] = (byte)((destData[dp >> 1] & 0x0f) | (index << 4));
2457                            break;
2458                        case TYPE_INDEX_2: {
2459                            final int shift = 6 - (dp & 3) * 2;
2460                            destData[dp >> 2] = (byte)(destData[dp >> 2] & ~(0x03 << shift) | (index << shift));
2461                        } break;
2462                        case TYPE_INDEX_1_MSB: {
2463                            final int shift = 7 - (dp & 7);
2464                            destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (index << shift));
2465                        } break;
2466                        case TYPE_INDEX_1_LSB: {
2467                            final int shift = dp & 7;
2468                            destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (index << shift));
2469                        } break;
2470                    }
2471                }
2472            }
2473        }
2474        return;
2475    }
2476        
2477    /*** Comprehensive blit (apply transformations) ***/
2478    int alpha = alphaMode;
2479    int index = 0;
2480    int indexq = 0;
2481    int lastindex = 0, lastr = -1, lastg = -1, lastb = -1;
2482    final int[] rerr, gerr, berr;
2483    if (ditherEnabled) {
2484        rerr = new int[destWidth + 2];
2485        gerr = new int[destWidth + 2];
2486        berr = new int[destWidth + 2];
2487    } else {
2488        rerr = null; gerr = null; berr = null;
2489    }
2490    for (int dy = destHeight, sfy = sfyi; dy > 0; --dy,
2491            sp = spr += (sfy >>> 16) * srcStride,
2492            ap = apr += (sfy >>> 16) * alphaStride,
2493            sfy = (sfy & 0xffff) + sfyi,
2494            dp = dpr += dpryi) {
2495        int lrerr = 0, lgerr = 0, lberr = 0;
2496        for (int dx = destWidth, sfx = sfxi; dx > 0; --dx,
2497                dp += dprxi,
2498                sfx = (sfx & 0xffff) + sfxi) {
2499            /*** READ NEXT PIXEL ***/
2500            switch (stype) {
2501                case TYPE_INDEX_8:
2502                    index = srcData[sp] & 0xff;
2503                    sp += (sfx >>> 16);
2504                    break;
2505                case TYPE_INDEX_4:
2506                    if ((sp & 1) != 0) index = srcData[sp >> 1] & 0x0f;
2507                    else index = (srcData[sp >> 1] >>> 4) & 0x0f;
2508                    sp += (sfx >>> 16);
2509                    break;
2510                case TYPE_INDEX_2:
2511                    index = (srcData[sp >> 2] >>> (6 - (sp & 3) * 2)) & 0x03;
2512                    sp += (sfx >>> 16);
2513                    break;
2514                case TYPE_INDEX_1_MSB:
2515                    index = (srcData[sp >> 3] >>> (7 - (sp & 7))) & 0x01;
2516                    sp += (sfx >>> 16);
2517                    break;
2518                case TYPE_INDEX_1_LSB:
2519                    index = (srcData[sp >> 3] >>> (sp & 7)) & 0x01;
2520                    sp += (sfx >>> 16);
2521                    break;
2522            }
2523
2524            /*** DO SPECIAL PROCESSING IF REQUIRED ***/
2525            int r = srcReds[index] & 0xff, g = srcGreens[index] & 0xff, b = srcBlues[index] & 0xff;
2526            switch (alphaMode) {
2527                case ALPHA_CHANNEL_SEPARATE:
2528                    alpha = ((alphaData[ap] & 0xff) << 16) / 255;
2529                    ap += (sfx >> 16);
2530                    break;
2531                case ALPHA_MASK_UNPACKED:
2532                    alpha = (alphaData[ap] != 0) ? 0x10000 : 0;
2533                    ap += (sfx >> 16);
2534                    break;
2535                case ALPHA_MASK_PACKED:
2536                    alpha = (alphaData[ap >> 3] << ((ap & 7) + 9)) & 0x10000;
2537                    ap += (sfx >> 16);
2538                    break;
2539                case ALPHA_MASK_INDEX: { // could speed up using binary search if we sorted the indices
2540
int i = 0;
2541                    while (i < alphaData.length) {
2542                        if (index == (alphaData[i] & 0xff)) break;
2543                    }
2544                    if (i < alphaData.length) continue;
2545                } break;
2546                case ALPHA_MASK_RGB: {
2547                    int i = 0;
2548                    while (i < alphaData.length) {
2549                        if ((r == (alphaData[i] & 0xff)) &&
2550                            (g == (alphaData[i + 1] & 0xff)) &&
2551                            (b == (alphaData[i + 2] & 0xff))) break;
2552                        i += 3;
2553                    }
2554                    if (i < alphaData.length) continue;
2555                } break;
2556            }
2557            if (alpha != 0x10000) {
2558                if (alpha == 0x0000) continue;
2559                switch (dtype) {
2560                    case TYPE_INDEX_8:
2561                        indexq = destData[dp] & 0xff;
2562                        break;
2563                    case TYPE_INDEX_4:
2564                        if ((dp & 1) != 0) indexq = destData[dp >> 1] & 0x0f;
2565                        else indexq = (destData[dp >> 1] >>> 4) & 0x0f;
2566                        break;
2567                    case TYPE_INDEX_2:
2568                        indexq = (destData[dp >> 2] >>> (6 - (dp & 3) * 2)) & 0x03;
2569                        break;
2570                    case TYPE_INDEX_1_MSB:
2571                        indexq = (destData[dp >> 3] >>> (7 - (dp & 7))) & 0x01;
2572                        break;
2573                    case TYPE_INDEX_1_LSB:
2574                        indexq = (destData[dp >> 3] >>> (dp & 7)) & 0x01;
2575                        break;
2576                }
2577                // Perform alpha blending
2578
final int rq = destReds[indexq] & 0xff;
2579                final int gq = destGreens[indexq] & 0xff;
2580                final int bq = destBlues[indexq] & 0xff;
2581                r = rq + ((r - rq) * alpha >> 16);
2582                g = gq + ((g - gq) * alpha >> 16);
2583                b = bq + ((b - bq) * alpha >> 16);
2584            }
2585
2586            /*** MAP COLOR TO THE PALETTE ***/
2587            if (ditherEnabled) {
2588                // Floyd-Steinberg error diffusion
2589
r += rerr[dx] >> 4;
2590                if (r < 0) r = 0; else if (r > 255) r = 255;
2591                g += gerr[dx] >> 4;
2592                if (g < 0) g = 0; else if (g > 255) g = 255;
2593                b += berr[dx] >> 4;
2594                if (b < 0) b = 0; else if (b > 255) b = 255;
2595                rerr[dx] = lrerr;
2596                gerr[dx] = lgerr;
2597                berr[dx] = lberr;
2598            }
2599            if (r != lastr || g != lastg || b != lastb) {
2600                // moving the variable declarations out seems to make the JDK JIT happier...
2601
for (int j = 0, dr, dg, db, distance, minDistance = 0x7fffffff; j < destPaletteSize; ++j) {
2602                    dr = (destReds[j] & 0xff) - r;
2603                    dg = (destGreens[j] & 0xff) - g;
2604                    db = (destBlues[j] & 0xff) - b;
2605                    distance = dr * dr + dg * dg + db * db;
2606                    if (distance < minDistance) {
2607                        lastindex = j;
2608                        if (distance == 0) break;
2609                        minDistance = distance;
2610                    }
2611                }
2612                lastr = r; lastg = g; lastb = b;
2613            }
2614            if (ditherEnabled) {
2615                // Floyd-Steinberg error diffusion, cont'd...
2616
final int dxm1 = dx - 1, dxp1 = dx + 1;
2617                int acc;
2618                rerr[dxp1] += acc = (lrerr = r - (destReds[lastindex] & 0xff)) + lrerr + lrerr;
2619                rerr[dx] += acc += lrerr + lrerr;
2620                rerr[dxm1] += acc + lrerr + lrerr;
2621                gerr[dxp1] += acc = (lgerr = g - (destGreens[lastindex] & 0xff)) + lgerr + lgerr;
2622                gerr[dx] += acc += lgerr + lgerr;
2623                gerr[dxm1] += acc + lgerr + lgerr;
2624                berr[dxp1] += acc = (lberr = b - (destBlues[lastindex] & 0xff)) + lberr + lberr;
2625                berr[dx] += acc += lberr + lberr;
2626                berr[dxm1] += acc + lberr + lberr;
2627            }
2628
2629            /*** WRITE NEXT PIXEL ***/
2630            switch (dtype) {
2631                case TYPE_INDEX_8:
2632                    destData[dp] = (byte) lastindex;
2633                    break;
2634                case TYPE_INDEX_4:
2635                    if ((dp & 1) != 0) destData[dp >> 1] = (byte)((destData[dp >> 1] & 0xf0) | lastindex);
2636                    else destData[dp >> 1] = (byte)((destData[dp >> 1] & 0x0f) | (lastindex << 4));
2637                    break;
2638                case TYPE_INDEX_2: {
2639                    final int shift = 6 - (dp & 3) * 2;
2640                    destData[dp >> 2] = (byte)(destData[dp >> 2] & ~(0x03 << shift) | (lastindex << shift));
2641                } break;
2642                case TYPE_INDEX_1_MSB: {
2643                    final int shift = 7 - (dp & 7);
2644                    destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (lastindex << shift));
2645                } break;
2646                case TYPE_INDEX_1_LSB: {
2647                    final int shift = dp & 7;
2648                    destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (lastindex << shift));
2649                } break;
2650            }
2651        }
2652    }
2653}
2654
2655/**
2656 * Blits an index palette image into a direct palette image.
2657 * <p>
2658 * Note: The source and destination masks and palettes must
2659 * always be fully specified.
2660 * </p>
2661 *
2662 * @param op the blitter operation: a combination of BLIT_xxx flags
2663 * (see BLIT_xxx constants)
2664 * @param srcData the source byte array containing image data
2665 * @param srcDepth the source depth: one of 1, 2, 4, 8
2666 * @param srcStride the source number of bytes per line
2667 * @param srcOrder the source byte ordering: one of MSB_FIRST or LSB_FIRST;
2668 * ignored if srcDepth is not 1
2669 * @param srcX the top-left x-coord of the source blit region
2670 * @param srcY the top-left y-coord of the source blit region
2671 * @param srcWidth the width of the source blit region
2672 * @param srcHeight the height of the source blit region
2673 * @param srcReds the source palette red component intensities
2674 * @param srcGreens the source palette green component intensities
2675 * @param srcBlues the source palette blue component intensities
2676 * @param alphaMode the alpha blending or mask mode, may be
2677 * an integer 0-255 for global alpha; ignored if BLIT_ALPHA
2678 * not specified in the blitter operations
2679 * (see ALPHA_MODE_xxx constants)
2680 * @param alphaData the alpha blending or mask data, varies depending
2681 * on the value of alphaMode and sometimes ignored
2682 * @param alphaStride the alpha data number of bytes per line
2683 * @param alphaX the top-left x-coord of the alpha blit region
2684 * @param alphaY the top-left y-coord of the alpha blit region
2685 * @param destData the destination byte array containing image data
2686 * @param destDepth the destination depth: one of 8, 16, 24, 32
2687 * @param destStride the destination number of bytes per line
2688 * @param destOrder the destination byte ordering: one of MSB_FIRST or LSB_FIRST;
2689 * ignored if destDepth is not 16 or 32
2690 * @param destX the top-left x-coord of the destination blit region
2691 * @param destY the top-left y-coord of the destination blit region
2692 * @param destWidth the width of the destination blit region
2693 * @param destHeight the height of the destination blit region
2694 * @param destRedMask the destination red channel mask
2695 * @param destGreenMask the destination green channel mask
2696 * @param destBlueMask the destination blue channel mask
2697 * @param flipX if true the resulting image is flipped along the vertical axis
2698 * @param flipY if true the resulting image is flipped along the horizontal axis
2699 */

2700static void blit(int op,
2701    byte[] srcData, int srcDepth, int srcStride, int srcOrder,
2702    int srcX, int srcY, int srcWidth, int srcHeight,
2703    byte[] srcReds, byte[] srcGreens, byte[] srcBlues,
2704    int alphaMode, byte[] alphaData, int alphaStride, int alphaX, int alphaY,
2705    byte[] destData, int destDepth, int destStride, int destOrder,
2706    int destX, int destY, int destWidth, int destHeight,
2707    int destRedMask, int destGreenMask, int destBlueMask,
2708    boolean flipX, boolean flipY) {
2709    if ((destWidth <= 0) || (destHeight <= 0) || (alphaMode == ALPHA_TRANSPARENT)) return;
2710
2711    // these should be supplied as params later
2712
final int destAlphaMask = 0;
2713
2714    /*** Prepare scaling data ***/
2715    final int dwm1 = destWidth - 1;
2716    final int sfxi = (dwm1 != 0) ? (int)((((long)srcWidth << 16) - 1) / dwm1) : 0;
2717    final int dhm1 = destHeight - 1;
2718    final int sfyi = (dhm1 != 0) ? (int)((((long)srcHeight << 16) - 1) / dhm1) : 0;
2719
2720    /*** Prepare source-related data ***/
2721    final int stype;
2722    switch (srcDepth) {
2723        case 8:
2724            stype = TYPE_INDEX_8;
2725            break;
2726        case 4:
2727            srcStride <<= 1;
2728            stype = TYPE_INDEX_4;
2729            break;
2730        case 2:
2731            srcStride <<= 2;
2732            stype = TYPE_INDEX_2;
2733            break;
2734        case 1:
2735            srcStride <<= 3;
2736            stype = (srcOrder == MSB_FIRST) ? TYPE_INDEX_1_MSB : TYPE_INDEX_1_LSB;
2737            break;
2738        default:
2739            //throw new IllegalArgumentException("Invalid source type");
2740
return;
2741    }
2742    int spr = srcY * srcStride + srcX;
2743
2744    /*** Prepare destination-related data ***/
2745    final int dbpp, dtype;
2746    switch (destDepth) {
2747        case 8:
2748            dbpp = 1;
2749            dtype = TYPE_GENERIC_8;
2750            break;
2751        case 16:
2752            dbpp = 2;
2753            dtype = (destOrder == MSB_FIRST) ? TYPE_GENERIC_16_MSB : TYPE_GENERIC_16_LSB;
2754            break;
2755        case 24:
2756            dbpp = 3;
2757            dtype = TYPE_GENERIC_24;
2758            break;
2759        case 32:
2760            dbpp = 4;
2761            dtype = (destOrder == MSB_FIRST) ? TYPE_GENERIC_32_MSB : TYPE_GENERIC_32_LSB;
2762            break;
2763        default:
2764            //throw new IllegalArgumentException("Invalid destination type");
2765
return;
2766    }
2767    int dpr = ((flipY) ? destY + dhm1 : destY) * destStride + ((flipX) ? destX + dwm1 : destX) * dbpp;
2768    final int dprxi = (flipX) ? -dbpp : dbpp;
2769    final int dpryi = (flipY) ? -destStride : destStride;
2770
2771    /*** Prepare special processing data ***/
2772    int apr;
2773    if ((op & BLIT_ALPHA) != 0) {
2774        switch (alphaMode) {
2775            case ALPHA_MASK_UNPACKED:
2776            case ALPHA_CHANNEL_SEPARATE:
2777                if (alphaData == null) alphaMode = 0x10000;
2778                apr = alphaY * alphaStride + alphaX;
2779                break;
2780            case ALPHA_MASK_PACKED:
2781                if (alphaData == null) alphaMode = 0x10000;
2782                alphaStride <<= 3;
2783                apr = alphaY * alphaStride + alphaX;
2784                break;
2785            case ALPHA_MASK_INDEX:
2786            case ALPHA_MASK_RGB:
2787                if (alphaData == null) alphaMode = 0x10000;
2788                apr = 0;
2789                break;
2790            default:
2791                alphaMode = (alphaMode << 16) / 255; // prescale
2792
case ALPHA_CHANNEL_SOURCE:
2793                apr = 0;
2794                break;
2795        }
2796    } else {
2797        alphaMode = 0x10000;
2798        apr = 0;
2799    }
2800
2801    /*** Comprehensive blit (apply transformations) ***/
2802    final int destRedShift = getChannelShift(destRedMask);
2803    final int destRedWidth = getChannelWidth(destRedMask, destRedShift);
2804    final byte[] destReds = ANY_TO_EIGHT[destRedWidth];
2805    final int destRedPreShift = 8 - destRedWidth;
2806    final int destGreenShift = getChannelShift(destGreenMask);
2807    final int destGreenWidth = getChannelWidth(destGreenMask, destGreenShift);
2808    final byte[] destGreens = ANY_TO_EIGHT[destGreenWidth];
2809    final int destGreenPreShift = 8 - destGreenWidth;
2810    final int destBlueShift = getChannelShift(destBlueMask);
2811    final int destBlueWidth = getChannelWidth(destBlueMask, destBlueShift);
2812    final byte[] destBlues = ANY_TO_EIGHT[destBlueWidth];
2813    final int destBluePreShift = 8 - destBlueWidth;
2814    final int destAlphaShift = getChannelShift(destAlphaMask);
2815    final int destAlphaWidth = getChannelWidth(destAlphaMask, destAlphaShift);
2816    final byte[] destAlphas = ANY_TO_EIGHT[destAlphaWidth];
2817    final int destAlphaPreShift = 8 - destAlphaWidth;
2818
2819    int dp = dpr;
2820    int sp = spr;
2821    int ap = apr, alpha = alphaMode;
2822    int r = 0, g = 0, b = 0, a = 0, index = 0;
2823    int rq = 0, gq = 0, bq = 0, aq = 0;
2824    for (int dy = destHeight, sfy = sfyi; dy > 0; --dy,
2825            sp = spr += (sfy >>> 16) * srcStride,
2826            ap = apr += (sfy >>> 16) * alphaStride,
2827            sfy = (sfy & 0xffff) + sfyi,
2828            dp = dpr += dpryi) {
2829        for (int dx = destWidth, sfx = sfxi; dx > 0; --dx,
2830                dp += dprxi,
2831                sfx = (sfx & 0xffff) + sfxi) {
2832            /*** READ NEXT PIXEL ***/
2833            switch (stype) {
2834                case TYPE_INDEX_8:
2835                    index = srcData[sp] & 0xff;
2836                    sp += (sfx >>> 16);
2837                    break;
2838                case TYPE_INDEX_4:
2839                    if ((sp & 1) != 0) index = srcData[sp >> 1] & 0x0f;
2840                    else index = (srcData[sp >> 1] >>> 4) & 0x0f;
2841                    sp += (sfx >>> 16);
2842                    break;
2843                case TYPE_INDEX_2:
2844                    index = (srcData[sp >> 2] >>> (6 - (sp & 3) * 2)) & 0x03;
2845                    sp += (sfx >>> 16);
2846                    break;
2847                case TYPE_INDEX_1_MSB:
2848                    index = (srcData[sp >> 3] >>> (7 - (sp & 7))) & 0x01;
2849                    sp += (sfx >>> 16);
2850                    break;
2851                case TYPE_INDEX_1_LSB:
2852                    index = (srcData[sp >> 3] >>> (sp & 7)) & 0x01;
2853                    sp += (sfx >>> 16);
2854                    break;
2855            }
2856
2857            /*** DO SPECIAL PROCESSING IF REQUIRED ***/
2858            r = srcReds[index] & 0xff;
2859            g = srcGreens[index] & 0xff;
2860            b = srcBlues[index] & 0xff;
2861            switch (alphaMode) {
2862                case ALPHA_CHANNEL_SEPARATE:
2863                    alpha = ((alphaData[ap] & 0xff) << 16) / 255;
2864                    ap += (sfx >> 16);
2865                    break;
2866                case ALPHA_MASK_UNPACKED:
2867                    alpha = (alphaData[ap] != 0) ? 0x10000 : 0;
2868                    ap += (sfx >> 16);
2869                    break;
2870                case ALPHA_MASK_PACKED:
2871                    alpha = (alphaData[ap >> 3] << ((ap & 7) + 9)) & 0x10000;
2872                    ap += (sfx >> 16);
2873                    break;
2874                case ALPHA_MASK_INDEX: { // could speed up using binary search if we sorted the indices
2875
int i = 0;
2876                    while (i < alphaData.length) {
2877                        if (index == (alphaData[i] & 0xff)) break;
2878                    }
2879                    if (i < alphaData.length) continue;
2880                } break;
2881                case ALPHA_MASK_RGB: {
2882                    int i = 0;
2883                    while (i < alphaData.length) {
2884                        if ((r == (alphaData[i] & 0xff)) &&
2885                            (g == (alphaData[i + 1] & 0xff)) &&
2886                            (b == (alphaData[i + 2] & 0xff))) break;
2887                        i += 3;
2888                    }
2889                    if (i < alphaData.length) continue;
2890                } break;
2891            }
2892            if (alpha != 0x10000) {
2893                if (alpha == 0x0000) continue;
2894                switch (dtype) {
2895                    case TYPE_GENERIC_8: {
2896                        final int data = destData[dp] & 0xff;
2897                        rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
2898                        gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
2899                        bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
2900                        aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
2901                    } break;
2902                    case TYPE_GENERIC_16_MSB: {
2903                        final int data = ((destData[dp] & 0xff) << 8) | (destData[dp + 1] & 0xff);
2904                        rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
2905                        gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
2906                        bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
2907                        aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
2908                    } break;
2909                    case TYPE_GENERIC_16_LSB: {
2910                        final int data = ((destData[dp + 1] & 0xff) << 8) | (destData[dp] & 0xff);
2911                        rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
2912                        gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
2913                        bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
2914                        aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
2915                    } break;
2916                    case TYPE_GENERIC_24: {
2917                        final int data = (( ((destData[dp] & 0xff) << 8) |
2918                            (destData[dp + 1] & 0xff)) << 8) |
2919                            (destData[dp + 2] & 0xff);
2920                        rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
2921                        gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
2922                        bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
2923                        aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
2924                    } break;
2925                    case TYPE_GENERIC_32_MSB: {
2926                        final int data = (( (( ((destData[dp] & 0xff) << 8) |
2927                            (destData[dp + 1] & 0xff)) << 8) |
2928                            (destData[dp + 2] & 0xff)) << 8) |
2929                            (destData[dp + 3] & 0xff);
2930                        rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
2931                        gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
2932                        bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
2933                        aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
2934                    } break;
2935                    case TYPE_GENERIC_32_LSB: {
2936                        final int data = (( (( ((destData[dp + 3] & 0xff) << 8) |
2937                            (destData[dp + 2] & 0xff)) << 8) |
2938                            (destData[dp + 1] & 0xff)) << 8) |
2939                            (destData[dp] & 0xff);
2940                        rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
2941                        gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
2942                        bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
2943                        aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
2944                    } break;
2945                }
2946                // Perform alpha blending
2947
a = aq + ((a - aq) * alpha >> 16);
2948                r = rq + ((r - rq) * alpha >> 16);
2949                g = gq + ((g - gq) * alpha >> 16);
2950                b = bq + ((b - bq) * alpha >> 16);
2951            }
2952
2953            /*** WRITE NEXT PIXEL ***/
2954            final int data =
2955                (r >>> destRedPreShift << destRedShift) |
2956                (g >>> destGreenPreShift << destGreenShift) |
2957                (b >>> destBluePreShift << destBlueShift) |
2958                (a >>> destAlphaPreShift << destAlphaShift);
2959            switch (dtype) {
2960                case TYPE_GENERIC_8: {
2961                    destData[dp] = (byte) data;
2962                } break;
2963                case TYPE_GENERIC_16_MSB: {
2964                    destData[dp] = (byte) (data >>> 8);
2965                    destData[dp + 1] = (byte) (data & 0xff);
2966                } break;
2967                case TYPE_GENERIC_16_LSB: {
2968                    destData[dp] = (byte) (data & 0xff);
2969                    destData[dp + 1] = (byte) (data >>> 8);
2970                } break;
2971                case TYPE_GENERIC_24: {
2972                    destData[dp] = (byte) (data >>> 16);
2973                    destData[dp + 1] = (byte) (data >>> 8);
2974                    destData[dp + 2] = (byte) (data & 0xff);
2975                } break;
2976                case TYPE_GENERIC_32_MSB: {
2977                    destData[dp] = (byte) (data >>> 24);
2978                    destData[dp + 1] = (byte) (data >>> 16);
2979                    destData[dp + 2] = (byte) (data >>> 8);
2980                    destData[dp + 3] = (byte) (data & 0xff);
2981                } break;
2982                case TYPE_GENERIC_32_LSB: {
2983                    destData[dp] = (byte) (data & 0xff);
2984                    destData[dp + 1] = (byte) (data >>> 8);
2985                    destData[dp + 2] = (byte) (data >>> 16);
2986                    destData[dp + 3] = (byte) (data >>> 24);
2987                } break;
2988            }
2989        }
2990    }
2991}
2992
2993/**
2994 * Blits a direct palette image into an index palette image.
2995 * <p>
2996 * Note: The source and destination masks and palettes must
2997 * always be fully specified.
2998 * </p>
2999 *
3000 * @param op the blitter operation: a combination of BLIT_xxx flags
3001 * (see BLIT_xxx constants)
3002 * @param srcData the source byte array containing image data
3003 * @param srcDepth the source depth: one of 8, 16, 24, 32
3004 * @param srcStride the source number of bytes per line
3005 * @param srcOrder the source byte ordering: one of MSB_FIRST or LSB_FIRST;
3006 * ignored if srcDepth is not 16 or 32
3007 * @param srcX the top-left x-coord of the source blit region
3008 * @param srcY the top-left y-coord of the source blit region
3009 * @param srcWidth the width of the source blit region
3010 * @param srcHeight the height of the source blit region
3011 * @param srcRedMask the source red channel mask
3012 * @param srcGreenMask the source green channel mask
3013 * @param srcBlueMask the source blue channel mask
3014 * @param alphaMode the alpha blending or mask mode, may be
3015 * an integer 0-255 for global alpha; ignored if BLIT_ALPHA
3016 * not specified in the blitter operations
3017 * (see ALPHA_MODE_xxx constants)
3018 * @param alphaData the alpha blending or mask data, varies depending
3019 * on the value of alphaMode and sometimes ignored
3020 * @param alphaStride the alpha data number of bytes per line
3021 * @param alphaX the top-left x-coord of the alpha blit region
3022 * @param alphaY the top-left y-coord of the alpha blit region
3023 * @param destData the destination byte array containing image data
3024 * @param destDepth the destination depth: one of 1, 2, 4, 8
3025 * @param destStride the destination number of bytes per line
3026 * @param destOrder the destination byte ordering: one of MSB_FIRST or LSB_FIRST;
3027 * ignored if destDepth is not 1
3028 * @param destX the top-left x-coord of the destination blit region
3029 * @param destY the top-left y-coord of the destination blit region
3030 * @param destWidth the width of the destination blit region
3031 * @param destHeight the height of the destination blit region
3032 * @param destReds the destination palette red component intensities
3033 * @param destGreens the destination palette green component intensities
3034 * @param destBlues the destination palette blue component intensities
3035 * @param flipX if true the resulting image is flipped along the vertical axis
3036 * @param flipY if true the resulting image is flipped along the horizontal axis
3037 */

3038static void blit(int op,
3039    byte[] srcData, int srcDepth, int srcStride, int srcOrder,
3040    int srcX, int srcY, int srcWidth, int srcHeight,
3041    int srcRedMask, int srcGreenMask, int srcBlueMask,
3042    int alphaMode, byte[] alphaData, int alphaStride, int alphaX, int alphaY,
3043    byte[] destData, int destDepth, int destStride, int destOrder,
3044    int destX, int destY, int destWidth, int destHeight,
3045    byte[] destReds, byte[] destGreens, byte[] destBlues,
3046    boolean flipX, boolean flipY) {
3047    if ((destWidth <= 0) || (destHeight <= 0) || (alphaMode == ALPHA_TRANSPARENT)) return;
3048
3049    // these should be supplied as params later
3050
final int srcAlphaMask = 0;
3051
3052    /*** Prepare scaling data ***/
3053    final int dwm1 = destWidth - 1;
3054    final int sfxi = (dwm1 != 0) ? (int)((((long)srcWidth << 16) - 1) / dwm1) : 0;
3055    final int dhm1 = destHeight - 1;
3056    final int sfyi = (dhm1 != 0) ? (int)((((long)srcHeight << 16) - 1) / dhm1) : 0;
3057
3058    /*** Prepare source-related data ***/
3059    final int sbpp, stype;
3060    switch (srcDepth) {
3061        case 8:
3062            sbpp = 1;
3063            stype = TYPE_GENERIC_8;
3064            break;
3065        case 16:
3066            sbpp = 2;
3067            stype = (srcOrder == MSB_FIRST) ? TYPE_GENERIC_16_MSB : TYPE_GENERIC_16_LSB;
3068            break;
3069        case 24:
3070            sbpp = 3;
3071            stype = TYPE_GENERIC_24;
3072            break;
3073        case 32:
3074            sbpp = 4;
3075            stype = (srcOrder == MSB_FIRST) ? TYPE_GENERIC_32_MSB : TYPE_GENERIC_32_LSB;
3076            break;
3077        default:
3078            //throw new IllegalArgumentException("Invalid source type");
3079
return;
3080    }
3081    int spr = srcY * srcStride + srcX * sbpp;
3082
3083    /*** Prepare destination-related data ***/
3084    final int dtype;
3085    switch (destDepth) {
3086        case 8:
3087            dtype = TYPE_INDEX_8;
3088            break;
3089        case 4:
3090            destStride <<= 1;
3091            dtype = TYPE_INDEX_4;
3092            break;
3093        case 2:
3094            destStride <<= 2;
3095            dtype = TYPE_INDEX_2;
3096            break;
3097        case 1:
3098            destStride <<= 3;
3099            dtype = (destOrder == MSB_FIRST) ? TYPE_INDEX_1_MSB : TYPE_INDEX_1_LSB;
3100            break;
3101        default:
3102            //throw new IllegalArgumentException("Invalid source type");
3103
return;
3104    }
3105    int dpr = ((flipY) ? destY + dhm1 : destY) * destStride + ((flipX) ? destX + dwm1 : destX);
3106    final int dprxi = (flipX) ? -1 : 1;
3107    final int dpryi = (flipY) ? -destStride : destStride;
3108
3109    /*** Prepare special processing data ***/
3110    int apr;
3111    if ((op & BLIT_ALPHA) != 0) {
3112        switch (alphaMode) {
3113            case ALPHA_MASK_UNPACKED:
3114            case ALPHA_CHANNEL_SEPARATE:
3115                if (alphaData == null) alphaMode = 0x10000;
3116                apr = alphaY * alphaStride + alphaX;
3117                break;
3118            case ALPHA_MASK_PACKED:
3119                if (alphaData == null) alphaMode = 0x10000;
3120                alphaStride <<= 3;
3121                apr = alphaY * alphaStride + alphaX;
3122                break;
3123            case ALPHA_MASK_INDEX:
3124                //throw new IllegalArgumentException("Invalid alpha type");
3125
return;
3126            case ALPHA_MASK_RGB:
3127                if (alphaData == null) alphaMode = 0x10000;
3128                apr = 0;
3129                break;
3130            default:
3131                alphaMode = (alphaMode << 16) / 255; // prescale
3132
case ALPHA_CHANNEL_SOURCE:
3133                apr = 0;
3134                break;
3135        }
3136    } else {
3137        alphaMode = 0x10000;
3138        apr = 0;
3139    }
3140    final boolean ditherEnabled = (op & BLIT_DITHER) != 0;
3141
3142    /*** Comprehensive blit (apply transformations) ***/
3143    final int srcRedShift = getChannelShift(srcRedMask);
3144    final byte[] srcReds = ANY_TO_EIGHT[getChannelWidth(srcRedMask, srcRedShift)];
3145    final int srcGreenShift = getChannelShift(srcGreenMask);
3146    final byte[] srcGreens = ANY_TO_EIGHT[getChannelWidth(srcGreenMask, srcGreenShift)];
3147    final int srcBlueShift = getChannelShift(srcBlueMask);
3148    final byte[] srcBlues = ANY_TO_EIGHT[getChannelWidth(srcBlueMask, srcBlueShift)];
3149    final int srcAlphaShift = getChannelShift(srcAlphaMask);
3150    final byte[] srcAlphas = ANY_TO_EIGHT[getChannelWidth(srcAlphaMask, srcAlphaShift)];
3151
3152    int dp = dpr;
3153    int sp = spr;
3154    int ap = apr, alpha = alphaMode;
3155    int r = 0, g = 0, b = 0, a = 0;
3156    int indexq = 0;
3157    int lastindex = 0, lastr = -1, lastg = -1, lastb = -1;
3158    final int[] rerr, gerr, berr;
3159    int destPaletteSize = 1 << destDepth;
3160    if ((destReds != null) && (destReds.length < destPaletteSize)) destPaletteSize = destReds.length;
3161    if (ditherEnabled) {
3162        rerr = new int[destWidth + 2];
3163        gerr = new int[destWidth + 2];
3164        berr = new int[destWidth + 2];
3165    } else {
3166        rerr = null; gerr = null; berr = null;
3167    }
3168    for (int dy = destHeight, sfy = sfyi; dy > 0; --dy,
3169            sp = spr += (sfy >>> 16) * srcStride,
3170            ap = apr += (sfy >>> 16) * alphaStride,
3171            sfy = (sfy & 0xffff) + sfyi,
3172            dp = dpr += dpryi) {
3173        int lrerr = 0, lgerr = 0, lberr = 0;
3174        for (int dx = destWidth, sfx = sfxi; dx > 0; --dx,
3175                dp += dprxi,
3176                sfx = (sfx & 0xffff) + sfxi) {
3177            /*** READ NEXT PIXEL ***/
3178            switch (stype) {
3179                case TYPE_GENERIC_8: {
3180                    final int data = srcData[sp] & 0xff;
3181                    sp += (sfx >>> 16);
3182                    r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
3183                    g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
3184                    b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
3185                    a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
3186                } break;
3187                case TYPE_GENERIC_16_MSB: {
3188                    final int data = ((srcData[sp] & 0xff) << 8) | (srcData[sp + 1] & 0xff);
3189                    sp += (sfx >>> 16) * 2;
3190                    r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
3191                    g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
3192                    b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
3193                    a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
3194                } break;
3195                case TYPE_GENERIC_16_LSB: {
3196                    final int data = ((srcData[sp + 1] & 0xff) << 8) | (srcData[sp] & 0xff);
3197                    sp += (sfx >>> 16) * 2;
3198                    r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
3199                    g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
3200                    b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
3201                    a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
3202                } break;
3203                case TYPE_GENERIC_24: {
3204                    final int data = (( ((srcData[sp] & 0xff) << 8) |
3205                        (srcData[sp + 1] & 0xff)) << 8) |
3206                        (srcData[sp + 2] & 0xff);
3207                    sp += (sfx >>> 16) * 3;
3208                    r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
3209                    g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
3210                    b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
3211                    a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
3212                } break;
3213                case TYPE_GENERIC_32_MSB: {
3214                    final int data = (( (( ((srcData[sp] & 0xff) << 8) |
3215                        (srcData[sp + 1] & 0xff)) << 8) |
3216                        (srcData[sp + 2] & 0xff)) << 8) |
3217                        (srcData[sp + 3] & 0xff);
3218                    sp += (sfx >>> 16) * 4;
3219                    r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
3220                    g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
3221                    b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
3222                    a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
3223                } break;
3224                case TYPE_GENERIC_32_LSB: {
3225                    final int data = (( (( ((srcData[sp + 3] & 0xff) << 8) |
3226                        (srcData[sp + 2] & 0xff)) << 8) |
3227                        (srcData[sp + 1] & 0xff)) << 8) |
3228                        (srcData[sp] & 0xff);
3229                    sp += (sfx >>> 16) * 4;
3230                    r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
3231                    g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
3232                    b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
3233                    a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
3234                } break;
3235            }
3236
3237            /*** DO SPECIAL PROCESSING IF REQUIRED ***/
3238            switch (alphaMode) {
3239                case ALPHA_CHANNEL_SEPARATE:
3240                    alpha = ((alphaData[ap] & 0xff) << 16) / 255;
3241                    ap += (sfx >> 16);
3242                    break;
3243                case ALPHA_CHANNEL_SOURCE:
3244                    alpha = (a << 16) / 255;
3245                    break;
3246                case ALPHA_MASK_UNPACKED:
3247                    alpha = (alphaData[ap] != 0) ? 0x10000 : 0;
3248                    ap += (sfx >> 16);
3249                    break;
3250                case ALPHA_MASK_PACKED:
3251                    alpha = (alphaData[ap >> 3] << ((ap & 7) + 9)) & 0x10000;
3252                    ap += (sfx >> 16);
3253                    break;
3254                case ALPHA_MASK_RGB:
3255                    alpha = 0x10000;
3256                    for (int i = 0; i < alphaData.length; i += 3) {
3257                        if ((r == alphaData[i]) && (g == alphaData[i + 1]) && (b == alphaData[i + 2])) {
3258                            alpha = 0x0000;
3259                            break;
3260                        }
3261                    }
3262                    break;
3263            }
3264            if (alpha != 0x10000) {
3265                if (alpha == 0x0000) continue;
3266                switch (dtype) {
3267                    case TYPE_INDEX_8:
3268                        indexq = destData[dp] & 0xff;
3269                        break;
3270                    case TYPE_INDEX_4:
3271                        if ((dp & 1) != 0) indexq = destData[dp >> 1] & 0x0f;
3272                        else indexq = (destData[dp >> 1] >>> 4) & 0x0f;
3273                        break;
3274                    case TYPE_INDEX_2:
3275                        indexq = (destData[dp >> 2] >>> (6 - (dp & 3) * 2)) & 0x03;
3276                        break;
3277                    case TYPE_INDEX_1_MSB:
3278                        indexq = (destData[dp >> 3] >>> (7 - (dp & 7))) & 0x01;
3279                        break;
3280                    case TYPE_INDEX_1_LSB:
3281                        indexq = (destData[dp >> 3] >>> (dp & 7)) & 0x01;
3282                        break;
3283                }
3284                // Perform alpha blending
3285
final int rq = destReds[indexq] & 0xff;
3286                final int gq = destGreens[indexq] & 0xff;
3287                final int bq = destBlues[indexq] & 0xff;
3288                r = rq + ((r - rq) * alpha >> 16);
3289                g = gq + ((g - gq) * alpha >> 16);
3290                b = bq + ((b - bq) * alpha >> 16);
3291            }
3292
3293            /*** MAP COLOR TO THE PALETTE ***/
3294            if (ditherEnabled) {
3295                // Floyd-Steinberg error diffusion
3296
r += rerr[dx] >> 4;
3297                if (r < 0) r = 0; else if (r > 255) r = 255;
3298                g += gerr[dx] >> 4;
3299                if (g < 0) g = 0; else if (g > 255) g = 255;
3300                b += berr[dx] >> 4;
3301                if (b < 0) b = 0; else if (b > 255) b = 255;
3302                rerr[dx] = lrerr;
3303                gerr[dx] = lgerr;
3304                berr[dx] = lberr;
3305            }
3306            if (r != lastr || g != lastg || b != lastb) {
3307                // moving the variable declarations out seems to make the JDK JIT happier...
3308
for (int j = 0, dr, dg, db, distance, minDistance = 0x7fffffff; j < destPaletteSize; ++j) {
3309                    dr = (destReds[j] & 0xff) - r;
3310                    dg = (destGreens[j] & 0xff) - g;
3311                    db = (destBlues[j] & 0xff) - b;
3312                    distance = dr * dr + dg * dg + db * db;
3313                    if (distance < minDistance) {
3314                        lastindex = j;
3315                        if (distance == 0) break;
3316                        minDistance = distance;
3317                    }
3318                }
3319                lastr = r; lastg = g; lastb = b;
3320            }
3321            if (ditherEnabled) {
3322                // Floyd-Steinberg error diffusion, cont'd...
3323
final int dxm1 = dx - 1, dxp1 = dx + 1;
3324                int acc;
3325                rerr[dxp1] += acc = (lrerr = r - (destReds[lastindex] & 0xff)) + lrerr + lrerr;
3326                rerr[dx] += acc += lrerr + lrerr;
3327                rerr[dxm1] += acc + lrerr + lrerr;
3328                gerr[dxp1] += acc = (lgerr = g - (destGreens[lastindex] & 0xff)) + lgerr + lgerr;
3329                gerr[dx] += acc += lgerr + lgerr;
3330                gerr[dxm1] += acc + lgerr + lgerr;
3331                berr[dxp1] += acc = (lberr = b - (destBlues[lastindex] & 0xff)) + lberr + lberr;
3332                berr[dx] += acc += lberr + lberr;
3333                berr[dxm1] += acc + lberr + lberr;
3334            }
3335
3336            /*** WRITE NEXT PIXEL ***/
3337            switch (dtype) {
3338                case TYPE_INDEX_8:
3339                    destData[dp] = (byte) lastindex;
3340                    break;
3341                case TYPE_INDEX_4:
3342                    if ((dp & 1) != 0) destData[dp >> 1] = (byte)((destData[dp >> 1] & 0xf0) | lastindex);
3343                    else destData[dp >> 1] = (byte)((destData[dp >> 1] & 0x0f) | (lastindex << 4));
3344                    break;
3345                case TYPE_INDEX_2: {
3346                    final int shift = 6 - (dp & 3) * 2;
3347                    destData[dp >> 2] = (byte)(destData[dp >> 2] & ~(0x03 << shift) | (lastindex << shift));
3348                } break;
3349                case TYPE_INDEX_1_MSB: {
3350                    final int shift = 7 - (dp & 7);
3351                    destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (lastindex << shift));
3352                } break;
3353                case TYPE_INDEX_1_LSB: {
3354                    final int shift = dp & 7;
3355                    destData[dp >> 3] = (byte)(destData[dp >> 3] & ~(0x01 << shift) | (lastindex << shift));
3356                } break;
3357            }
3358        }
3359    }
3360}
3361
3362/**
3363 * Computes the required channel shift from a mask.
3364 */

3365static int getChannelShift(int mask) {
3366    if (mask == 0) return 0;
3367    int i;
3368    for (i = 0; ((mask & 1) == 0) && (i < 32); ++i) {
3369        mask >>>= 1;
3370    }
3371    return i;
3372}
3373
3374/**
3375 * Computes the required channel width (depth) from a mask.
3376 */

3377static int getChannelWidth(int mask, int shift) {
3378    if (mask == 0) return 0;
3379    int i;
3380    mask >>>= shift;
3381    for (i = shift; ((mask & 1) != 0) && (i < 32); ++i) {
3382        mask >>>= 1;
3383    }
3384    return i - shift;
3385}
3386
3387/**
3388 * Extracts a field from packed RGB data given a mask for that field.
3389 */

3390static byte getChannelField(int data, int mask) {
3391    final int shift = getChannelShift(mask);
3392    return ANY_TO_EIGHT[getChannelWidth(mask, shift)][(data & mask) >>> shift];
3393}
3394
3395/**
3396 * Creates an ImageData containing one band's worth of a gradient filled
3397 * block. If <code>vertical</code> is true, the band must be tiled
3398 * horizontally to fill a region, otherwise it must be tiled vertically.
3399 *
3400 * @param width the width of the region to be filled
3401 * @param height the height of the region to be filled
3402 * @param vertical if true sweeps from top to bottom, else
3403 * sweeps from left to right
3404 * @param fromRGB the color to start with
3405 * @param toRGB the color to end with
3406 * @param redBits the number of significant red bits, 0 for palette modes
3407 * @param greenBits the number of significant green bits, 0 for palette modes
3408 * @param blueBits the number of significant blue bits, 0 for palette modes
3409 * @return the new ImageData
3410 */

3411static ImageData createGradientBand(
3412    int width, int height, boolean vertical,
3413    RGB fromRGB, RGB toRGB,
3414    int redBits, int greenBits, int blueBits) {
3415    /* Gradients are drawn as tiled bands */
3416    final int bandWidth, bandHeight, bitmapDepth;
3417    final byte[] bitmapData;
3418    final PaletteData paletteData;
3419    /* Select an algorithm depending on the depth of the screen */
3420    if (redBits != 0 && greenBits != 0 && blueBits != 0) {
3421        paletteData = new PaletteData(0x0000ff00, 0x00ff0000, 0xff000000);
3422        bitmapDepth = 32;
3423        if (redBits >= 8 && greenBits >= 8 && blueBits >= 8) {
3424            /* Precise color */
3425            final int steps;
3426            if (vertical) {
3427                bandWidth = 1;
3428                bandHeight = height;
3429                steps = bandHeight > 1 ? bandHeight - 1 : 1;
3430            } else {
3431                bandWidth = width;
3432                bandHeight = 1;
3433                steps = bandWidth > 1 ? bandWidth - 1 : 1;
3434            }
3435            final int bytesPerLine = bandWidth * 4;
3436            bitmapData = new byte[bandHeight * bytesPerLine];
3437            buildPreciseGradientChannel(fromRGB.blue, toRGB.blue, steps, bandWidth, bandHeight, vertical, bitmapData, 0, bytesPerLine);
3438            buildPreciseGradientChannel(fromRGB.green, toRGB.green, steps, bandWidth, bandHeight, vertical, bitmapData, 1, bytesPerLine);
3439            buildPreciseGradientChannel(fromRGB.red, toRGB.red, steps, bandWidth, bandHeight, vertical, bitmapData, 2, bytesPerLine);
3440        } else {
3441            /* Dithered color */
3442            final int steps;
3443            if (vertical) {
3444                bandWidth = (width < 8) ? width : 8;
3445                bandHeight = height;
3446                steps = bandHeight > 1 ? bandHeight - 1 : 1;
3447            } else {
3448                bandWidth = width;
3449                bandHeight = (height < 8) ? height : 8;
3450                steps = bandWidth > 1 ? bandWidth - 1 : 1;
3451            }
3452            final int bytesPerLine = bandWidth * 4;
3453            bitmapData = new byte[bandHeight * bytesPerLine];
3454            buildDitheredGradientChannel(fromRGB.blue, toRGB.blue, steps, bandWidth, bandHeight, vertical, bitmapData, 0, bytesPerLine, blueBits);
3455            buildDitheredGradientChannel(fromRGB.green, toRGB.green, steps, bandWidth, bandHeight, vertical, bitmapData, 1, bytesPerLine, greenBits);
3456            buildDitheredGradientChannel(fromRGB.red, toRGB.red, steps, bandWidth, bandHeight, vertical, bitmapData, 2, bytesPerLine, redBits);
3457        }
3458    } else {
3459        /* Dithered two tone */
3460        paletteData = new PaletteData(new RGB[] { fromRGB, toRGB });
3461        bitmapDepth = 8;
3462        final int blendi;
3463        if (vertical) {
3464            bandWidth = (width < 8) ? width : 8;
3465            bandHeight = height;
3466            blendi = (bandHeight > 1) ? 0x1040000 / (bandHeight - 1) + 1 : 1;
3467        } else {
3468            bandWidth = width;
3469            bandHeight = (height < 8) ? height : 8;
3470            blendi = (bandWidth > 1) ? 0x1040000 / (bandWidth - 1) + 1 : 1;
3471        }
3472        final int bytesPerLine = (bandWidth + 3) & -4;
3473        bitmapData = new byte[bandHeight * bytesPerLine];
3474        if (vertical) {
3475            for (int dy = 0, blend = 0, dp = 0; dy < bandHeight;
3476                ++dy, blend += blendi, dp += bytesPerLine) {
3477                for (int dx = 0; dx < bandWidth; ++dx) {
3478                    bitmapData[dp + dx] = (blend + DITHER_MATRIX[dy & 7][dx]) <
3479                        0x1000000 ? (byte)0 : (byte)1;
3480                }
3481            }
3482        } else {
3483            for (int dx = 0, blend = 0; dx < bandWidth; ++dx, blend += blendi) {
3484                for (int dy = 0, dptr = dx; dy < bandHeight; ++dy, dptr += bytesPerLine) {
3485                    bitmapData[dptr] = (blend + DITHER_MATRIX[dy][dx & 7]) <
3486                        0x1000000 ? (byte)0 : (byte)1;
3487                }
3488            }
3489        }
3490    }
3491    return new ImageData(bandWidth, bandHeight, bitmapDepth, paletteData, 4, bitmapData);
3492}
3493
3494/*
3495 * Fill in gradated values for a color channel
3496 */

3497static final void buildPreciseGradientChannel(int from, int to, int steps,
3498    int bandWidth, int bandHeight, boolean vertical,
3499    byte[] bitmapData, int dp, int bytesPerLine) {
3500    int val = from << 16;
3501    final int inc = ((to << 16) - val) / steps + 1;
3502    if (vertical) {
3503        for (int dy = 0; dy < bandHeight; ++dy, dp += bytesPerLine) {
3504            bitmapData[dp] = (byte)(val >>> 16);
3505            val += inc;
3506        }
3507    } else {
3508        for (int dx = 0; dx < bandWidth; ++dx, dp += 4) {
3509            bitmapData[dp] = (byte)(val >>> 16);
3510            val += inc;
3511        }
3512    }
3513}
3514
3515/*
3516 * Fill in dithered gradated values for a color channel
3517 */

3518static final void buildDitheredGradientChannel(int from, int to, int steps,
3519    int bandWidth, int bandHeight, boolean vertical,
3520    byte[] bitmapData, int dp, int bytesPerLine, int bits) {
3521    final int mask = 0xff00 >>> bits;
3522    int val = from << 16;
3523    final int inc = ((to << 16) - val) / steps + 1;
3524    if (vertical) {
3525        for (int dy = 0; dy < bandHeight; ++dy, dp += bytesPerLine) {
3526            for (int dx = 0, dptr = dp; dx < bandWidth; ++dx, dptr += 4) {
3527                final int thresh = DITHER_MATRIX[dy & 7][dx] >>> bits;
3528                int temp = val + thresh;
3529                if (temp > 0xffffff) bitmapData[dptr] = -1;
3530                else bitmapData[dptr] = (byte)((temp >>> 16) & mask);
3531            }
3532            val += inc;
3533        }
3534    } else {
3535        for (int dx = 0; dx < bandWidth; ++dx, dp += 4) {
3536            for (int dy = 0, dptr = dp; dy < bandHeight; ++dy, dptr += bytesPerLine) {
3537                final int thresh = DITHER_MATRIX[dy][dx & 7] >>> bits;
3538                int temp = val + thresh;
3539                if (temp > 0xffffff) bitmapData[dptr] = -1;
3540                else bitmapData[dptr] = (byte)((temp >>> 16) & mask);
3541            }
3542            val += inc;
3543        }
3544    }
3545}
3546
3547/**
3548 * Renders a gradient onto a GC.
3549 * <p>
3550 * This is a GC helper.
3551 * </p>
3552 *
3553 * @param gc the GC to render the gradient onto
3554 * @param device the device the GC belongs to
3555 * @param x the top-left x coordinate of the region to be filled
3556 * @param y the top-left y coordinate of the region to be filled
3557 * @param width the width of the region to be filled
3558 * @param height the height of the region to be filled
3559 * @param vertical if true sweeps from top to bottom, else
3560 * sweeps from left to right
3561 * @param fromRGB the color to start with
3562 * @param toRGB the color to end with
3563 * @param redBits the number of significant red bits, 0 for palette modes
3564 * @param greenBits the number of significant green bits, 0 for palette modes
3565 * @param blueBits the number of significant blue bits, 0 for palette modes
3566 */

3567static void fillGradientRectangle(GC gc, Device device,
3568    int x, int y, int width, int height, boolean vertical,
3569    RGB fromRGB, RGB toRGB,
3570    int redBits, int greenBits, int blueBits) {
3571    /* Create the bitmap and tile it */
3572    ImageData band = createGradientBand(width, height, vertical,
3573        fromRGB, toRGB, redBits, greenBits, blueBits);
3574    Image image = new Image(device, band);
3575    if ((band.width == 1) || (band.height == 1)) {
3576        gc.drawImage(image, 0, 0, band.width, band.height, x, y, width, height);
3577    } else {
3578        if (vertical) {
3579            for (int dx = 0; dx < width; dx += band.width) {
3580                int blitWidth = width - dx;
3581                if (blitWidth > band.width) blitWidth = band.width;
3582                gc.drawImage(image, 0, 0, blitWidth, band.height, dx + x, y, blitWidth, band.height);
3583            }
3584        } else {
3585            for (int dy = 0; dy < height; dy += band.height) {
3586                int blitHeight = height - dy;
3587                if (blitHeight > band.height) blitHeight = band.height;
3588                gc.drawImage(image, 0, 0, band.width, blitHeight, x, dy + y, band.width, blitHeight);
3589            }
3590        }
3591    }
3592    image.dispose();
3593}
3594
3595}
3596
Popular Tags