1 /*******************************************************************************
2  * Copyright (c) 2000, 2008 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  * Port to the D programming language:
11  *     Frank Benoit <benoit@tionex.de>
12  *******************************************************************************/
13 module org.eclipse.swt.graphics.ImageData;
14 
15 
16 import org.eclipse.swt.graphics.PaletteData;
17 import org.eclipse.swt.graphics.RGB;
18 import org.eclipse.swt.graphics.Image;
19 import org.eclipse.swt.graphics.GC;
20 import org.eclipse.swt.graphics.Device;
21 import org.eclipse.swt.graphics.ImageDataLoader;
22 import org.eclipse.swt.SWT;
23 import org.eclipse.swt.internal.CloneableCompatibility;
24 import java.lang.all;
25 
26 public import java.io.InputStream;
27 
28 
29 /**
30  * Instances of this class are device-independent descriptions
31  * of images. They are typically used as an intermediate format
32  * between loading from or writing to streams and creating an
33  * <code>Image</code>.
34  * <p>
35  * Note that the public fields <code>x</code>, <code>y</code>,
36  * <code>disposalMethod</code> and <code>delayTime</code> are
37  * typically only used when the image is in a set of images used
38  * for animation.
39  * </p>
40  *
41  * @see Image
42  * @see ImageLoader
43  * @see <a href="http://www.eclipse.org/swt/snippets/#image">ImageData snippets</a>
44  * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ImageAnalyzer</a>
45  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
46  */
47 
48 public final class ImageData : CloneableCompatibility {
49 
50     /**
51      * The width of the image, in pixels.
52      */
53     public int width;
54 
55     /**
56      * The height of the image, in pixels.
57      */
58     public int height;
59 
60     /**
61      * The color depth of the image, in bits per pixel.
62      * <p>
63      * Note that a depth of 8 or less does not necessarily
64      * mean that the image is palette indexed, or
65      * conversely that a depth greater than 8 means that
66      * the image is direct color.  Check the associated
67      * PaletteData's isDirect field for such determinations.
68      */
69     public int depth;
70 
71     /**
72      * The scanline padding.
73      * <p>
74      * If one scanline of the image is not a multiple of
75      * this number, it will be padded with zeros until it is.
76      * </p>
77      */
78     public int scanlinePad;
79 
80     /**
81      * The number of bytes per scanline.
82      * <p>
83      * This is a multiple of the scanline padding.
84      * </p>
85      */
86     public int bytesPerLine;
87 
88     /**
89      * The pixel data of the image.
90      * <p>
91      * Note that for 16 bit depth images the pixel data is stored
92      * in least significant byte order; however, for 24bit and
93      * 32bit depth images the pixel data is stored in most
94      * significant byte order.
95      * </p>
96      */
97     public byte[] data;
98 
99     /**
100      * The color table for the image.
101      */
102     public PaletteData palette;
103 
104     /**
105      * The transparent pixel.
106      * <p>
107      * Pixels with this value are transparent.
108      * </p><p>
109      * The default is -1 which means 'no transparent pixel'.
110      * </p>
111      */
112     public int transparentPixel;
113 
114     /**
115      * An icon-specific field containing the data from the icon mask.
116      * <p>
117      * This is a 1 bit bitmap stored with the most significant
118      * bit first.  The number of bytes per scanline is
119      * '((width + 7) / 8 + (maskPad - 1)) / maskPad * maskPad'.
120      * </p><p>
121      * The default is null which means 'no transparency mask'.
122      * </p>
123      */
124     public byte[] maskData;
125 
126     /**
127      * An icon-specific field containing the scanline pad of the mask.
128      * <p>
129      * If one scanline of the transparency mask is not a
130      * multiple of this number, it will be padded with zeros until
131      * it is.
132      * </p>
133      */
134     public int maskPad;
135 
136     /**
137      * The alpha data of the image.
138      * <p>
139      * Every pixel can have an <em>alpha blending</em> value that
140      * varies from 0, meaning fully transparent, to 255 meaning
141      * fully opaque.  The number of bytes per scanline is
142      * 'width'.
143      * </p>
144      */
145     public byte[] alphaData;
146 
147     /**
148      * The global alpha value to be used for every pixel.
149      * <p>
150      * If this value is set, the <code>alphaData</code> field
151      * is ignored and when the image is rendered each pixel
152      * will be blended with the background an amount
153      * proportional to this value.
154      * </p><p>
155      * The default is -1 which means 'no global alpha value'
156      * </p>
157      */
158     public int alpha;
159 
160     /**
161      * The type of file from which the image was read.
162      *
163      * It is expressed as one of the following values:
164      * <dl>
165      * <dt><code>IMAGE_BMP</code></dt>
166      * <dd>Windows BMP file format, no compression</dd>
167      * <dt><code>IMAGE_BMP_RLE</code></dt>
168      * <dd>Windows BMP file format, RLE compression if appropriate</dd>
169      * <dt><code>IMAGE_GIF</code></dt>
170      * <dd>GIF file format</dd>
171      * <dt><code>IMAGE_ICO</code></dt>
172      * <dd>Windows ICO file format</dd>
173      * <dt><code>IMAGE_JPEG</code></dt>
174      * <dd>JPEG file format</dd>
175      * <dt><code>IMAGE_PNG</code></dt>
176      * <dd>PNG file format</dd>
177      * </dl>
178      */
179     public int type;
180 
181     /**
182      * The x coordinate of the top left corner of the image
183      * within the logical screen (this field corresponds to
184      * the GIF89a Image Left Position value).
185      */
186     public int x;
187 
188     /**
189      * The y coordinate of the top left corner of the image
190      * within the logical screen (this field corresponds to
191      * the GIF89a Image Top Position value).
192      */
193     public int y;
194 
195     /**
196      * A description of how to dispose of the current image
197      * before displaying the next.
198      *
199      * It is expressed as one of the following values:
200      * <dl>
201      * <dt><code>DM_UNSPECIFIED</code></dt>
202      * <dd>disposal method not specified</dd>
203      * <dt><code>DM_FILL_NONE</code></dt>
204      * <dd>do nothing - leave the image in place</dd>
205      * <dt><code>DM_FILL_BACKGROUND</code></dt>
206      * <dd>fill with the background color</dd>
207      * <dt><code>DM_FILL_PREVIOUS</code></dt>
208      * <dd>restore the previous picture</dd>
209      * </dl>
210      * (this field corresponds to the GIF89a Disposal Method value)
211      */
212     public int disposalMethod;
213 
214     /**
215      * The time to delay before displaying the next image
216      * in an animation (this field corresponds to the GIF89a
217      * Delay Time value).
218      */
219     public int delayTime;
220 
221     /**
222      * Arbitrary channel width data to 8-bit conversion table.
223      */
224     private static byte[][] ANY_TO_EIGHT;
225     private static byte[] ONE_TO_ONE_MAPPING;
226 
227     private static bool static_this_completed = false;
228     private static void static_this() {
229         if( static_this_completed ) return;
230         synchronized {
231             if( static_this_completed ) return;
232             ANY_TO_EIGHT = new byte[][](9);
233             for (int b = 0; b < 9; ++b) {
234                 byte[] data = ANY_TO_EIGHT[b] = new byte[1 << b];
235                 if (b is 0) continue;
236                 int inc = 0;
237                 for (int bit = 0x10000; (bit >>= b) !is 0;) inc |= bit;
238                 for (int v = 0, p = 0; v < 0x10000; v+= inc) data[p++] = cast(byte)(v >> 8);
239             }
240             ONE_TO_ONE_MAPPING = ANY_TO_EIGHT[8];
241             static_this_completed = true;
242         }
243     }
244 
245     /**
246      * Scaled 8x8 Bayer dither matrix.
247      */
248     static const int[][] DITHER_MATRIX = [
249         [ 0xfc0000, 0x7c0000, 0xdc0000, 0x5c0000, 0xf40000, 0x740000, 0xd40000, 0x540000 ],
250         [ 0x3c0000, 0xbc0000, 0x1c0000, 0x9c0000, 0x340000, 0xb40000, 0x140000, 0x940000 ],
251         [ 0xcc0000, 0x4c0000, 0xec0000, 0x6c0000, 0xc40000, 0x440000, 0xe40000, 0x640000 ],
252         [ 0x0c0000, 0x8c0000, 0x2c0000, 0xac0000, 0x040000, 0x840000, 0x240000, 0xa40000 ],
253         [ 0xf00000, 0x700000, 0xd00000, 0x500000, 0xf80000, 0x780000, 0xd80000, 0x580000 ],
254         [ 0x300000, 0xb00000, 0x100000, 0x900000, 0x380000, 0xb80000, 0x180000, 0x980000 ],
255         [ 0xc00000, 0x400000, 0xe00000, 0x600000, 0xc80000, 0x480000, 0xe80000, 0x680000 ],
256         [ 0x000000, 0x800000, 0x200000, 0xa00000, 0x080000, 0x880000, 0x280000, 0xa80000 ]
257     ];
258 
259 /**
260  * Constructs a new, empty ImageData with the given width, height,
261  * depth and palette. The data will be initialized to an (all zero)
262  * array of the appropriate size.
263  *
264  * @param width the width of the image
265  * @param height the height of the image
266  * @param depth the depth of the image
267  * @param palette the palette of the image (must not be null)
268  *
269  * @exception IllegalArgumentException <ul>
270  *    <li>ERROR_INVALID_ARGUMENT - if the width or height is negative, or if the depth is not
271  *          one of 1, 2, 4, 8, 16, 24 or 32</li>
272  *    <li>ERROR_NULL_ARGUMENT - if the palette is null</li>
273  * </ul>
274  */
275 public this(int width, int height, int depth, PaletteData palette) {
276     this(width, height, depth, palette,
277         4, null, 0, null,
278         null, -1, -1, SWT.IMAGE_UNDEFINED,
279         0, 0, 0, 0);
280 }
281 
282 /**
283  * Constructs a new, empty ImageData with the given width, height,
284  * depth, palette, scanlinePad and data.
285  *
286  * @param width the width of the image
287  * @param height the height of the image
288  * @param depth the depth of the image
289  * @param palette the palette of the image
290  * @param scanlinePad the padding of each line, in bytes
291  * @param data the data of the image
292  *
293  * @exception IllegalArgumentException <ul>
294  *    <li>ERROR_INVALID_ARGUMENT - if the width or height is negative, or if the depth is not
295  *          one of 1, 2, 4, 8, 16, 24 or 32, or the data array is too small to contain the image data</li>
296  *    <li>ERROR_NULL_ARGUMENT - if the palette or data is null</li>
297  *    <li>ERROR_CANNOT_BE_ZERO - if the scanlinePad is zero</li>
298  * </ul>
299  */
300 public this(int width, int height, int depth, PaletteData palette, int scanlinePad, byte[] data) {
301     this(width, height, depth, palette,
302         scanlinePad, checkData(data), 0, null,
303         null, -1, -1, SWT.IMAGE_UNDEFINED,
304         0, 0, 0, 0);
305 }
306 
307 /**
308  * Constructs an <code>ImageData</code> loaded from the specified
309  * input stream. Throws an error if an error occurs while loading
310  * the image, or if the image has an unsupported type.  Application
311  * code is still responsible for closing the input stream.
312  * <p>
313  * This constructor is provided for convenience when loading a single
314  * image only. If the stream contains multiple images, only the first
315  * one will be loaded. To load multiple images, use
316  * <code>ImageLoader.load()</code>.
317  * </p><p>
318  * This constructor may be used to load a resource as follows:
319  * </p>
320  * <pre>
321  *     static ImageData loadImageData (Class clazz, String string) {
322  *          InputStream stream = clazz.getResourceAsStream (string);
323  *          if (stream is null) return null;
324  *          ImageData imageData = null;
325  *          try {
326  *               imageData = new ImageData (stream);
327  *          } catch (SWTException ex) {
328  *          } finally {
329  *               try {
330  *                    stream.close ();
331  *               } catch (IOException ex) {}
332  *          }
333  *          return imageData;
334  *     }
335  * </pre>
336  *
337  * @param stream the input stream to load the image from (must not be null)
338  *
339  * @exception IllegalArgumentException <ul>
340  *    <li>ERROR_NULL_ARGUMENT - if the stream is null</li>
341  * </ul>
342  * @exception SWTException <ul>
343  *    <li>ERROR_IO - if an IO error occurs while reading from the stream</li>
344  *    <li>ERROR_INVALID_IMAGE - if the image stream contains invalid data</li>
345  *    <li>ERROR_UNSUPPORTED_FORMAT - if the image stream contains an unrecognized format</li>
346  * </ul>
347  *
348  * @see ImageLoader#load(InputStream)
349  */
350 public this(InputStream stream) {
351     ImageData[] data = ImageDataLoader.load(stream);
352     if (data.length < 1) SWT.error(SWT.ERROR_INVALID_IMAGE);
353     ImageData i = data[0];
354     setAllFields(
355         i.width,
356         i.height,
357         i.depth,
358         i.scanlinePad,
359         i.bytesPerLine,
360         i.data,
361         i.palette,
362         i.transparentPixel,
363         i.maskData,
364         i.maskPad,
365         i.alphaData,
366         i.alpha,
367         i.type,
368         i.x,
369         i.y,
370         i.disposalMethod,
371         i.delayTime);
372 }
373 
374 /**
375  * Constructs an <code>ImageData</code> loaded from a file with the
376  * specified name. Throws an error if an error occurs loading the
377  * image, or if the image has an unsupported type.
378  * <p>
379  * This constructor is provided for convenience when loading a single
380  * image only. If the file contains multiple images, only the first
381  * one will be loaded. To load multiple images, use
382  * <code>ImageLoader.load()</code>.
383  * </p>
384  *
385  * @param filename the name of the file to load the image from (must not be null)
386  *
387  * @exception IllegalArgumentException <ul>
388  *    <li>ERROR_NULL_ARGUMENT - if the file name is null</li>
389  * </ul>
390  * @exception SWTException <ul>
391  *    <li>ERROR_IO - if an IO error occurs while reading from the file</li>
392  *    <li>ERROR_INVALID_IMAGE - if the image file contains invalid data</li>
393  *    <li>ERROR_UNSUPPORTED_FORMAT - if the image file contains an unrecognized format</li>
394  * </ul>
395  */
396 public this(String filename) {
397     ImageData[] data = ImageDataLoader.load(filename);
398     if (data.length < 1) SWT.error(SWT.ERROR_INVALID_IMAGE);
399     ImageData i = data[0];
400     setAllFields(
401         i.width,
402         i.height,
403         i.depth,
404         i.scanlinePad,
405         i.bytesPerLine,
406         i.data,
407         i.palette,
408         i.transparentPixel,
409         i.maskData,
410         i.maskPad,
411         i.alphaData,
412         i.alpha,
413         i.type,
414         i.x,
415         i.y,
416         i.disposalMethod,
417         i.delayTime);
418 }
419 
420 /**
421  * Prevents uninitialized instances from being created outside the package.
422  */
423 private this() {
424 }
425 
426 /**
427  * Constructs an image data by giving values for all non-computable fields.
428  * <p>
429  * This method is for internal use, and is not described further.
430  * </p>
431  */
432 this(
433     int width, int height, int depth, PaletteData palette,
434     int scanlinePad, byte[] data, int maskPad, byte[] maskData,
435     byte[] alphaData, int alpha, int transparentPixel, int type,
436     int x, int y, int disposalMethod, int delayTime)
437 {
438     if (palette is null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
439     if (!(depth is 1 || depth is 2 || depth is 4 || depth is 8
440         || depth is 16 || depth is 24 || depth is 32)) {
441         SWT.error(SWT.ERROR_INVALID_ARGUMENT);
442     }
443     if (width <= 0 || height <= 0) {
444         SWT.error(SWT.ERROR_INVALID_ARGUMENT);
445     }
446     if (scanlinePad is 0) SWT.error (SWT.ERROR_CANNOT_BE_ZERO);
447 
448     int bytesPerLine = (((width * depth + 7) / 8) + (scanlinePad - 1))
449         / scanlinePad * scanlinePad;
450 
451     /*
452      * When the image is being loaded from a PNG, we need to use the theoretical minimum
453      * number of bytes per line to check whether there is enough data, because the actual
454      * number of bytes per line is calculated based on the given depth, which may be larger
455      * than the actual depth of the PNG.
456      */
457     int minBytesPerLine = type is SWT.IMAGE_PNG ? ((((width + 7) / 8) + 3) / 4) * 4 : bytesPerLine;
458     if (data !is null && data.length < minBytesPerLine * height) {
459         SWT.error(SWT.ERROR_INVALID_ARGUMENT);
460     }
461     setAllFields(
462         width,
463         height,
464         depth,
465         scanlinePad,
466         bytesPerLine,
467         data !is null ? data : new byte[bytesPerLine * height],
468         palette,
469         transparentPixel,
470         maskData,
471         maskPad,
472         alphaData,
473         alpha,
474         type,
475         x,
476         y,
477         disposalMethod,
478         delayTime);
479 }
480 
481 /**
482  * Initializes all fields in the receiver. This method must be called
483  * by all public constructors to ensure that all fields are initialized
484  * for a new ImageData object. If a new field is added to the class,
485  * then it must be added to this method.
486  * <p>
487  * This method is for internal use, and is not described further.
488  * </p>
489  */
490 void setAllFields(int width, int height, int depth, int scanlinePad,
491     int bytesPerLine, byte[] data, PaletteData palette, int transparentPixel,
492     byte[] maskData, int maskPad, byte[] alphaData, int alpha,
493     int type, int x, int y, int disposalMethod, int delayTime) {
494 
495     this.width = width;
496     this.height = height;
497     this.depth = depth;
498     this.scanlinePad = scanlinePad;
499     this.bytesPerLine = bytesPerLine;
500     this.data = data;
501     this.palette = palette;
502     this.transparentPixel = transparentPixel;
503     this.maskData = maskData;
504     this.maskPad = maskPad;
505     this.alphaData = alphaData;
506     this.alpha = alpha;
507     this.type = type;
508     this.x = x;
509     this.y = y;
510     this.disposalMethod = disposalMethod;
511     this.delayTime = delayTime;
512 }
513 
514 /**
515  * Invokes internal SWT functionality to create a new instance of
516  * this class.
517  * <p>
518  * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
519  * API for <code>ImageData</code>. It is marked public only so that it
520  * can be shared within the packages provided by SWT. It is subject
521  * to change without notice, and should never be called from
522  * application code.
523  * </p>
524  * <p>
525  * This method is for internal use, and is not described further.
526  * </p>
527  */
528 public static ImageData internal_new(
529     int width, int height, int depth, PaletteData palette,
530     int scanlinePad, byte[] data, int maskPad, byte[] maskData,
531     byte[] alphaData, int alpha, int transparentPixel, int type,
532     int x, int y, int disposalMethod, int delayTime)
533 {
534     return new ImageData(
535         width, height, depth, palette, scanlinePad, data, maskPad, maskData,
536         alphaData, alpha, transparentPixel, type, x, y, disposalMethod, delayTime);
537 }
538 
539 ImageData colorMaskImage(int pixel) {
540     ImageData mask = new ImageData(width, height, 1, bwPalette(),
541         2, null, 0, null, null, -1, -1, SWT.IMAGE_UNDEFINED,
542         0, 0, 0, 0);
543     int[] row = new int[width];
544     for (int y = 0; y < height; y++) {
545         getPixels(0, y, width, row, 0);
546         for (int i = 0; i < width; i++) {
547             if (pixel !is -1 && row[i] is pixel) {
548                 row[i] = 0;
549             } else {
550                 row[i] = 1;
551             }
552         }
553         mask.setPixels(0, y, width, row, 0);
554     }
555     return mask;
556 }
557 
558 static byte[] checkData(byte [] data) {
559     if (data is null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
560     return data;
561 }
562 
563 /**
564  * Returns a new instance of the same class as the receiver,
565  * whose slots have been filled in with <em>copies</em> of
566  * the values in the slots of the receiver. That is, the
567  * returned object is a <em>deep copy</em> of the receiver.
568  *
569  * @return a copy of the receiver.
570  */
571 public Object clone() {
572     byte[] cloneData = new byte[data.length];
573     System.arraycopy(data, 0, cloneData, 0, data.length);
574     byte[] cloneMaskData = null;
575     if (maskData !is null) {
576         cloneMaskData = new byte[maskData.length];
577         System.arraycopy(maskData, 0, cloneMaskData, 0, maskData.length);
578     }
579     byte[] cloneAlphaData = null;
580     if (alphaData !is null) {
581         cloneAlphaData = new byte[alphaData.length];
582         System.arraycopy(alphaData, 0, cloneAlphaData, 0, alphaData.length);
583     }
584     return new ImageData(
585         width,
586         height,
587         depth,
588         palette,
589         scanlinePad,
590         cloneData,
591         maskPad,
592         cloneMaskData,
593         cloneAlphaData,
594         alpha,
595         transparentPixel,
596         type,
597         x,
598         y,
599         disposalMethod,
600         delayTime);
601 }
602 
603 /**
604  * Returns the alpha value at offset <code>x</code> in
605  * scanline <code>y</code> in the receiver's alpha data.
606  * The alpha value is between 0 (transparent) and
607  * 255 (opaque).
608  *
609  * @param x the x coordinate of the pixel to get the alpha value of
610  * @param y the y coordinate of the pixel to get the alpha value of
611  * @return the alpha value at the given coordinates
612  *
613  * @exception IllegalArgumentException <ul>
614  *    <li>ERROR_INVALID_ARGUMENT - if either argument is out of range</li>
615  * </ul>
616  */
617 public int getAlpha(int x, int y) {
618     if (x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
619 
620     if (alphaData is null) return 255;
621     return alphaData[y * width + x] & 0xFF;
622 }
623 
624 /**
625  * Returns <code>getWidth</code> alpha values starting at offset
626  * <code>x</code> in scanline <code>y</code> in the receiver's alpha
627  * data starting at <code>startIndex</code>. The alpha values
628  * are unsigned, between <code>(byte)0</code> (transparent) and
629  * <code>(byte)255</code> (opaque).
630  *
631  * @param x the x position of the pixel to begin getting alpha values
632  * @param y the y position of the pixel to begin getting alpha values
633  * @param getWidth the width of the data to get
634  * @param alphas the buffer in which to put the alpha values
635  * @param startIndex the offset into the image to begin getting alpha values
636  *
637  * @exception IndexOutOfBoundsException if getWidth is too large
638  * @exception IllegalArgumentException <ul>
639  *    <li>ERROR_NULL_ARGUMENT - if pixels is null</li>
640  *    <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
641  *    <li>ERROR_INVALID_ARGUMENT - if getWidth is negative</li>
642  * </ul>
643  */
644 public void getAlphas(int x, int y, int getWidth, byte[] alphas, int startIndex) {
645     if (alphas is null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
646     if (getWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
647     if (getWidth is 0) return;
648 
649     if (alphaData is null) {
650         int endIndex = startIndex + getWidth;
651         for (int i = startIndex; i < endIndex; i++) {
652             alphas[i] = cast(byte)255;
653         }
654         return;
655     }
656     // may throw an IndexOutOfBoundsException
657     System.arraycopy(alphaData, y * width + x, alphas, startIndex, getWidth);
658 }
659 
660 /**
661  * Returns the pixel value at offset <code>x</code> in
662  * scanline <code>y</code> in the receiver's data.
663  *
664  * @param x the x position of the pixel to get
665  * @param y the y position of the pixel to get
666  * @return the pixel at the given coordinates
667  *
668  * @exception IllegalArgumentException <ul>
669  *    <li>ERROR_INVALID_ARGUMENT - if either argument is out of bounds</li>
670  * </ul>
671  * @exception SWTException <ul>
672  *    <li>ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8, 16, 24 or 32</li>
673  * </ul>
674  */
675 public int getPixel(int x, int y) {
676     if (x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
677     int index;
678     int theByte;
679     int mask;
680     switch (depth) {
681         case 32:
682             index = (y * bytesPerLine) + (x * 4);
683             return ((data[index] & 0xFF) << 24) + ((data[index+1] & 0xFF) << 16) +
684                     ((data[index+2] & 0xFF) << 8) + (data[index+3] & 0xFF);
685         case 24:
686             index = (y * bytesPerLine) + (x * 3);
687             return ((data[index] & 0xFF) << 16) + ((data[index+1] & 0xFF) << 8) +
688                 (data[index+2] & 0xFF);
689         case 16:
690             index = (y * bytesPerLine) + (x * 2);
691             return ((data[index+1] & 0xFF) << 8) + (data[index] & 0xFF);
692         case 8:
693             index = (y * bytesPerLine) + x ;
694             return data[index] & 0xFF;
695         case 4:
696             index = (y * bytesPerLine) + (x >> 1);
697             theByte = data[index] & 0xFF;
698             if ((x & 0x1) is 0) {
699                 return theByte >> 4;
700             } else {
701                 return theByte & 0x0F;
702             }
703         case 2:
704             index = (y * bytesPerLine) + (x >> 2);
705             theByte = data[index] & 0xFF;
706             int offset = 3 - (x % 4);
707             mask = 3 << (offset * 2);
708             return (theByte & mask) >> (offset * 2);
709         case 1:
710             index = (y * bytesPerLine) + (x >> 3);
711             theByte = data[index] & 0xFF;
712             mask = 1 << (7 - (x & 0x7));
713             if ((theByte & mask) is 0) {
714                 return 0;
715             } else {
716                 return 1;
717             }
718         default:
719     }
720     SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
721     return 0;
722 }
723 
724 /**
725  * Returns <code>getWidth</code> pixel values starting at offset
726  * <code>x</code> in scanline <code>y</code> in the receiver's
727  * data starting at <code>startIndex</code>.
728  *
729  * @param x the x position of the first pixel to get
730  * @param y the y position of the first pixel to get
731  * @param getWidth the width of the data to get
732  * @param pixels the buffer in which to put the pixels
733  * @param startIndex the offset into the byte array to begin storing pixels
734  *
735  * @exception IndexOutOfBoundsException if getWidth is too large
736  * @exception IllegalArgumentException <ul>
737  *    <li>ERROR_NULL_ARGUMENT - if pixels is null</li>
738  *    <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
739  *    <li>ERROR_INVALID_ARGUMENT - if getWidth is negative</li>
740  * </ul>
741  * @exception SWTException <ul>
742  *    <li>ERROR_UNSUPPORTED_DEPTH - if the depth is not one of 1, 2, 4 or 8
743  *        (For higher depths, use the int[] version of this method.)</li>
744  * </ul>
745  */
746 public void getPixels(int x, int y, int getWidth, byte[] pixels, int startIndex) {
747     if (pixels is null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
748     if (getWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
749     if (getWidth is 0) return;
750     int index;
751     int theByte;
752     int mask = 0;
753     int n = getWidth;
754     int i = startIndex;
755     int srcX = x, srcY = y;
756     switch (depth) {
757         case 8:
758             index = (y * bytesPerLine) + x;
759             for (int j = 0; j < getWidth; j++) {
760                 pixels[i] = data[index];
761                 i++;
762                 srcX++;
763                 if (srcX >= width) {
764                     srcY++;
765                     index = srcY * bytesPerLine;
766                     srcX = 0;
767                 } else {
768                     index++;
769                 }
770             }
771             return;
772         case 4:
773             index = (y * bytesPerLine) + (x >> 1);
774             if ((x & 0x1) is 1) {
775                 theByte = data[index] & 0xFF;
776                 pixels[i] = cast(byte)(theByte & 0x0F);
777                 i++;
778                 n--;
779                 srcX++;
780                 if (srcX >= width) {
781                     srcY++;
782                     index = srcY * bytesPerLine;
783                     srcX = 0;
784                 } else {
785                     index++;
786                 }
787             }
788             while (n > 1) {
789                 theByte = data[index] & 0xFF;
790                 pixels[i] = cast(byte)(theByte >> 4);
791                 i++;
792                 n--;
793                 srcX++;
794                 if (srcX >= width) {
795                     srcY++;
796                     index = srcY * bytesPerLine;
797                     srcX = 0;
798                 } else {
799                     pixels[i] = cast(byte)(theByte & 0x0F);
800                     i++;
801                     n--;
802                     srcX++;
803                     if (srcX >= width) {
804                         srcY++;
805                         index = srcY * bytesPerLine;
806                         srcX = 0;
807                     } else {
808                         index++;
809                     }
810                 }
811             }
812             if (n > 0) {
813                 theByte = data[index] & 0xFF;
814                 pixels[i] = cast(byte)(theByte >> 4);
815             }
816             return;
817         case 2:
818             index = (y * bytesPerLine) + (x >> 2);
819             theByte = data[index] & 0xFF;
820             int offset;
821             while (n > 0) {
822                 offset = 3 - (srcX % 4);
823                 mask = 3 << (offset * 2);
824                 pixels[i] = cast(byte)((theByte & mask) >> (offset * 2));
825                 i++;
826                 n--;
827                 srcX++;
828                 if (srcX >= width) {
829                     srcY++;
830                     index = srcY * bytesPerLine;
831                     if (n > 0) theByte = data[index] & 0xFF;
832                     srcX = 0;
833                 } else {
834                     if (offset is 0) {
835                         index++;
836                         theByte = data[index] & 0xFF;
837                     }
838                 }
839             }
840             return;
841         case 1:
842             index = (y * bytesPerLine) + (x >> 3);
843             theByte = data[index] & 0xFF;
844             while (n > 0) {
845                 mask = 1 << (7 - (srcX & 0x7));
846                 if ((theByte & mask) is 0) {
847                     pixels[i] = 0;
848                 } else {
849                     pixels[i] = 1;
850                 }
851                 i++;
852                 n--;
853                 srcX++;
854                 if (srcX >= width) {
855                     srcY++;
856                     index = srcY * bytesPerLine;
857                     if (n > 0) theByte = data[index] & 0xFF;
858                     srcX = 0;
859                 } else {
860                     if (mask is 1) {
861                         index++;
862                         if (n > 0) theByte = data[index] & 0xFF;
863                     }
864                 }
865             }
866             return;
867         default:
868     }
869     SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
870 }
871 
872 /**
873  * Returns <code>getWidth</code> pixel values starting at offset
874  * <code>x</code> in scanline <code>y</code> in the receiver's
875  * data starting at <code>startIndex</code>.
876  *
877  * @param x the x position of the first pixel to get
878  * @param y the y position of the first pixel to get
879  * @param getWidth the width of the data to get
880  * @param pixels the buffer in which to put the pixels
881  * @param startIndex the offset into the buffer to begin storing pixels
882  *
883  * @exception IndexOutOfBoundsException if getWidth is too large
884  * @exception IllegalArgumentException <ul>
885  *    <li>ERROR_NULL_ARGUMENT - if pixels is null</li>
886  *    <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
887  *    <li>ERROR_INVALID_ARGUMENT - if getWidth is negative</li>
888  * </ul>
889  * @exception SWTException <ul>
890  *    <li>ERROR_UNSUPPORTED_DEPTH - if the depth is not one of 1, 2, 4, 8, 16, 24 or 32</li>
891  * </ul>
892  */
893 public void getPixels(int x, int y, int getWidth, int[] pixels, int startIndex) {
894     if (pixels is null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
895     if (getWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
896     if (getWidth is 0) return;
897     int index;
898     int theByte;
899     int mask;
900     int n = getWidth;
901     int i = startIndex;
902     int srcX = x, srcY = y;
903     switch (depth) {
904         case 32:
905             index = (y * bytesPerLine) + (x * 4);
906             i = startIndex;
907             for (int j = 0; j < getWidth; j++) {
908                 pixels[i] = ((data[index] & 0xFF) << 24) | ((data[index+1] & 0xFF) << 16)
909                     | ((data[index+2] & 0xFF) << 8) | (data[index+3] & 0xFF);
910                 i++;
911                 srcX++;
912                 if (srcX >= width) {
913                     srcY++;
914                     index = srcY * bytesPerLine;
915                     srcX = 0;
916                 } else {
917                     index += 4;
918                 }
919             }
920             return;
921         case 24:
922             index = (y * bytesPerLine) + (x * 3);
923             for (int j = 0; j < getWidth; j++) {
924                 pixels[i] = ((data[index] & 0xFF) << 16) | ((data[index+1] & 0xFF) << 8)
925                     | (data[index+2] & 0xFF);
926                 i++;
927                 srcX++;
928                 if (srcX >= width) {
929                     srcY++;
930                     index = srcY * bytesPerLine;
931                     srcX = 0;
932                 } else {
933                     index += 3;
934                 }
935             }
936             return;
937         case 16:
938             index = (y * bytesPerLine) + (x * 2);
939             for (int j = 0; j < getWidth; j++) {
940                 pixels[i] = ((data[index+1] & 0xFF) << 8) + (data[index] & 0xFF);
941                 i++;
942                 srcX++;
943                 if (srcX >= width) {
944                     srcY++;
945                     index = srcY * bytesPerLine;
946                     srcX = 0;
947                 } else {
948                     index += 2;
949                 }
950             }
951             return;
952         case 8:
953             index = (y * bytesPerLine) + x;
954             for (int j = 0; j < getWidth; j++) {
955                 pixels[i] = data[index] & 0xFF;
956                 i++;
957                 srcX++;
958                 if (srcX >= width) {
959                     srcY++;
960                     index = srcY * bytesPerLine;
961                     srcX = 0;
962                 } else {
963                     index++;
964                 }
965             }
966             return;
967         case 4:
968             index = (y * bytesPerLine) + (x >> 1);
969             if ((x & 0x1) is 1) {
970                 theByte = data[index] & 0xFF;
971                 pixels[i] = theByte & 0x0F;
972                 i++;
973                 n--;
974                 srcX++;
975                 if (srcX >= width) {
976                     srcY++;
977                     index = srcY * bytesPerLine;
978                     srcX = 0;
979                 } else {
980                     index++;
981                 }
982             }
983             while (n > 1) {
984                 theByte = data[index] & 0xFF;
985                 pixels[i] = theByte >> 4;
986                 i++;
987                 n--;
988                 srcX++;
989                 if (srcX >= width) {
990                     srcY++;
991                     index = srcY * bytesPerLine;
992                     srcX = 0;
993                 } else {
994                     pixels[i] = theByte & 0x0F;
995                     i++;
996                     n--;
997                     srcX++;
998                     if (srcX >= width) {
999                         srcY++;
1000                         index = srcY * bytesPerLine;
1001                         srcX = 0;
1002                     } else {
1003                         index++;
1004                     }
1005                 }
1006             }
1007             if (n > 0) {
1008                 theByte = data[index] & 0xFF;
1009                 pixels[i] = theByte >> 4;
1010             }
1011             return;
1012         case 2:
1013             index = (y * bytesPerLine) + (x >> 2);
1014             theByte = data[index] & 0xFF;
1015             int offset;
1016             while (n > 0) {
1017                 offset = 3 - (srcX % 4);
1018                 mask = 3 << (offset * 2);
1019                 pixels[i] = cast(byte)((theByte & mask) >> (offset * 2));
1020                 i++;
1021                 n--;
1022                 srcX++;
1023                 if (srcX >= width) {
1024                     srcY++;
1025                     index = srcY * bytesPerLine;
1026                     if (n > 0) theByte = data[index] & 0xFF;
1027                     srcX = 0;
1028                 } else {
1029                     if (offset is 0) {
1030                         index++;
1031                         theByte = data[index] & 0xFF;
1032                     }
1033                 }
1034             }
1035             return;
1036         case 1:
1037             index = (y * bytesPerLine) + (x >> 3);
1038             theByte = data[index] & 0xFF;
1039             while (n > 0) {
1040                 mask = 1 << (7 - (srcX & 0x7));
1041                 if ((theByte & mask) is 0) {
1042                     pixels[i] = 0;
1043                 } else {
1044                     pixels[i] = 1;
1045                 }
1046                 i++;
1047                 n--;
1048                 srcX++;
1049                 if (srcX >= width) {
1050                     srcY++;
1051                     index = srcY * bytesPerLine;
1052                     if (n > 0) theByte = data[index] & 0xFF;
1053                     srcX = 0;
1054                 } else {
1055                     if (mask is 1) {
1056                         index++;
1057                         if (n > 0) theByte = data[index] & 0xFF;
1058                     }
1059                 }
1060             }
1061             return;
1062         default:
1063     }
1064     SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
1065 }
1066 
1067 /**
1068  * Returns an array of <code>RGB</code>s which comprise the
1069  * indexed color table of the receiver, or null if the receiver
1070  * has a direct color model.
1071  *
1072  * @return the RGB values for the image or null if direct color
1073  *
1074  * @see PaletteData#getRGBs()
1075  */
1076 public RGB[] getRGBs() {
1077     return palette.getRGBs();
1078 }
1079 
1080 /**
1081  * Returns an <code>ImageData</code> which specifies the
1082  * transparency mask information for the receiver. If the
1083  * receiver has no transparency or is not an icon, returns
1084  * an opaque mask.
1085  *
1086  * @return the transparency mask
1087  */
1088 public ImageData getTransparencyMask() {
1089     if (getTransparencyType() is SWT.TRANSPARENCY_MASK) {
1090         return new ImageData(width, height, 1, bwPalette(), maskPad, maskData);
1091     } else {
1092         return colorMaskImage(transparentPixel);
1093     }
1094 }
1095 
1096 /**
1097  * Returns the image transparency type, which will be one of
1098  * <code>SWT.TRANSPARENCY_NONE</code>, <code>SWT.TRANSPARENCY_MASK</code>,
1099  * <code>SWT.TRANSPARENCY_PIXEL</code> or <code>SWT.TRANSPARENCY_ALPHA</code>.
1100  *
1101  * @return the receiver's transparency type
1102  */
1103 public int getTransparencyType() {
1104     if (maskData !is null) return SWT.TRANSPARENCY_MASK;
1105     if (transparentPixel !is -1) return SWT.TRANSPARENCY_PIXEL;
1106     if (alphaData !is null) return SWT.TRANSPARENCY_ALPHA;
1107     return SWT.TRANSPARENCY_NONE;
1108 }
1109 
1110 /**
1111  * Returns the byte order of the receiver.
1112  *
1113  * @return MSB_FIRST or LSB_FIRST
1114  */
1115 int getByteOrder() {
1116     return depth !is 16 ? MSB_FIRST : LSB_FIRST;
1117 }
1118 
1119 /**
1120  * Returns a copy of the receiver which has been stretched or
1121  * shrunk to the specified size. If either the width or height
1122  * is negative, the resulting image will be inverted in the
1123  * associated axis.
1124  *
1125  * @param width the width of the new ImageData
1126  * @param height the height of the new ImageData
1127  * @return a scaled copy of the image
1128  */
1129 public ImageData scaledTo(int width, int height) {
1130     /* Create a destination image with no data */
1131     bool flipX = (width < 0);
1132     if (flipX) width = - width;
1133     bool flipY = (height < 0);
1134     if (flipY) height = - height;
1135 
1136     ImageData dest = new ImageData(
1137         width, height, depth, palette,
1138         scanlinePad, null, 0, null,
1139         null, -1, transparentPixel, type,
1140         x, y, disposalMethod, delayTime);
1141 
1142     /* Scale the image contents */
1143     if (palette.isDirect) blit(BLIT_SRC,
1144         this.data, this.depth, this.bytesPerLine, this.getByteOrder(), 0, 0, this.width, this.height, 0, 0, 0,
1145         ALPHA_OPAQUE, null, 0, 0, 0,
1146         dest.data, dest.depth, dest.bytesPerLine, dest.getByteOrder(), 0, 0, dest.width, dest.height, 0, 0, 0,
1147         flipX, flipY);
1148     else blit(BLIT_SRC,
1149         this.data, this.depth, this.bytesPerLine, this.getByteOrder(), 0, 0, this.width, this.height, null, null, null,
1150         ALPHA_OPAQUE, null, 0, 0, 0,
1151         dest.data, dest.depth, dest.bytesPerLine, dest.getByteOrder(), 0, 0, dest.width, dest.height, null, null, null,
1152         flipX, flipY);
1153 
1154     /* Scale the image mask or alpha */
1155     if (maskData !is null) {
1156         dest.maskPad = this.maskPad;
1157         int destBpl = (dest.width + 7) / 8;
1158         destBpl = (destBpl + (dest.maskPad - 1)) / dest.maskPad * dest.maskPad;
1159         dest.maskData = new byte[destBpl * dest.height];
1160         int srcBpl = (this.width + 7) / 8;
1161         srcBpl = (srcBpl + (this.maskPad - 1)) / this.maskPad * this.maskPad;
1162         blit(BLIT_SRC,
1163             this.maskData, 1, srcBpl, MSB_FIRST, 0, 0, this.width, this.height, null, null, null,
1164             ALPHA_OPAQUE, null, 0, 0, 0,
1165             dest.maskData, 1, destBpl, MSB_FIRST, 0, 0, dest.width, dest.height, null, null, null,
1166             flipX, flipY);
1167     } else if (alpha !is -1) {
1168         dest.alpha = this.alpha;
1169     } else if (alphaData !is null) {
1170         dest.alphaData = new byte[dest.width * dest.height];
1171         blit(BLIT_SRC,
1172             this.alphaData, 8, this.width, MSB_FIRST, 0, 0, this.width, this.height, null, null, null,
1173             ALPHA_OPAQUE, null, 0, 0, 0,
1174             dest.alphaData, 8, dest.width, MSB_FIRST, 0, 0, dest.width, dest.height, null, null, null,
1175             flipX, flipY);
1176     }
1177     return dest;
1178 }
1179 
1180 /**
1181  * Sets the alpha value at offset <code>x</code> in
1182  * scanline <code>y</code> in the receiver's alpha data.
1183  * The alpha value must be between 0 (transparent)
1184  * and 255 (opaque).
1185  *
1186  * @param x the x coordinate of the alpha value to set
1187  * @param y the y coordinate of the alpha value to set
1188  * @param alpha the value to set the alpha to
1189  *
1190  * @exception IllegalArgumentException <ul>
1191  *    <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
1192  *  </ul>
1193  */
1194 public void setAlpha(int x, int y, int alpha) {
1195     if (x >= width || y >= height || x < 0 || y < 0 || alpha < 0 || alpha > 255)
1196         SWT.error(SWT.ERROR_INVALID_ARGUMENT);
1197 
1198     if (alphaData is null) alphaData = new byte[width * height];
1199     alphaData[y * width + x] = cast(byte)alpha;
1200 }
1201 
1202 /**
1203  * Sets the alpha values starting at offset <code>x</code> in
1204  * scanline <code>y</code> in the receiver's alpha data to the
1205  * values from the array <code>alphas</code> starting at
1206  * <code>startIndex</code>. The alpha values must be between
1207  * <code>(byte)0</code> (transparent) and <code>(byte)255</code> (opaque)
1208  *
1209  * @param x the x coordinate of the pixel to being setting the alpha values
1210  * @param y the y coordinate of the pixel to being setting the alpha values
1211  * @param putWidth the width of the alpha values to set
1212  * @param alphas the alpha values to set
1213  * @param startIndex the index at which to begin setting
1214  *
1215  * @exception IndexOutOfBoundsException if putWidth is too large
1216  * @exception IllegalArgumentException <ul>
1217  *    <li>ERROR_NULL_ARGUMENT - if pixels is null</li>
1218  *    <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
1219  *    <li>ERROR_INVALID_ARGUMENT - if putWidth is negative</li>
1220  * </ul>
1221  */
1222 public void setAlphas(int x, int y, int putWidth, byte[] alphas, int startIndex) {
1223     if (alphas is null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
1224     if (putWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
1225     if (putWidth is 0) return;
1226 
1227     if (alphaData is null) alphaData = new byte[width * height];
1228     // may throw an IndexOutOfBoundsException
1229     System.arraycopy(alphas, startIndex, alphaData, y * width + x, putWidth);
1230 }
1231 
1232 /**
1233  * Sets the pixel value at offset <code>x</code> in
1234  * scanline <code>y</code> in the receiver's data.
1235  *
1236  * @param x the x coordinate of the pixel to set
1237  * @param y the y coordinate of the pixel to set
1238  * @param pixelValue the value to set the pixel to
1239  *
1240  * @exception IllegalArgumentException <ul>
1241  *    <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
1242  * </ul>
1243  * @exception SWTException <ul>
1244  *    <li>ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8, 16, 24 or 32</li>
1245  * </ul>
1246  */
1247 public void setPixel(int x, int y, int pixelValue) {
1248     if (x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
1249     int index;
1250     byte theByte;
1251     int mask;
1252     switch (depth) {
1253         case 32:
1254             index = (y * bytesPerLine) + (x * 4);
1255             data[index]  = cast(byte)((pixelValue >> 24) & 0xFF);
1256             data[index + 1] = cast(byte)((pixelValue >> 16) & 0xFF);
1257             data[index + 2] = cast(byte)((pixelValue >> 8) & 0xFF);
1258             data[index + 3] = cast(byte)(pixelValue & 0xFF);
1259             return;
1260         case 24:
1261             index = (y * bytesPerLine) + (x * 3);
1262             data[index] = cast(byte)((pixelValue >> 16) & 0xFF);
1263             data[index + 1] = cast(byte)((pixelValue >> 8) & 0xFF);
1264             data[index + 2] = cast(byte)(pixelValue & 0xFF);
1265             return;
1266         case 16:
1267             index = (y * bytesPerLine) + (x * 2);
1268             data[index + 1] = cast(byte)((pixelValue >> 8) & 0xFF);
1269             data[index] = cast(byte)(pixelValue & 0xFF);
1270             return;
1271         case 8:
1272             index = (y * bytesPerLine) + x ;
1273             data[index] = cast(byte)(pixelValue & 0xFF);
1274             return;
1275         case 4:
1276             index = (y * bytesPerLine) + (x >> 1);
1277             if ((x & 0x1) is 0) {
1278                 data[index] = cast(byte)((data[index] & 0x0F) | ((pixelValue & 0x0F) << 4));
1279             } else {
1280                 data[index] = cast(byte)((data[index] & 0xF0) | (pixelValue & 0x0F));
1281             }
1282             return;
1283         case 2:
1284             index = (y * bytesPerLine) + (x >> 2);
1285             theByte = data[index];
1286             int offset = 3 - (x % 4);
1287             mask = 0xFF ^ (3 << (offset * 2));
1288             data[index] = cast(byte)((data[index] & mask) | (pixelValue << (offset * 2)));
1289             return;
1290         case 1:
1291             index = (y * bytesPerLine) + (x >> 3);
1292             theByte = data[index];
1293             mask = 1 << (7 - (x & 0x7));
1294             if ((pixelValue & 0x1) is 1) {
1295                 data[index] = cast(byte)(theByte | mask);
1296             } else {
1297                 data[index] = cast(byte)(theByte & (mask ^ -1));
1298             }
1299             return;
1300         default:
1301     }
1302     SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
1303 }
1304 
1305 /**
1306  * Sets the pixel values starting at offset <code>x</code> in
1307  * scanline <code>y</code> in the receiver's data to the
1308  * values from the array <code>pixels</code> starting at
1309  * <code>startIndex</code>.
1310  *
1311  * @param x the x position of the pixel to set
1312  * @param y the y position of the pixel to set
1313  * @param putWidth the width of the pixels to set
1314  * @param pixels the pixels to set
1315  * @param startIndex the index at which to begin setting
1316  *
1317  * @exception IndexOutOfBoundsException if putWidth is too large
1318  * @exception IllegalArgumentException <ul>
1319  *    <li>ERROR_NULL_ARGUMENT - if pixels is null</li>
1320  *    <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
1321  *    <li>ERROR_INVALID_ARGUMENT - if putWidth is negative</li>
1322  * </ul>
1323  * @exception SWTException <ul>
1324  *    <li>ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8
1325  *        (For higher depths, use the int[] version of this method.)</li>
1326  * </ul>
1327  */
1328 public void setPixels(int x, int y, int putWidth, byte[] pixels, int startIndex) {
1329     if (pixels is null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
1330     if (putWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
1331     if (putWidth is 0) return;
1332     int index;
1333     int theByte;
1334     int mask;
1335     int n = putWidth;
1336     int i = startIndex;
1337     int srcX = x, srcY = y;
1338     switch (depth) {
1339         case 8:
1340             index = (y * bytesPerLine) + x;
1341             for (int j = 0; j < putWidth; j++) {
1342                 data[index] = cast(byte)(pixels[i] & 0xFF);
1343                 i++;
1344                 srcX++;
1345                 if (srcX >= width) {
1346                     srcY++;
1347                     index = srcY * bytesPerLine;
1348                     srcX = 0;
1349                 } else {
1350                     index++;
1351                 }
1352             }
1353             return;
1354         case 4:
1355             index = (y * bytesPerLine) + (x >> 1);
1356             bool high = (x & 0x1) is 0;
1357             while (n > 0) {
1358                 theByte = pixels[i] & 0x0F;
1359                 if (high) {
1360                     data[index] = cast(byte)((data[index] & 0x0F) | (theByte << 4));
1361                 } else {
1362                     data[index] = cast(byte)((data[index] & 0xF0) | theByte);
1363                 }
1364                 i++;
1365                 n--;
1366                 srcX++;
1367                 if (srcX >= width) {
1368                     srcY++;
1369                     index = srcY * bytesPerLine;
1370                     high = true;
1371                     srcX = 0;
1372                 } else {
1373                     if (!high) index++;
1374                     high = !high;
1375                 }
1376             }
1377             return;
1378         case 2:
1379             byte [] masks = [ cast(byte)0xFC, cast(byte)0xF3, cast(byte)0xCF, cast(byte)0x3F ];
1380             index = (y * bytesPerLine) + (x >> 2);
1381             int offset = 3 - (x % 4);
1382             while (n > 0) {
1383                 theByte = pixels[i] & 0x3;
1384                 data[index] = cast(byte)((data[index] & masks[offset]) | (theByte << (offset * 2)));
1385                 i++;
1386                 n--;
1387                 srcX++;
1388                 if (srcX >= width) {
1389                     srcY++;
1390                     index = srcY * bytesPerLine;
1391                     offset = 0;
1392                     srcX = 0;
1393                 } else {
1394                     if (offset is 0) {
1395                         index++;
1396                         offset = 3;
1397                     } else {
1398                         offset--;
1399                     }
1400                 }
1401             }
1402             return;
1403         case 1:
1404             index = (y * bytesPerLine) + (x >> 3);
1405             while (n > 0) {
1406                 mask = 1 << (7 - (srcX & 0x7));
1407                 if ((pixels[i] & 0x1) is 1) {
1408                     data[index] = cast(byte)((data[index] & 0xFF) | mask);
1409                 } else {
1410                     data[index] = cast(byte)((data[index] & 0xFF) & (mask ^ -1));
1411                 }
1412                 i++;
1413                 n--;
1414                 srcX++;
1415                 if (srcX >= width) {
1416                     srcY++;
1417                     index = srcY * bytesPerLine;
1418                     srcX = 0;
1419                 } else {
1420                     if (mask is 1) {
1421                         index++;
1422                     }
1423                 }
1424             }
1425             return;
1426         default:
1427     }
1428     SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
1429 }
1430 
1431 /**
1432  * Sets the pixel values starting at offset <code>x</code> in
1433  * scanline <code>y</code> in the receiver's data to the
1434  * values from the array <code>pixels</code> starting at
1435  * <code>startIndex</code>.
1436  *
1437  * @param x the x position of the pixel to set
1438  * @param y the y position of the pixel to set
1439  * @param putWidth the width of the pixels to set
1440  * @param pixels the pixels to set
1441  * @param startIndex the index at which to begin setting
1442  *
1443  * @exception IndexOutOfBoundsException if putWidth is too large
1444  * @exception IllegalArgumentException <ul>
1445  *    <li>ERROR_NULL_ARGUMENT - if pixels is null</li>
1446  *    <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
1447  *    <li>ERROR_INVALID_ARGUMENT - if putWidth is negative</li>
1448  * </ul>
1449  * @exception SWTException <ul>
1450  *    <li>ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8, 16, 24 or 32</li>
1451  * </ul>
1452  */
1453 public void setPixels(int x, int y, int putWidth, int[] pixels, int startIndex) {
1454     if (pixels is null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
1455     if (putWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
1456     if (putWidth is 0) return;
1457     int index;
1458     int theByte;
1459     int mask;
1460     int n = putWidth;
1461     int i = startIndex;
1462     int pixel;
1463     int srcX = x, srcY = y;
1464     switch (depth) {
1465         case 32:
1466             index = (y * bytesPerLine) + (x * 4);
1467             for (int j = 0; j < putWidth; j++) {
1468                 pixel = pixels[i];
1469                 data[index] = cast(byte)((pixel >> 24) & 0xFF);
1470                 data[index + 1] = cast(byte)((pixel >> 16) & 0xFF);
1471                 data[index + 2] = cast(byte)((pixel >> 8) & 0xFF);
1472                 data[index + 3] = cast(byte)(pixel & 0xFF);
1473                 i++;
1474                 srcX++;
1475                 if (srcX >= width) {
1476                     srcY++;
1477                     index = srcY * bytesPerLine;
1478                     srcX = 0;
1479                 } else {
1480                     index += 4;
1481                 }
1482             }
1483             return;
1484         case 24:
1485             index = (y * bytesPerLine) + (x * 3);
1486             for (int j = 0; j < putWidth; j++) {
1487                 pixel = pixels[i];
1488                 data[index] = cast(byte)((pixel >> 16) & 0xFF);
1489                 data[index + 1] = cast(byte)((pixel >> 8) & 0xFF);
1490                 data[index + 2] = cast(byte)(pixel & 0xFF);
1491                 i++;
1492                 srcX++;
1493                 if (srcX >= width) {
1494                     srcY++;
1495                     index = srcY * bytesPerLine;
1496                     srcX = 0;
1497                 } else {
1498                     index += 3;
1499                 }
1500             }
1501             return;
1502         case 16:
1503             index = (y * bytesPerLine) + (x * 2);
1504             for (int j = 0; j < putWidth; j++) {
1505                 pixel = pixels[i];
1506                 data[index] = cast(byte)(pixel & 0xFF);
1507                 data[index + 1] = cast(byte)((pixel >> 8) & 0xFF);
1508                 i++;
1509                 srcX++;
1510                 if (srcX >= width) {
1511                     srcY++;
1512                     index = srcY * bytesPerLine;
1513                     srcX = 0;
1514                 } else {
1515                     index += 2;
1516                 }
1517             }
1518             return;
1519         case 8:
1520             index = (y * bytesPerLine) + x;
1521             for (int j = 0; j < putWidth; j++) {
1522                 data[index] = cast(byte)(pixels[i] & 0xFF);
1523                 i++;
1524                 srcX++;
1525                 if (srcX >= width) {
1526                     srcY++;
1527                     index = srcY * bytesPerLine;
1528                     srcX = 0;
1529                 } else {
1530                     index++;
1531                 }
1532             }
1533             return;
1534         case 4:
1535             index = (y * bytesPerLine) + (x >> 1);
1536             bool high = (x & 0x1) is 0;
1537             while (n > 0) {
1538                 theByte = pixels[i] & 0x0F;
1539                 if (high) {
1540                     data[index] = cast(byte)((data[index] & 0x0F) | (theByte << 4));
1541                 } else {
1542                     data[index] = cast(byte)((data[index] & 0xF0) | theByte);
1543                 }
1544                 i++;
1545                 n--;
1546                 srcX++;
1547                 if (srcX >= width) {
1548                     srcY++;
1549                     index = srcY * bytesPerLine;
1550                     high = true;
1551                     srcX = 0;
1552                 } else {
1553                     if (!high) index++;
1554                     high = !high;
1555                 }
1556             }
1557             return;
1558         case 2:
1559             byte [] masks = [ cast(byte)0xFC, cast(byte)0xF3, cast(byte)0xCF, cast(byte)0x3F ];
1560             index = (y * bytesPerLine) + (x >> 2);
1561             int offset = 3 - (x % 4);
1562             while (n > 0) {
1563                 theByte = pixels[i] & 0x3;
1564                 data[index] = cast(byte)((data[index] & masks[offset]) | (theByte << (offset * 2)));
1565                 i++;
1566                 n--;
1567                 srcX++;
1568                 if (srcX >= width) {
1569                     srcY++;
1570                     index = srcY * bytesPerLine;
1571                     offset = 3;
1572                     srcX = 0;
1573                 } else {
1574                     if (offset is 0) {
1575                         index++;
1576                         offset = 3;
1577                     } else {
1578                         offset--;
1579                     }
1580                 }
1581             }
1582             return;
1583         case 1:
1584             index = (y * bytesPerLine) + (x >> 3);
1585             while (n > 0) {
1586                 mask = 1 << (7 - (srcX & 0x7));
1587                 if ((pixels[i] & 0x1) is 1) {
1588                     data[index] = cast(byte)((data[index] & 0xFF) | mask);
1589                 } else {
1590                     data[index] = cast(byte)((data[index] & 0xFF) & (mask ^ -1));
1591                 }
1592                 i++;
1593                 n--;
1594                 srcX++;
1595                 if (srcX >= width) {
1596                     srcY++;
1597                     index = srcY * bytesPerLine;
1598                     srcX = 0;
1599                 } else {
1600                     if (mask is 1) {
1601                         index++;
1602                     }
1603                 }
1604             }
1605             return;
1606         default:
1607     }
1608     SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
1609 }
1610 
1611 /**
1612  * Returns a palette with 2 colors: black & white.
1613  */
1614 static PaletteData bwPalette() {
1615     return new PaletteData( [ new RGB(0, 0, 0), new RGB(255, 255, 255) ] );
1616 }
1617 
1618 /**
1619  * Gets the offset of the most significant bit for
1620  * the given mask.
1621  */
1622 static int getMSBOffset(int mask) {
1623     for (int i = 31; i >= 0; i--) {
1624         if (((mask >> i) & 0x1) !is 0) return i + 1;
1625     }
1626     return 0;
1627 }
1628 
1629 /**
1630  * Finds the closest match.
1631  */
1632 static int closestMatch(int depth, byte red, byte green, byte blue, int redMask, int greenMask, int blueMask, byte[] reds, byte[] greens, byte[] blues) {
1633     if (depth > 8) {
1634         int rshift = 32 - getMSBOffset(redMask);
1635         int gshift = 32 - getMSBOffset(greenMask);
1636         int bshift = 32 - getMSBOffset(blueMask);
1637         return (((red << 24) >>> rshift) & redMask) |
1638             (((green << 24) >>> gshift) & greenMask) |
1639             (((blue << 24) >>> bshift) & blueMask);
1640     }
1641     int r, g, b;
1642     int minDistance = 0x7fffffff;
1643     int nearestPixel = 0;
1644     auto n = reds.length;
1645     for (int j = 0; j < n; j++) {
1646         r = (reds[j] & 0xFF) - (red & 0xFF);
1647         g = (greens[j] & 0xFF) - (green & 0xFF);
1648         b = (blues[j] & 0xFF) - (blue & 0xFF);
1649         int distance = r*r + g*g + b*b;
1650         if (distance < minDistance) {
1651             nearestPixel = j;
1652             if (distance is 0) break;
1653             minDistance = distance;
1654         }
1655     }
1656     return nearestPixel;
1657 }
1658 
1659 static final ImageData convertMask(ImageData mask) {
1660     if (mask.depth is 1) return mask;
1661     PaletteData palette = new PaletteData([new RGB(0, 0, 0), new RGB(255,255,255)]);
1662     ImageData newMask = new ImageData(mask.width, mask.height, 1, palette);
1663     /* Find index of black in mask palette */
1664     int blackIndex = 0;
1665     RGB[] rgbs = mask.getRGBs();
1666     if (rgbs !is null) {
1667         while (blackIndex < rgbs.length) {
1668             if (rgbs[blackIndex] is palette.colors[0] ) break;
1669             blackIndex++;
1670         }
1671     }
1672     int[] pixels = new int[mask.width];
1673     for (int y = 0; y < mask.height; y++) {
1674         mask.getPixels(0, y, mask.width, pixels, 0);
1675         for (int i = 0; i < pixels.length; i++) {
1676             if (pixels[i] is blackIndex) {
1677                 pixels[i] = 0;
1678             } else {
1679                 pixels[i] = 1;
1680             }
1681         }
1682         newMask.setPixels(0, y, mask.width, pixels, 0);
1683     }
1684     return newMask;
1685 }
1686 
1687 static final byte[] convertPad(byte[] data, int width, int height, int depth, int pad, int newPad) {
1688     if (pad is newPad) return data;
1689     int stride = (width * depth + 7) / 8;
1690     int bpl = (stride + (pad - 1)) / pad * pad;
1691     int newBpl = (stride + (newPad - 1)) / newPad * newPad;
1692     byte[] newData = new byte[height * newBpl];
1693     int srcIndex = 0, destIndex = 0;
1694     for (int y = 0; y < height; y++) {
1695         System.arraycopy(data, srcIndex, newData, destIndex, stride);
1696         srcIndex += bpl;
1697         destIndex += newBpl;
1698     }
1699     return newData;
1700 }
1701 
1702 /**
1703  * Blit operation bits to be OR'ed together to specify the desired operation.
1704  */
1705 static const int
1706     BLIT_SRC = 1,     // copy source directly, else applies logic operations
1707     BLIT_ALPHA = 2,   // enable alpha blending
1708     BLIT_DITHER = 4;  // enable dithering in low color modes
1709 
1710 /**
1711  * Alpha mode, values 0 - 255 specify global alpha level
1712  */
1713 static const int
1714     ALPHA_OPAQUE = 255,           // Fully opaque (ignores any alpha data)
1715     ALPHA_TRANSPARENT = 0,        // Fully transparent (ignores any alpha data)
1716     ALPHA_CHANNEL_SEPARATE = -1,  // Use alpha channel from separate alphaData
1717     ALPHA_CHANNEL_SOURCE = -2,    // Use alpha channel embedded in sourceData
1718     ALPHA_MASK_UNPACKED = -3,     // Use transparency mask formed by bytes in alphaData (non-zero is opaque)
1719     ALPHA_MASK_PACKED = -4,       // Use transparency mask formed by packed bits in alphaData
1720     ALPHA_MASK_INDEX = -5,        // Consider source palette indices transparent if in alphaData array
1721     ALPHA_MASK_RGB = -6;          // Consider source RGBs transparent if in RGB888 format alphaData array
1722 
1723 /**
1724  * Byte and bit order constants.
1725  */
1726 static const int LSB_FIRST = 0;
1727 static const int MSB_FIRST = 1;
1728 
1729 /**
1730  * Data types (internal)
1731  */
1732 private static const int
1733     // direct / true color formats with arbitrary masks & shifts
1734     TYPE_GENERIC_8 = 0,
1735     TYPE_GENERIC_16_MSB = 1,
1736     TYPE_GENERIC_16_LSB = 2,
1737     TYPE_GENERIC_24 = 3,
1738     TYPE_GENERIC_32_MSB = 4,
1739     TYPE_GENERIC_32_LSB = 5,
1740     // palette indexed color formats
1741     TYPE_INDEX_8 = 6,
1742     TYPE_INDEX_4 = 7,
1743     TYPE_INDEX_2 = 8,
1744     TYPE_INDEX_1_MSB = 9,
1745     TYPE_INDEX_1_LSB = 10;
1746 
1747 /**
1748  * Blits a direct palette image into a direct palette image.
1749  * <p>
1750  * Note: When the source and destination depth, order and masks
1751  * are pairwise equal and the blitter operation is BLIT_SRC,
1752  * the masks are ignored.  Hence when not changing the image
1753  * data format, 0 may be specified for the masks.
1754  * </p>
1755  *
1756  * @param op the blitter operation: a combination of BLIT_xxx flags
1757  *        (see BLIT_xxx constants)
1758  * @param srcData the source byte array containing image data
1759  * @param srcDepth the source depth: one of 8, 16, 24, 32
1760  * @param srcStride the source number of bytes per line
1761  * @param srcOrder the source byte ordering: one of MSB_FIRST or LSB_FIRST;
1762  *        ignored if srcDepth is not 16 or 32
1763  * @param srcX the top-left x-coord of the source blit region
1764  * @param srcY the top-left y-coord of the source blit region
1765  * @param srcWidth the width of the source blit region
1766  * @param srcHeight the height of the source blit region
1767  * @param srcRedMask the source red channel mask
1768  * @param srcGreenMask the source green channel mask
1769  * @param srcBlueMask the source blue channel mask
1770  * @param alphaMode the alpha blending or mask mode, may be
1771  *        an integer 0-255 for global alpha; ignored if BLIT_ALPHA
1772  *        not specified in the blitter operations
1773  *        (see ALPHA_MODE_xxx constants)
1774  * @param alphaData the alpha blending or mask data, varies depending
1775  *        on the value of alphaMode and sometimes ignored
1776  * @param alphaStride the alpha data number of bytes per line
1777  * @param alphaX the top-left x-coord of the alpha blit region
1778  * @param alphaY the top-left y-coord of the alpha blit region
1779  * @param destData the destination byte array containing image data
1780  * @param destDepth the destination depth: one of 8, 16, 24, 32
1781  * @param destStride the destination number of bytes per line
1782  * @param destOrder the destination byte ordering: one of MSB_FIRST or LSB_FIRST;
1783  *        ignored if destDepth is not 16 or 32
1784  * @param destX the top-left x-coord of the destination blit region
1785  * @param destY the top-left y-coord of the destination blit region
1786  * @param destWidth the width of the destination blit region
1787  * @param destHeight the height of the destination blit region
1788  * @param destRedMask the destination red channel mask
1789  * @param destGreenMask the destination green channel mask
1790  * @param destBlueMask the destination blue channel mask
1791  * @param flipX if true the resulting image is flipped along the vertical axis
1792  * @param flipY if true the resulting image is flipped along the horizontal axis
1793  */
1794 static void blit(int op,
1795     byte[] srcData, int srcDepth, int srcStride, int srcOrder,
1796     int srcX, int srcY, int srcWidth, int srcHeight,
1797     int srcRedMask, int srcGreenMask, int srcBlueMask,
1798     int alphaMode, byte[] alphaData, int alphaStride, int alphaX, int alphaY,
1799     byte[] destData, int destDepth, int destStride, int destOrder,
1800     int destX, int destY, int destWidth, int destHeight,
1801     int destRedMask, int destGreenMask, int destBlueMask,
1802     bool flipX, bool flipY) {
1803 
1804     static_this();
1805 
1806     if ((destWidth <= 0) || (destHeight <= 0) || (alphaMode is ALPHA_TRANSPARENT)) return;
1807 
1808     // these should be supplied as params later
1809     const int srcAlphaMask = 0, destAlphaMask = 0;
1810 
1811     /*** Prepare scaling data ***/
1812     int dwm1 = destWidth - 1;
1813     int sfxi = (dwm1 !is 0) ? cast(int)(((cast(long)srcWidth << 16) - 1) / dwm1) : 0;
1814     int dhm1 = destHeight - 1;
1815     int sfyi = (dhm1 !is 0) ? cast(int)(((cast(long)srcHeight << 16) - 1) / dhm1) : 0;
1816 
1817     /*** Prepare source-related data ***/
1818     int sbpp, stype;
1819     switch (srcDepth) {
1820         case 8:
1821             sbpp = 1;
1822             stype = TYPE_GENERIC_8;
1823             break;
1824         case 16:
1825             sbpp = 2;
1826             stype = (srcOrder is MSB_FIRST) ? TYPE_GENERIC_16_MSB : TYPE_GENERIC_16_LSB;
1827             break;
1828         case 24:
1829             sbpp = 3;
1830             stype = TYPE_GENERIC_24;
1831             break;
1832         case 32:
1833             sbpp = 4;
1834             stype = (srcOrder is MSB_FIRST) ? TYPE_GENERIC_32_MSB : TYPE_GENERIC_32_LSB;
1835             break;
1836         default:
1837             //throw new IllegalArgumentException("Invalid source type");
1838             return;
1839     }
1840     int spr = srcY * srcStride + srcX * sbpp;
1841 
1842     /*** Prepare destination-related data ***/
1843     int dbpp, dtype;
1844     switch (destDepth) {
1845         case 8:
1846             dbpp = 1;
1847             dtype = TYPE_GENERIC_8;
1848             break;
1849         case 16:
1850             dbpp = 2;
1851             dtype = (destOrder is MSB_FIRST) ? TYPE_GENERIC_16_MSB : TYPE_GENERIC_16_LSB;
1852             break;
1853         case 24:
1854             dbpp = 3;
1855             dtype = TYPE_GENERIC_24;
1856             break;
1857         case 32:
1858             dbpp = 4;
1859             dtype = (destOrder is MSB_FIRST) ? TYPE_GENERIC_32_MSB : TYPE_GENERIC_32_LSB;
1860             break;
1861         default:
1862             //throw new IllegalArgumentException("Invalid destination type");
1863             return;
1864     }
1865     int dpr = ((flipY) ? destY + dhm1 : destY) * destStride + ((flipX) ? destX + dwm1 : destX) * dbpp;
1866     int dprxi = (flipX) ? -dbpp : dbpp;
1867     int dpryi = (flipY) ? -destStride : destStride;
1868 
1869     /*** Prepare special processing data ***/
1870     int apr;
1871     if ((op & BLIT_ALPHA) !is 0) {
1872         switch (alphaMode) {
1873             case ALPHA_MASK_UNPACKED:
1874             case ALPHA_CHANNEL_SEPARATE:
1875                 if (alphaData is null) alphaMode = 0x10000;
1876                 apr = alphaY * alphaStride + alphaX;
1877                 break;
1878             case ALPHA_MASK_PACKED:
1879                 if (alphaData is null) alphaMode = 0x10000;
1880                 alphaStride <<= 3;
1881                 apr = alphaY * alphaStride + alphaX;
1882                 break;
1883             case ALPHA_MASK_INDEX:
1884                 //throw new IllegalArgumentException("Invalid alpha type");
1885                 return;
1886             case ALPHA_MASK_RGB:
1887                 if (alphaData is null) alphaMode = 0x10000;
1888                 apr = 0;
1889                 break;
1890             default:
1891                 alphaMode = (alphaMode << 16) / 255; // prescale
1892                 goto case ALPHA_CHANNEL_SOURCE;
1893             case ALPHA_CHANNEL_SOURCE:
1894                 apr = 0;
1895                 break;
1896         }
1897     } else {
1898         alphaMode = 0x10000;
1899         apr = 0;
1900     }
1901 
1902     /*** Blit ***/
1903     int dp = dpr;
1904     int sp = spr;
1905     if ((alphaMode is 0x10000) && (stype is dtype) &&
1906         (srcRedMask is destRedMask) && (srcGreenMask is destGreenMask) &&
1907         (srcBlueMask is destBlueMask) && (srcAlphaMask is destAlphaMask)) {
1908         /*** Fast blit (straight copy) ***/
1909         switch (sbpp) {
1910             case 1:
1911                 for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
1912                     for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
1913                         destData[dp] = srcData[sp];
1914                         sp += (sfx >>> 16);
1915                     }
1916                 }
1917                 break;
1918             case 2:
1919                 for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
1920                     for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
1921                         destData[dp] = srcData[sp];
1922                         destData[dp + 1] = srcData[sp + 1];
1923                         sp += (sfx >>> 16) * 2;
1924                     }
1925                 }
1926                 break;
1927             case 3:
1928                 for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
1929                     for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
1930                         destData[dp] = srcData[sp];
1931                         destData[dp + 1] = srcData[sp + 1];
1932                         destData[dp + 2] = srcData[sp + 2];
1933                         sp += (sfx >>> 16) * 3;
1934                     }
1935                 }
1936                 break;
1937             case 4:
1938                 for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
1939                     for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
1940                         destData[dp] = srcData[sp];
1941                         destData[dp + 1] = srcData[sp + 1];
1942                         destData[dp + 2] = srcData[sp + 2];
1943                         destData[dp + 3] = srcData[sp + 3];
1944                         sp += (sfx >>> 16) * 4;
1945                     }
1946                 }
1947                 break;
1948         default:
1949         }
1950         return;
1951     }
1952     /*** Comprehensive blit (apply transformations) ***/
1953     int srcRedShift = getChannelShift(srcRedMask);
1954     byte[] srcReds = ANY_TO_EIGHT[getChannelWidth(srcRedMask, srcRedShift)];
1955     int srcGreenShift = getChannelShift(srcGreenMask);
1956     byte[] srcGreens = ANY_TO_EIGHT[getChannelWidth(srcGreenMask, srcGreenShift)];
1957     int srcBlueShift = getChannelShift(srcBlueMask);
1958     byte[] srcBlues = ANY_TO_EIGHT[getChannelWidth(srcBlueMask, srcBlueShift)];
1959     int srcAlphaShift = getChannelShift(srcAlphaMask);
1960     byte[] srcAlphas = ANY_TO_EIGHT[getChannelWidth(srcAlphaMask, srcAlphaShift)];
1961 
1962     int destRedShift = getChannelShift(destRedMask);
1963     int destRedWidth = getChannelWidth(destRedMask, destRedShift);
1964     byte[] destReds = ANY_TO_EIGHT[destRedWidth];
1965     int destRedPreShift = 8 - destRedWidth;
1966     int destGreenShift = getChannelShift(destGreenMask);
1967     int destGreenWidth = getChannelWidth(destGreenMask, destGreenShift);
1968     byte[] destGreens = ANY_TO_EIGHT[destGreenWidth];
1969     int destGreenPreShift = 8 - destGreenWidth;
1970     int destBlueShift = getChannelShift(destBlueMask);
1971     int destBlueWidth = getChannelWidth(destBlueMask, destBlueShift);
1972     byte[] destBlues = ANY_TO_EIGHT[destBlueWidth];
1973     int destBluePreShift = 8 - destBlueWidth;
1974     int destAlphaShift = getChannelShift(destAlphaMask);
1975     int destAlphaWidth = getChannelWidth(destAlphaMask, destAlphaShift);
1976     byte[] destAlphas = ANY_TO_EIGHT[destAlphaWidth];
1977     int destAlphaPreShift = 8 - destAlphaWidth;
1978 
1979     int ap = apr, alpha = alphaMode;
1980     int r = 0, g = 0, b = 0, a = 0;
1981     int rq = 0, gq = 0, bq = 0, aq = 0;
1982     for (int dy = destHeight, sfy = sfyi; dy > 0; --dy,
1983             sp = spr += (sfy >>> 16) * srcStride,
1984             ap = apr += (sfy >>> 16) * alphaStride,
1985             sfy = (sfy & 0xffff) + sfyi,
1986             dp = dpr += dpryi) {
1987         for (int dx = destWidth, sfx = sfxi; dx > 0; --dx,
1988                 dp += dprxi,
1989                 sfx = (sfx & 0xffff) + sfxi) {
1990             /*** READ NEXT PIXEL ***/
1991             switch (stype) {
1992                 case TYPE_GENERIC_8: {
1993                     int data = srcData[sp] & 0xff;
1994                     sp += (sfx >>> 16);
1995                     r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
1996                     g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
1997                     b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
1998                     a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
1999                 } break;
2000                 case TYPE_GENERIC_16_MSB: {
2001                     int data = ((srcData[sp] & 0xff) << 8) | (srcData[sp + 1] & 0xff);
2002                     sp += (sfx >>> 16) * 2;
2003                     r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
2004                     g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
2005                     b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
2006                     a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
2007                 } break;
2008                 case TYPE_GENERIC_16_LSB: {
2009                     int data = ((srcData[sp + 1] & 0xff) << 8) | (srcData[sp] & 0xff);
2010                     sp += (sfx >>> 16) * 2;
2011                     r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
2012                     g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
2013                     b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
2014                     a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
2015                 } break;
2016                 case TYPE_GENERIC_24: {
2017                     int data = (( ((srcData[sp] & 0xff) << 8) |
2018                         (srcData[sp + 1] & 0xff)) << 8) |
2019                         (srcData[sp + 2] & 0xff);
2020                     sp += (sfx >>> 16) * 3;
2021                     r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
2022                     g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
2023                     b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
2024                     a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
2025                 } break;
2026                 case TYPE_GENERIC_32_MSB: {
2027                     int data = (( (( ((srcData[sp] & 0xff) << 8) |
2028                         (srcData[sp + 1] & 0xff)) << 8) |
2029                         (srcData[sp + 2] & 0xff)) << 8) |
2030                         (srcData[sp + 3] & 0xff);
2031                     sp += (sfx >>> 16) * 4;
2032                     r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
2033                     g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
2034                     b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
2035                     a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
2036                 } break;
2037                 case TYPE_GENERIC_32_LSB: {
2038                     int data = (( (( ((srcData[sp + 3] & 0xff) << 8) |
2039                         (srcData[sp + 2] & 0xff)) << 8) |
2040                         (srcData[sp + 1] & 0xff)) << 8) |
2041                         (srcData[sp] & 0xff);
2042                     sp += (sfx >>> 16) * 4;
2043                     r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
2044                     g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
2045                     b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
2046                     a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
2047                 } break;
2048                 default:
2049             }
2050 
2051             /*** DO SPECIAL PROCESSING IF REQUIRED ***/
2052             switch (alphaMode) {
2053                 case ALPHA_CHANNEL_SEPARATE:
2054                     alpha = ((alphaData[ap] & 0xff) << 16) / 255;
2055                     ap += (sfx >> 16);
2056                     break;
2057                 case ALPHA_CHANNEL_SOURCE:
2058                     alpha = (a << 16) / 255;
2059                     break;
2060                 case ALPHA_MASK_UNPACKED:
2061                     alpha = (alphaData[ap] !is 0) ? 0x10000 : 0;
2062                     ap += (sfx >> 16);
2063                     break;
2064                 case ALPHA_MASK_PACKED:
2065                     alpha = (alphaData[ap >> 3] << ((ap & 7) + 9)) & 0x10000;
2066                     ap += (sfx >> 16);
2067                     break;
2068                 case ALPHA_MASK_RGB:
2069                     alpha = 0x10000;
2070                     for (int i = 0; i < alphaData.length; i += 3) {
2071                         if ((r is alphaData[i]) && (g is alphaData[i + 1]) && (b is alphaData[i + 2])) {
2072                             alpha = 0x0000;
2073                             break;
2074                         }
2075                     }
2076                     break;
2077                 default:
2078             }
2079             if (alpha !is 0x10000) {
2080                 if (alpha is 0x0000) continue;
2081                 switch (dtype) {
2082                     case TYPE_GENERIC_8: {
2083                         int data = destData[dp] & 0xff;
2084                         rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
2085                         gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
2086                         bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
2087                         aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
2088                     } break;
2089                     case TYPE_GENERIC_16_MSB: {
2090                         int data = ((destData[dp] & 0xff) << 8) | (destData[dp + 1] & 0xff);
2091                         rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
2092                         gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
2093                         bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
2094                         aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
2095                     } break;
2096                     case TYPE_GENERIC_16_LSB: {
2097                         int data = ((destData[dp + 1] & 0xff) << 8) | (destData[dp] & 0xff);
2098                         rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
2099                         gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
2100                         bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
2101                         aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
2102                     } break;
2103                     case TYPE_GENERIC_24: {
2104                         int data = (( ((destData[dp] & 0xff) << 8) |
2105                             (destData[dp + 1] & 0xff)) << 8) |
2106                             (destData[dp + 2] & 0xff);
2107                         rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
2108                         gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
2109                         bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
2110                         aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
2111                     } break;
2112                     case TYPE_GENERIC_32_MSB: {
2113                         int data = (( (( ((destData[dp] & 0xff) << 8) |
2114                             (destData[dp + 1] & 0xff)) << 8) |
2115                             (destData[dp + 2] & 0xff)) << 8) |
2116                             (destData[dp + 3] & 0xff);
2117                         rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
2118                         gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
2119                         bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
2120                         aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
2121                     } break;
2122                     case TYPE_GENERIC_32_LSB: {
2123                         int data = (( (( ((destData[dp + 3] & 0xff) << 8) |
2124                             (destData[dp + 2] & 0xff)) << 8) |
2125                             (destData[dp + 1] & 0xff)) << 8) |
2126                             (destData[dp] & 0xff);
2127                         rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
2128                         gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
2129                         bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
2130                         aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
2131                     } break;
2132                     default:
2133                 }
2134                 // Perform alpha blending
2135                 a = aq + ((a - aq) * alpha >> 16);
2136                 r = rq + ((r - rq) * alpha >> 16);
2137                 g = gq + ((g - gq) * alpha >> 16);
2138                 b = bq + ((b - bq) * alpha >> 16);
2139             }
2140 
2141             /*** WRITE NEXT PIXEL ***/
2142             int data =
2143                 (r >>> destRedPreShift << destRedShift) |
2144                 (g >>> destGreenPreShift << destGreenShift) |
2145                 (b >>> destBluePreShift << destBlueShift) |
2146                 (a >>> destAlphaPreShift << destAlphaShift);
2147             switch (dtype) {
2148                 case TYPE_GENERIC_8: {
2149                     destData[dp] = cast(byte) data;
2150                 } break;
2151                 case TYPE_GENERIC_16_MSB: {
2152                     destData[dp] = cast(byte) (data >>> 8);
2153                     destData[dp + 1] = cast(byte) (data & 0xff);
2154                 } break;
2155                 case TYPE_GENERIC_16_LSB: {
2156                     destData[dp] = cast(byte) (data & 0xff);
2157                     destData[dp + 1] = cast(byte) (data >>> 8);
2158                 } break;
2159                 case TYPE_GENERIC_24: {
2160                     destData[dp] = cast(byte) (data >>> 16);
2161                     destData[dp + 1] = cast(byte) (data >>> 8);
2162                     destData[dp + 2] = cast(byte) (data & 0xff);
2163                 } break;
2164                 case TYPE_GENERIC_32_MSB: {
2165                     destData[dp] = cast(byte) (data >>> 24);
2166                     destData[dp + 1] = cast(byte) (data >>> 16);
2167                     destData[dp + 2] = cast(byte) (data >>> 8);
2168                     destData[dp + 3] = cast(byte) (data & 0xff);
2169                 } break;
2170                 case TYPE_GENERIC_32_LSB: {
2171                     destData[dp] = cast(byte) (data & 0xff);
2172                     destData[dp + 1] = cast(byte) (data >>> 8);
2173                     destData[dp + 2] = cast(byte) (data >>> 16);
2174                     destData[dp + 3] = cast(byte) (data >>> 24);
2175                 } break;
2176                 default:
2177             }
2178         }
2179     }
2180 }
2181 
2182 /**
2183  * Blits an index palette image into an index palette image.
2184  * <p>
2185  * Note: The source and destination red, green, and blue
2186  * arrays may be null if no alpha blending or dither is to be
2187  * performed.
2188  * </p>
2189  *
2190  * @param op the blitter operation: a combination of BLIT_xxx flags
2191  *        (see BLIT_xxx constants)
2192  * @param srcData the source byte array containing image data
2193  * @param srcDepth the source depth: one of 1, 2, 4, 8
2194  * @param srcStride the source number of bytes per line
2195  * @param srcOrder the source byte ordering: one of MSB_FIRST or LSB_FIRST;
2196  *        ignored if srcDepth is not 1
2197  * @param srcX the top-left x-coord of the source blit region
2198  * @param srcY the top-left y-coord of the source blit region
2199  * @param srcWidth the width of the source blit region
2200  * @param srcHeight the height of the source blit region
2201  * @param srcReds the source palette red component intensities
2202  * @param srcGreens the source palette green component intensities
2203  * @param srcBlues the source palette blue component intensities
2204  * @param alphaMode the alpha blending or mask mode, may be
2205  *        an integer 0-255 for global alpha; ignored if BLIT_ALPHA
2206  *        not specified in the blitter operations
2207  *        (see ALPHA_MODE_xxx constants)
2208  * @param alphaData the alpha blending or mask data, varies depending
2209  *        on the value of alphaMode and sometimes ignored
2210  * @param alphaStride the alpha data number of bytes per line
2211  * @param alphaX the top-left x-coord of the alpha blit region
2212  * @param alphaY the top-left y-coord of the alpha blit region
2213  * @param destData the destination byte array containing image data
2214  * @param destDepth the destination depth: one of 1, 2, 4, 8
2215  * @param destStride the destination number of bytes per line
2216  * @param destOrder the destination byte ordering: one of MSB_FIRST or LSB_FIRST;
2217  *        ignored if destDepth is not 1
2218  * @param destX the top-left x-coord of the destination blit region
2219  * @param destY the top-left y-coord of the destination blit region
2220  * @param destWidth the width of the destination blit region
2221  * @param destHeight the height of the destination blit region
2222  * @param destReds the destination palette red component intensities
2223  * @param destGreens the destination palette green component intensities
2224  * @param destBlues the destination palette blue component intensities
2225  * @param flipX if true the resulting image is flipped along the vertical axis
2226  * @param flipY if true the resulting image is flipped along the horizontal axis
2227  */
2228 static void blit(int op,
2229     byte[] srcData, int srcDepth, int srcStride, int srcOrder,
2230     int srcX, int srcY, int srcWidth, int srcHeight,
2231     byte[] srcReds, byte[] srcGreens, byte[] srcBlues,
2232     int alphaMode, byte[] alphaData, int alphaStride, int alphaX, int alphaY,
2233     byte[] destData, int destDepth, int destStride, int destOrder,
2234     int destX, int destY, int destWidth, int destHeight,
2235     byte[] destReds, byte[] destGreens, byte[] destBlues,
2236     bool flipX, bool flipY) {
2237 
2238     static_this();
2239 
2240     if ((destWidth <= 0) || (destHeight <= 0) || (alphaMode is ALPHA_TRANSPARENT)) return;
2241 
2242     /*** Prepare scaling data ***/
2243     int dwm1 = destWidth - 1;
2244     int sfxi = (dwm1 !is 0) ? cast(int)(((cast(long)srcWidth << 16) - 1) / dwm1) : 0;
2245     int dhm1 = destHeight - 1;
2246     int sfyi = (dhm1 !is 0) ? cast(int)(((cast(long)srcHeight << 16) - 1) / dhm1) : 0;
2247 
2248     /*** Prepare source-related data ***/
2249     int stype;
2250     switch (srcDepth) {
2251         case 8:
2252             stype = TYPE_INDEX_8;
2253             break;
2254         case 4:
2255             srcStride <<= 1;
2256             stype = TYPE_INDEX_4;
2257             break;
2258         case 2:
2259             srcStride <<= 2;
2260             stype = TYPE_INDEX_2;
2261             break;
2262         case 1:
2263             srcStride <<= 3;
2264             stype = (srcOrder is MSB_FIRST) ? TYPE_INDEX_1_MSB : TYPE_INDEX_1_LSB;
2265             break;
2266         default:
2267             //throw new IllegalArgumentException("Invalid source type");
2268             return;
2269     }
2270     int spr = srcY * srcStride + srcX;
2271 
2272     /*** Prepare destination-related data ***/
2273     int dtype;
2274     switch (destDepth) {
2275         case 8:
2276             dtype = TYPE_INDEX_8;
2277             break;
2278         case 4:
2279             destStride <<= 1;
2280             dtype = TYPE_INDEX_4;
2281             break;
2282         case 2:
2283             destStride <<= 2;
2284             dtype = TYPE_INDEX_2;
2285             break;
2286         case 1:
2287             destStride <<= 3;
2288             dtype = (destOrder is MSB_FIRST) ? TYPE_INDEX_1_MSB : TYPE_INDEX_1_LSB;
2289             break;
2290         default:
2291             //throw new IllegalArgumentException("Invalid source type");
2292             return;
2293     }
2294     int dpr = ((flipY) ? destY + dhm1 : destY) * destStride + ((flipX) ? destX + dwm1 : destX);
2295     int dprxi = (flipX) ? -1 : 1;
2296     int dpryi = (flipY) ? -destStride : destStride;
2297 
2298     /*** Prepare special processing data ***/
2299     int apr;
2300     if ((op & BLIT_ALPHA) !is 0) {
2301         switch (alphaMode) {
2302             case ALPHA_MASK_UNPACKED:
2303             case ALPHA_CHANNEL_SEPARATE:
2304                 if (alphaData is null) alphaMode = 0x10000;
2305                 apr = alphaY * alphaStride + alphaX;
2306                 break;
2307             case ALPHA_MASK_PACKED:
2308                 if (alphaData is null) alphaMode = 0x10000;
2309                 alphaStride <<= 3;
2310                 apr = alphaY * alphaStride + alphaX;
2311                 break;
2312             case ALPHA_MASK_INDEX:
2313             case ALPHA_MASK_RGB:
2314                 if (alphaData is null) alphaMode = 0x10000;
2315                 apr = 0;
2316                 break;
2317             default:
2318                 alphaMode = (alphaMode << 16) / 255; // prescale
2319                 goto case ALPHA_CHANNEL_SOURCE;
2320             case ALPHA_CHANNEL_SOURCE:
2321                 apr = 0;
2322                 break;
2323         }
2324     } else {
2325         alphaMode = 0x10000;
2326         apr = 0;
2327     }
2328     bool ditherEnabled = (op & BLIT_DITHER) !is 0;
2329 
2330     /*** Blit ***/
2331     int dp = dpr;
2332     int sp = spr;
2333     int ap = apr;
2334     int destPaletteSize = 1 << destDepth;
2335     if ((destReds !is null) && (destReds.length < destPaletteSize))
2336         destPaletteSize = cast(int)/*64bit*/destReds.length;
2337     byte[] paletteMapping = null;
2338     bool isExactPaletteMapping = true;
2339     switch (alphaMode) {
2340         case 0x10000:
2341             /*** If the palettes and formats are equivalent use a one-to-one mapping ***/
2342             if ((stype is dtype) &&
2343                 (srcReds is destReds) && (srcGreens is destGreens) && (srcBlues is destBlues)) {
2344                 paletteMapping = ONE_TO_ONE_MAPPING;
2345                 break;
2346             /*** If palettes have not been supplied, supply a suitable mapping ***/
2347             } else if ((srcReds is null) || (destReds is null)) {
2348                 if (srcDepth <= destDepth) {
2349                     paletteMapping = ONE_TO_ONE_MAPPING;
2350                 } else {
2351                     paletteMapping = new byte[1 << srcDepth];
2352                     int mask = (0xff << destDepth) >>> 8;
2353                     for (int i = 0; i < paletteMapping.length; ++i) paletteMapping[i] = cast(byte)(i & mask);
2354                 }
2355                 break;
2356             }
2357             goto case ALPHA_MASK_UNPACKED;
2358         case ALPHA_MASK_UNPACKED:
2359         case ALPHA_MASK_PACKED:
2360         case ALPHA_MASK_INDEX:
2361         case ALPHA_MASK_RGB:
2362             /*** Generate a palette mapping ***/
2363             int srcPaletteSize = 1 << srcDepth;
2364             paletteMapping = new byte[srcPaletteSize];
2365             if ((srcReds !is null) && (srcReds.length < srcPaletteSize))
2366                 srcPaletteSize = cast(int)/*64bit*/srcReds.length;
2367             for (int i = 0, r, g, b, index; i < srcPaletteSize; ++i) {
2368                 r = srcReds[i] & 0xff;
2369                 g = srcGreens[i] & 0xff;
2370                 b = srcBlues[i] & 0xff;
2371                 index = 0;
2372                 int minDistance = 0x7fffffff;
2373                 for (int j = 0, dr, dg, db, distance; j < destPaletteSize; ++j) {
2374                     dr = (destReds[j] & 0xff) - r;
2375                     dg = (destGreens[j] & 0xff) - g;
2376                     db = (destBlues[j] & 0xff) - b;
2377                     distance = dr * dr + dg * dg + db * db;
2378                     if (distance < minDistance) {
2379                         index = j;
2380                         if (distance is 0) break;
2381                         minDistance = distance;
2382                     }
2383                 }
2384                 paletteMapping[i] = cast(byte)index;
2385                 if (minDistance !is 0) isExactPaletteMapping = false;
2386             }
2387             break;
2388         default:
2389     }
2390     if ((paletteMapping !is null) && (isExactPaletteMapping || ! ditherEnabled)) {
2391         if ((stype is dtype) && (alphaMode is 0x10000)) {
2392             /*** Fast blit (copy w/ mapping) ***/
2393             switch (stype) {
2394                 case TYPE_INDEX_8:
2395                     for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
2396                         for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
2397                             destData[dp] = paletteMapping[srcData[sp] & 0xff];
2398                             sp += (sfx >>> 16);
2399                         }
2400                     }
2401                     break;
2402                 case TYPE_INDEX_4:
2403                     for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
2404                         for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
2405                             int v;
2406                             if ((sp & 1) !is 0) v = paletteMapping[srcData[sp >> 1] & 0x0f];
2407                             else v = (srcData[sp >> 1] >>> 4) & 0x0f;
2408                             sp += (sfx >>> 16);
2409                             if ((dp & 1) !is 0) destData[dp >> 1] = cast(byte)((destData[dp >> 1] & 0xf0) | v);
2410                             else destData[dp >> 1] = cast(byte)((destData[dp >> 1] & 0x0f) | (v << 4));
2411                         }
2412                     }
2413                     break;
2414                 case TYPE_INDEX_2:
2415                     for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
2416                         for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
2417                             int index = paletteMapping[(srcData[sp >> 2] >>> (6 - (sp & 3) * 2)) & 0x03];
2418                             sp += (sfx >>> 16);
2419                             int shift = 6 - (dp & 3) * 2;
2420                             destData[dp >> 2] = cast(byte)(destData[dp >> 2] & ~(0x03 << shift) | (index << shift));
2421                         }
2422                     }
2423                     break;
2424                 case TYPE_INDEX_1_MSB:
2425                     for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
2426                         for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
2427                             int index = paletteMapping[(srcData[sp >> 3] >>> (7 - (sp & 7))) & 0x01];
2428                             sp += (sfx >>> 16);
2429                             int shift = 7 - (dp & 7);
2430                             destData[dp >> 3] = cast(byte)(destData[dp >> 3] & ~(0x01 << shift) | (index << shift));
2431                         }
2432                     }
2433                     break;
2434                 case TYPE_INDEX_1_LSB:
2435                     for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16) * srcStride, sfy = (sfy & 0xffff) + sfyi, dp = dpr += dpryi) {
2436                         for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff) + sfxi) {
2437                             int index = paletteMapping[(srcData[sp >> 3] >>> (sp & 7)) & 0x01];
2438                             sp += (sfx >>> 16);
2439                             int shift = dp & 7;
2440                             destData[dp >> 3] = cast(byte)(destData[dp >> 3] & ~(0x01 << shift) | (index << shift));
2441                         }
2442                     }
2443                     break;
2444                 default:
2445             }
2446         } else {
2447             /*** Convert between indexed modes using mapping and mask ***/
2448             for (int dy = destHeight, sfy = sfyi; dy > 0; --dy,
2449                     sp = spr += (sfy >>> 16) * srcStride,
2450                     sfy = (sfy & 0xffff) + sfyi,
2451                     dp = dpr += dpryi) {
2452                 for (int dx = destWidth, sfx = sfxi; dx > 0; --dx,
2453                         dp += dprxi,
2454                         sfx = (sfx & 0xffff) + sfxi) {
2455                     int index;
2456                     /*** READ NEXT PIXEL ***/
2457                     switch (stype) {
2458                         case TYPE_INDEX_8:
2459                             index = srcData[sp] & 0xff;
2460                             sp += (sfx >>> 16);
2461                             break;
2462                         case TYPE_INDEX_4:
2463                             if ((sp & 1) !is 0) index = srcData[sp >> 1] & 0x0f;
2464                             else index = (srcData[sp >> 1] >>> 4) & 0x0f;
2465                             sp += (sfx >>> 16);
2466                             break;
2467                         case TYPE_INDEX_2:
2468                             index = (srcData[sp >> 2] >>> (6 - (sp & 3) * 2)) & 0x03;
2469                             sp += (sfx >>> 16);
2470                             break;
2471                         case TYPE_INDEX_1_MSB:
2472                             index = (srcData[sp >> 3] >>> (7 - (sp & 7))) & 0x01;
2473                             sp += (sfx >>> 16);
2474                             break;
2475                         case TYPE_INDEX_1_LSB:
2476                             index = (srcData[sp >> 3] >>> (sp & 7)) & 0x01;
2477                             sp += (sfx >>> 16);
2478                             break;
2479                         default:
2480                             return;
2481                     }
2482                     /*** APPLY MASK ***/
2483                     switch (alphaMode) {
2484                         case ALPHA_MASK_UNPACKED: {
2485                             byte mask = alphaData[ap];
2486                             ap += (sfx >> 16);
2487                             if (mask is 0) continue;
2488                         } break;
2489                         case ALPHA_MASK_PACKED: {
2490                             int mask = alphaData[ap >> 3] & (1 << (ap & 7));
2491                             ap += (sfx >> 16);
2492                             if (mask is 0) continue;
2493                         } break;
2494                         case ALPHA_MASK_INDEX: {
2495                             int i = 0;
2496                             while (i < alphaData.length) {
2497                                 if (index is (alphaData[i] & 0xff)) break;
2498                             }
2499                             if (i < alphaData.length) continue;
2500                         } break;
2501                         case ALPHA_MASK_RGB: {
2502                             byte r = srcReds[index], g = srcGreens[index], b = srcBlues[index];
2503                             int i = 0;
2504                             while (i < alphaData.length) {
2505                                 if ((r is alphaData[i]) && (g is alphaData[i + 1]) && (b is alphaData[i + 2])) break;
2506                                 i += 3;
2507                             }
2508                             if (i < alphaData.length) continue;
2509                         } break;
2510                         default:
2511                     }
2512                     index = paletteMapping[index] & 0xff;
2513 
2514                     /*** WRITE NEXT PIXEL ***/
2515                     switch (dtype) {
2516                         case TYPE_INDEX_8:
2517                             destData[dp] = cast(byte) index;
2518                             break;
2519                         case TYPE_INDEX_4:
2520                             if ((dp & 1) !is 0) destData[dp >> 1] = cast(byte)((destData[dp >> 1] & 0xf0) | index);
2521                             else destData[dp >> 1] = cast(byte)((destData[dp >> 1] & 0x0f) | (index << 4));
2522                             break;
2523                         case TYPE_INDEX_2: {
2524                             int shift = 6 - (dp & 3) * 2;
2525                             destData[dp >> 2] = cast(byte)(destData[dp >> 2] & ~(0x03 << shift) | (index << shift));
2526                         } break;
2527                         case TYPE_INDEX_1_MSB: {
2528                             int shift = 7 - (dp & 7);
2529                             destData[dp >> 3] = cast(byte)(destData[dp >> 3] & ~(0x01 << shift) | (index << shift));
2530                         } break;
2531                         case TYPE_INDEX_1_LSB: {
2532                             int shift = dp & 7;
2533                             destData[dp >> 3] = cast(byte)(destData[dp >> 3] & ~(0x01 << shift) | (index << shift));
2534                         } break;
2535                         default:
2536                     }
2537                 }
2538             }
2539         }
2540         return;
2541     }
2542 
2543     /*** Comprehensive blit (apply transformations) ***/
2544     int alpha = alphaMode;
2545     int index = 0;
2546     int indexq = 0;
2547     int lastindex = 0, lastr = -1, lastg = -1, lastb = -1;
2548     int[] rerr, gerr, berr;
2549     if (ditherEnabled) {
2550         rerr = new int[destWidth + 2];
2551         gerr = new int[destWidth + 2];
2552         berr = new int[destWidth + 2];
2553     } else {
2554         rerr = null; gerr = null; berr = null;
2555     }
2556     for (int dy = destHeight, sfy = sfyi; dy > 0; --dy,
2557             sp = spr += (sfy >>> 16) * srcStride,
2558             ap = apr += (sfy >>> 16) * alphaStride,
2559             sfy = (sfy & 0xffff) + sfyi,
2560             dp = dpr += dpryi) {
2561         int lrerr = 0, lgerr = 0, lberr = 0;
2562         for (int dx = destWidth, sfx = sfxi; dx > 0; --dx,
2563                 dp += dprxi,
2564                 sfx = (sfx & 0xffff) + sfxi) {
2565             /*** READ NEXT PIXEL ***/
2566             switch (stype) {
2567                 case TYPE_INDEX_8:
2568                     index = srcData[sp] & 0xff;
2569                     sp += (sfx >>> 16);
2570                     break;
2571                 case TYPE_INDEX_4:
2572                     if ((sp & 1) !is 0) index = srcData[sp >> 1] & 0x0f;
2573                     else index = (srcData[sp >> 1] >>> 4) & 0x0f;
2574                     sp += (sfx >>> 16);
2575                     break;
2576                 case TYPE_INDEX_2:
2577                     index = (srcData[sp >> 2] >>> (6 - (sp & 3) * 2)) & 0x03;
2578                     sp += (sfx >>> 16);
2579                     break;
2580                 case TYPE_INDEX_1_MSB:
2581                     index = (srcData[sp >> 3] >>> (7 - (sp & 7))) & 0x01;
2582                     sp += (sfx >>> 16);
2583                     break;
2584                 case TYPE_INDEX_1_LSB:
2585                     index = (srcData[sp >> 3] >>> (sp & 7)) & 0x01;
2586                     sp += (sfx >>> 16);
2587                     break;
2588                 default:
2589             }
2590 
2591             /*** DO SPECIAL PROCESSING IF REQUIRED ***/
2592             int r = srcReds[index] & 0xff, g = srcGreens[index] & 0xff, b = srcBlues[index] & 0xff;
2593             switch (alphaMode) {
2594                 case ALPHA_CHANNEL_SEPARATE:
2595                     alpha = ((alphaData[ap] & 0xff) << 16) / 255;
2596                     ap += (sfx >> 16);
2597                     break;
2598                 case ALPHA_MASK_UNPACKED:
2599                     alpha = (alphaData[ap] !is 0) ? 0x10000 : 0;
2600                     ap += (sfx >> 16);
2601                     break;
2602                 case ALPHA_MASK_PACKED:
2603                     alpha = (alphaData[ap >> 3] << ((ap & 7) + 9)) & 0x10000;
2604                     ap += (sfx >> 16);
2605                     break;
2606                 case ALPHA_MASK_INDEX: { // could speed up using binary search if we sorted the indices
2607                     int i = 0;
2608                     while (i < alphaData.length) {
2609                         if (index is (alphaData[i] & 0xff)) break;
2610                     }
2611                     if (i < alphaData.length) continue;
2612                 } break;
2613                 case ALPHA_MASK_RGB: {
2614                     int i = 0;
2615                     while (i < alphaData.length) {
2616                         if ((r is (alphaData[i] & 0xff)) &&
2617                             (g is (alphaData[i + 1] & 0xff)) &&
2618                             (b is (alphaData[i + 2] & 0xff))) break;
2619                         i += 3;
2620                     }
2621                     if (i < alphaData.length) continue;
2622                 } break;
2623                 default:
2624             }
2625             if (alpha !is 0x10000) {
2626                 if (alpha is 0x0000) continue;
2627                 switch (dtype) {
2628                     case TYPE_INDEX_8:
2629                         indexq = destData[dp] & 0xff;
2630                         break;
2631                     case TYPE_INDEX_4:
2632                         if ((dp & 1) !is 0) indexq = destData[dp >> 1] & 0x0f;
2633                         else indexq = (destData[dp >> 1] >>> 4) & 0x0f;
2634                         break;
2635                     case TYPE_INDEX_2:
2636                         indexq = (destData[dp >> 2] >>> (6 - (dp & 3) * 2)) & 0x03;
2637                         break;
2638                     case TYPE_INDEX_1_MSB:
2639                         indexq = (destData[dp >> 3] >>> (7 - (dp & 7))) & 0x01;
2640                         break;
2641                     case TYPE_INDEX_1_LSB:
2642                         indexq = (destData[dp >> 3] >>> (dp & 7)) & 0x01;
2643                         break;
2644                     default:
2645                 }
2646                 // Perform alpha blending
2647                 int rq = destReds[indexq] & 0xff;
2648                 int gq = destGreens[indexq] & 0xff;
2649                 int bq = destBlues[indexq] & 0xff;
2650                 r = rq + ((r - rq) * alpha >> 16);
2651                 g = gq + ((g - gq) * alpha >> 16);
2652                 b = bq + ((b - bq) * alpha >> 16);
2653             }
2654 
2655             /*** MAP COLOR TO THE PALETTE ***/
2656             if (ditherEnabled) {
2657                 // Floyd-Steinberg error diffusion
2658                 r += rerr[dx] >> 4;
2659                 if (r < 0) r = 0; else if (r > 255) r = 255;
2660                 g += gerr[dx] >> 4;
2661                 if (g < 0) g = 0; else if (g > 255) g = 255;
2662                 b += berr[dx] >> 4;
2663                 if (b < 0) b = 0; else if (b > 255) b = 255;
2664                 rerr[dx] = lrerr;
2665                 gerr[dx] = lgerr;
2666                 berr[dx] = lberr;
2667             }
2668             if (r !is lastr || g !is lastg || b !is lastb) {
2669                 // moving the variable declarations out seems to make the JDK JIT happier...
2670                 for (int j = 0, dr, dg, db, distance, minDistance = 0x7fffffff; j < destPaletteSize; ++j) {
2671                     dr = (destReds[j] & 0xff) - r;
2672                     dg = (destGreens[j] & 0xff) - g;
2673                     db = (destBlues[j] & 0xff) - b;
2674                     distance = dr * dr + dg * dg + db * db;
2675                     if (distance < minDistance) {
2676                         lastindex = j;
2677                         if (distance is 0) break;
2678                         minDistance = distance;
2679                     }
2680                 }
2681                 lastr = r; lastg = g; lastb = b;
2682             }
2683             if (ditherEnabled) {
2684                 // Floyd-Steinberg error diffusion, cont'd...
2685                 int dxm1 = dx - 1, dxp1 = dx + 1;
2686                 int acc;
2687                 rerr[dxp1] += acc = (lrerr = r - (destReds[lastindex] & 0xff)) + lrerr + lrerr;
2688                 rerr[dx] += acc += lrerr + lrerr;
2689                 rerr[dxm1] += acc + lrerr + lrerr;
2690                 gerr[dxp1] += acc = (lgerr = g - (destGreens[lastindex] & 0xff)) + lgerr + lgerr;
2691                 gerr[dx] += acc += lgerr + lgerr;
2692                 gerr[dxm1] += acc + lgerr + lgerr;
2693                 berr[dxp1] += acc = (lberr = b - (destBlues[lastindex] & 0xff)) + lberr + lberr;
2694                 berr[dx] += acc += lberr + lberr;
2695                 berr[dxm1] += acc + lberr + lberr;
2696             }
2697 
2698             /*** WRITE NEXT PIXEL ***/
2699             switch (dtype) {
2700                 case TYPE_INDEX_8:
2701                     destData[dp] = cast(byte) lastindex;
2702                     break;
2703                 case TYPE_INDEX_4:
2704                     if ((dp & 1) !is 0) destData[dp >> 1] = cast(byte)((destData[dp >> 1] & 0xf0) | lastindex);
2705                     else destData[dp >> 1] = cast(byte)((destData[dp >> 1] & 0x0f) | (lastindex << 4));
2706                     break;
2707                 case TYPE_INDEX_2: {
2708                     int shift = 6 - (dp & 3) * 2;
2709                     destData[dp >> 2] = cast(byte)(destData[dp >> 2] & ~(0x03 << shift) | (lastindex << shift));
2710                 } break;
2711                 case TYPE_INDEX_1_MSB: {
2712                     int shift = 7 - (dp & 7);
2713                     destData[dp >> 3] = cast(byte)(destData[dp >> 3] & ~(0x01 << shift) | (lastindex << shift));
2714                 } break;
2715                 case TYPE_INDEX_1_LSB: {
2716                     int shift = dp & 7;
2717                     destData[dp >> 3] = cast(byte)(destData[dp >> 3] & ~(0x01 << shift) | (lastindex << shift));
2718                 } break;
2719                 default:
2720             }
2721         }
2722     }
2723 }
2724 
2725 /**
2726  * Blits an index palette image into a direct palette image.
2727  * <p>
2728  * Note: The source and destination masks and palettes must
2729  * always be fully specified.
2730  * </p>
2731  *
2732  * @param op the blitter operation: a combination of BLIT_xxx flags
2733  *        (see BLIT_xxx constants)
2734  * @param srcData the source byte array containing image data
2735  * @param srcDepth the source depth: one of 1, 2, 4, 8
2736  * @param srcStride the source number of bytes per line
2737  * @param srcOrder the source byte ordering: one of MSB_FIRST or LSB_FIRST;
2738  *        ignored if srcDepth is not 1
2739  * @param srcX the top-left x-coord of the source blit region
2740  * @param srcY the top-left y-coord of the source blit region
2741  * @param srcWidth the width of the source blit region
2742  * @param srcHeight the height of the source blit region
2743  * @param srcReds the source palette red component intensities
2744  * @param srcGreens the source palette green component intensities
2745  * @param srcBlues the source palette blue component intensities
2746  * @param alphaMode the alpha blending or mask mode, may be
2747  *        an integer 0-255 for global alpha; ignored if BLIT_ALPHA
2748  *        not specified in the blitter operations
2749  *        (see ALPHA_MODE_xxx constants)
2750  * @param alphaData the alpha blending or mask data, varies depending
2751  *        on the value of alphaMode and sometimes ignored
2752  * @param alphaStride the alpha data number of bytes per line
2753  * @param alphaX the top-left x-coord of the alpha blit region
2754  * @param alphaY the top-left y-coord of the alpha blit region
2755  * @param destData the destination byte array containing image data
2756  * @param destDepth the destination depth: one of 8, 16, 24, 32
2757  * @param destStride the destination number of bytes per line
2758  * @param destOrder the destination byte ordering: one of MSB_FIRST or LSB_FIRST;
2759  *        ignored if destDepth is not 16 or 32
2760  * @param destX the top-left x-coord of the destination blit region
2761  * @param destY the top-left y-coord of the destination blit region
2762  * @param destWidth the width of the destination blit region
2763  * @param destHeight the height of the destination blit region
2764  * @param destRedMask the destination red channel mask
2765  * @param destGreenMask the destination green channel mask
2766  * @param destBlueMask the destination blue channel mask
2767  * @param flipX if true the resulting image is flipped along the vertical axis
2768  * @param flipY if true the resulting image is flipped along the horizontal axis
2769  */
2770 static void blit(int op,
2771     byte[] srcData, int srcDepth, int srcStride, int srcOrder,
2772     int srcX, int srcY, int srcWidth, int srcHeight,
2773     byte[] srcReds, byte[] srcGreens, byte[] srcBlues,
2774     int alphaMode, byte[] alphaData, int alphaStride, int alphaX, int alphaY,
2775     byte[] destData, int destDepth, int destStride, int destOrder,
2776     int destX, int destY, int destWidth, int destHeight,
2777     int destRedMask, int destGreenMask, int destBlueMask,
2778     bool flipX, bool flipY) {
2779 
2780     static_this();
2781 
2782     if ((destWidth <= 0) || (destHeight <= 0) || (alphaMode is ALPHA_TRANSPARENT)) return;
2783 
2784     // these should be supplied as params later
2785     int destAlphaMask = 0;
2786 
2787     /*** Prepare scaling data ***/
2788     int dwm1 = destWidth - 1;
2789     int sfxi = (dwm1 !is 0) ? cast(int)(((cast(long)srcWidth << 16) - 1) / dwm1) : 0;
2790     int dhm1 = destHeight - 1;
2791     int sfyi = (dhm1 !is 0) ? cast(int)(((cast(long)srcHeight << 16) - 1) / dhm1) : 0;
2792 
2793     /*** Prepare source-related data ***/
2794     int stype;
2795     switch (srcDepth) {
2796         case 8:
2797             stype = TYPE_INDEX_8;
2798             break;
2799         case 4:
2800             srcStride <<= 1;
2801             stype = TYPE_INDEX_4;
2802             break;
2803         case 2:
2804             srcStride <<= 2;
2805             stype = TYPE_INDEX_2;
2806             break;
2807         case 1:
2808             srcStride <<= 3;
2809             stype = (srcOrder is MSB_FIRST) ? TYPE_INDEX_1_MSB : TYPE_INDEX_1_LSB;
2810             break;
2811         default:
2812             //throw new IllegalArgumentException("Invalid source type");
2813             return;
2814     }
2815     int spr = srcY * srcStride + srcX;
2816 
2817     /*** Prepare destination-related data ***/
2818     int dbpp, dtype;
2819     switch (destDepth) {
2820         case 8:
2821             dbpp = 1;
2822             dtype = TYPE_GENERIC_8;
2823             break;
2824         case 16:
2825             dbpp = 2;
2826             dtype = (destOrder is MSB_FIRST) ? TYPE_GENERIC_16_MSB : TYPE_GENERIC_16_LSB;
2827             break;
2828         case 24:
2829             dbpp = 3;
2830             dtype = TYPE_GENERIC_24;
2831             break;
2832         case 32:
2833             dbpp = 4;
2834             dtype = (destOrder is MSB_FIRST) ? TYPE_GENERIC_32_MSB : TYPE_GENERIC_32_LSB;
2835             break;
2836         default:
2837             //throw new IllegalArgumentException("Invalid destination type");
2838             return;
2839     }
2840     int dpr = ((flipY) ? destY + dhm1 : destY) * destStride + ((flipX) ? destX + dwm1 : destX) * dbpp;
2841     int dprxi = (flipX) ? -dbpp : dbpp;
2842     int dpryi = (flipY) ? -destStride : destStride;
2843 
2844     /*** Prepare special processing data ***/
2845     int apr;
2846     if ((op & BLIT_ALPHA) !is 0) {
2847         switch (alphaMode) {
2848             case ALPHA_MASK_UNPACKED:
2849             case ALPHA_CHANNEL_SEPARATE:
2850                 if (alphaData is null) alphaMode = 0x10000;
2851                 apr = alphaY * alphaStride + alphaX;
2852                 break;
2853             case ALPHA_MASK_PACKED:
2854                 if (alphaData is null) alphaMode = 0x10000;
2855                 alphaStride <<= 3;
2856                 apr = alphaY * alphaStride + alphaX;
2857                 break;
2858             case ALPHA_MASK_INDEX:
2859             case ALPHA_MASK_RGB:
2860                 if (alphaData is null) alphaMode = 0x10000;
2861                 apr = 0;
2862                 break;
2863             default:
2864                 alphaMode = (alphaMode << 16) / 255; // prescale
2865                 goto case ALPHA_CHANNEL_SOURCE;
2866             case ALPHA_CHANNEL_SOURCE:
2867                 apr = 0;
2868                 break;
2869         }
2870     } else {
2871         alphaMode = 0x10000;
2872         apr = 0;
2873     }
2874 
2875     /*** Comprehensive blit (apply transformations) ***/
2876     int destRedShift = getChannelShift(destRedMask);
2877     int destRedWidth = getChannelWidth(destRedMask, destRedShift);
2878     byte[] destReds = ANY_TO_EIGHT[destRedWidth];
2879     int destRedPreShift = 8 - destRedWidth;
2880     int destGreenShift = getChannelShift(destGreenMask);
2881     int destGreenWidth = getChannelWidth(destGreenMask, destGreenShift);
2882     byte[] destGreens = ANY_TO_EIGHT[destGreenWidth];
2883     int destGreenPreShift = 8 - destGreenWidth;
2884     int destBlueShift = getChannelShift(destBlueMask);
2885     int destBlueWidth = getChannelWidth(destBlueMask, destBlueShift);
2886     byte[] destBlues = ANY_TO_EIGHT[destBlueWidth];
2887     int destBluePreShift = 8 - destBlueWidth;
2888     int destAlphaShift = getChannelShift(destAlphaMask);
2889     int destAlphaWidth = getChannelWidth(destAlphaMask, destAlphaShift);
2890     byte[] destAlphas = ANY_TO_EIGHT[destAlphaWidth];
2891     int destAlphaPreShift = 8 - destAlphaWidth;
2892 
2893     int dp = dpr;
2894     int sp = spr;
2895     int ap = apr, alpha = alphaMode;
2896     int r = 0, g = 0, b = 0, a = 0, index = 0;
2897     int rq = 0, gq = 0, bq = 0, aq = 0;
2898     for (int dy = destHeight, sfy = sfyi; dy > 0; --dy,
2899             sp = spr += (sfy >>> 16) * srcStride,
2900             ap = apr += (sfy >>> 16) * alphaStride,
2901             sfy = (sfy & 0xffff) + sfyi,
2902             dp = dpr += dpryi) {
2903         for (int dx = destWidth, sfx = sfxi; dx > 0; --dx,
2904                 dp += dprxi,
2905                 sfx = (sfx & 0xffff) + sfxi) {
2906             /*** READ NEXT PIXEL ***/
2907             switch (stype) {
2908                 case TYPE_INDEX_8:
2909                     index = srcData[sp] & 0xff;
2910                     sp += (sfx >>> 16);
2911                     break;
2912                 case TYPE_INDEX_4:
2913                     if ((sp & 1) !is 0) index = srcData[sp >> 1] & 0x0f;
2914                     else index = (srcData[sp >> 1] >>> 4) & 0x0f;
2915                     sp += (sfx >>> 16);
2916                     break;
2917                 case TYPE_INDEX_2:
2918                     index = (srcData[sp >> 2] >>> (6 - (sp & 3) * 2)) & 0x03;
2919                     sp += (sfx >>> 16);
2920                     break;
2921                 case TYPE_INDEX_1_MSB:
2922                     index = (srcData[sp >> 3] >>> (7 - (sp & 7))) & 0x01;
2923                     sp += (sfx >>> 16);
2924                     break;
2925                 case TYPE_INDEX_1_LSB:
2926                     index = (srcData[sp >> 3] >>> (sp & 7)) & 0x01;
2927                     sp += (sfx >>> 16);
2928                     break;
2929                 default:
2930             }
2931 
2932             /*** DO SPECIAL PROCESSING IF REQUIRED ***/
2933             r = srcReds[index] & 0xff;
2934             g = srcGreens[index] & 0xff;
2935             b = srcBlues[index] & 0xff;
2936             switch (alphaMode) {
2937                 case ALPHA_CHANNEL_SEPARATE:
2938                     alpha = ((alphaData[ap] & 0xff) << 16) / 255;
2939                     ap += (sfx >> 16);
2940                     break;
2941                 case ALPHA_MASK_UNPACKED:
2942                     alpha = (alphaData[ap] !is 0) ? 0x10000 : 0;
2943                     ap += (sfx >> 16);
2944                     break;
2945                 case ALPHA_MASK_PACKED:
2946                     alpha = (alphaData[ap >> 3] << ((ap & 7) + 9)) & 0x10000;
2947                     ap += (sfx >> 16);
2948                     break;
2949                 case ALPHA_MASK_INDEX: { // could speed up using binary search if we sorted the indices
2950                     int i = 0;
2951                     while (i < alphaData.length) {
2952                         if (index is (alphaData[i] & 0xff)) break;
2953                     }
2954                     if (i < alphaData.length) continue;
2955                 } break;
2956                 case ALPHA_MASK_RGB: {
2957                     int i = 0;
2958                     while (i < alphaData.length) {
2959                         if ((r is (alphaData[i] & 0xff)) &&
2960                             (g is (alphaData[i + 1] & 0xff)) &&
2961                             (b is (alphaData[i + 2] & 0xff))) break;
2962                         i += 3;
2963                     }
2964                     if (i < alphaData.length) continue;
2965                 } break;
2966                 default:
2967             }
2968             if (alpha !is 0x10000) {
2969                 if (alpha is 0x0000) continue;
2970                 switch (dtype) {
2971                     case TYPE_GENERIC_8: {
2972                         int data = destData[dp] & 0xff;
2973                         rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
2974                         gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
2975                         bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
2976                         aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
2977                     } break;
2978                     case TYPE_GENERIC_16_MSB: {
2979                         int data = ((destData[dp] & 0xff) << 8) | (destData[dp + 1] & 0xff);
2980                         rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
2981                         gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
2982                         bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
2983                         aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
2984                     } break;
2985                     case TYPE_GENERIC_16_LSB: {
2986                         int data = ((destData[dp + 1] & 0xff) << 8) | (destData[dp] & 0xff);
2987                         rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
2988                         gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
2989                         bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
2990                         aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
2991                     } break;
2992                     case TYPE_GENERIC_24: {
2993                         int data = (( ((destData[dp] & 0xff) << 8) |
2994                             (destData[dp + 1] & 0xff)) << 8) |
2995                             (destData[dp + 2] & 0xff);
2996                         rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
2997                         gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
2998                         bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
2999                         aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
3000                     } break;
3001                     case TYPE_GENERIC_32_MSB: {
3002                         int data = (( (( ((destData[dp] & 0xff) << 8) |
3003                             (destData[dp + 1] & 0xff)) << 8) |
3004                             (destData[dp + 2] & 0xff)) << 8) |
3005                             (destData[dp + 3] & 0xff);
3006                         rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
3007                         gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
3008                         bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
3009                         aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
3010                     } break;
3011                     case TYPE_GENERIC_32_LSB: {
3012                         int data = (( (( ((destData[dp + 3] & 0xff) << 8) |
3013                             (destData[dp + 2] & 0xff)) << 8) |
3014                             (destData[dp + 1] & 0xff)) << 8) |
3015                             (destData[dp] & 0xff);
3016                         rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
3017                         gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
3018                         bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
3019                         aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
3020                     } break;
3021                     default:
3022                 }
3023                 // Perform alpha blending
3024                 a = aq + ((a - aq) * alpha >> 16);
3025                 r = rq + ((r - rq) * alpha >> 16);
3026                 g = gq + ((g - gq) * alpha >> 16);
3027                 b = bq + ((b - bq) * alpha >> 16);
3028             }
3029 
3030             /*** WRITE NEXT PIXEL ***/
3031             int data =
3032                 (r >>> destRedPreShift << destRedShift) |
3033                 (g >>> destGreenPreShift << destGreenShift) |
3034                 (b >>> destBluePreShift << destBlueShift) |
3035                 (a >>> destAlphaPreShift << destAlphaShift);
3036             switch (dtype) {
3037                 case TYPE_GENERIC_8: {
3038                     destData[dp] = cast(byte) data;
3039                 } break;
3040                 case TYPE_GENERIC_16_MSB: {
3041                     destData[dp] = cast(byte) (data >>> 8);
3042                     destData[dp + 1] = cast(byte) (data & 0xff);
3043                 } break;
3044                 case TYPE_GENERIC_16_LSB: {
3045                     destData[dp] = cast(byte) (data & 0xff);
3046                     destData[dp + 1] = cast(byte) (data >>> 8);
3047                 } break;
3048                 case TYPE_GENERIC_24: {
3049                     destData[dp] = cast(byte) (data >>> 16);
3050                     destData[dp + 1] = cast(byte) (data >>> 8);
3051                     destData[dp + 2] = cast(byte) (data & 0xff);
3052                 } break;
3053                 case TYPE_GENERIC_32_MSB: {
3054                     destData[dp] = cast(byte) (data >>> 24);
3055                     destData[dp + 1] = cast(byte) (data >>> 16);
3056                     destData[dp + 2] = cast(byte) (data >>> 8);
3057                     destData[dp + 3] = cast(byte) (data & 0xff);
3058                 } break;
3059                 case TYPE_GENERIC_32_LSB: {
3060                     destData[dp] = cast(byte) (data & 0xff);
3061                     destData[dp + 1] = cast(byte) (data >>> 8);
3062                     destData[dp + 2] = cast(byte) (data >>> 16);
3063                     destData[dp + 3] = cast(byte) (data >>> 24);
3064                 } break;
3065                 default:
3066             }
3067         }
3068     }
3069 }
3070 
3071 /**
3072  * Blits a direct palette image into an index palette image.
3073  * <p>
3074  * Note: The source and destination masks and palettes must
3075  * always be fully specified.
3076  * </p>
3077  *
3078  * @param op the blitter operation: a combination of BLIT_xxx flags
3079  *        (see BLIT_xxx constants)
3080  * @param srcData the source byte array containing image data
3081  * @param srcDepth the source depth: one of 8, 16, 24, 32
3082  * @param srcStride the source number of bytes per line
3083  * @param srcOrder the source byte ordering: one of MSB_FIRST or LSB_FIRST;
3084  *        ignored if srcDepth is not 16 or 32
3085  * @param srcX the top-left x-coord of the source blit region
3086  * @param srcY the top-left y-coord of the source blit region
3087  * @param srcWidth the width of the source blit region
3088  * @param srcHeight the height of the source blit region
3089  * @param srcRedMask the source red channel mask
3090  * @param srcGreenMask the source green channel mask
3091  * @param srcBlueMask the source blue channel mask
3092  * @param alphaMode the alpha blending or mask mode, may be
3093  *        an integer 0-255 for global alpha; ignored if BLIT_ALPHA
3094  *        not specified in the blitter operations
3095  *        (see ALPHA_MODE_xxx constants)
3096  * @param alphaData the alpha blending or mask data, varies depending
3097  *        on the value of alphaMode and sometimes ignored
3098  * @param alphaStride the alpha data number of bytes per line
3099  * @param alphaX the top-left x-coord of the alpha blit region
3100  * @param alphaY the top-left y-coord of the alpha blit region
3101  * @param destData the destination byte array containing image data
3102  * @param destDepth the destination depth: one of 1, 2, 4, 8
3103  * @param destStride the destination number of bytes per line
3104  * @param destOrder the destination byte ordering: one of MSB_FIRST or LSB_FIRST;
3105  *        ignored if destDepth is not 1
3106  * @param destX the top-left x-coord of the destination blit region
3107  * @param destY the top-left y-coord of the destination blit region
3108  * @param destWidth the width of the destination blit region
3109  * @param destHeight the height of the destination blit region
3110  * @param destReds the destination palette red component intensities
3111  * @param destGreens the destination palette green component intensities
3112  * @param destBlues the destination palette blue component intensities
3113  * @param flipX if true the resulting image is flipped along the vertical axis
3114  * @param flipY if true the resulting image is flipped along the horizontal axis
3115  */
3116 static void blit(int op,
3117     byte[] srcData, int srcDepth, int srcStride, int srcOrder,
3118     int srcX, int srcY, int srcWidth, int srcHeight,
3119     int srcRedMask, int srcGreenMask, int srcBlueMask,
3120     int alphaMode, byte[] alphaData, int alphaStride, int alphaX, int alphaY,
3121     byte[] destData, int destDepth, int destStride, int destOrder,
3122     int destX, int destY, int destWidth, int destHeight,
3123     byte[] destReds, byte[] destGreens, byte[] destBlues,
3124     bool flipX, bool flipY) {
3125 
3126     static_this();
3127 
3128     if ((destWidth <= 0) || (destHeight <= 0) || (alphaMode is ALPHA_TRANSPARENT)) return;
3129 
3130     // these should be supplied as params later
3131     int srcAlphaMask = 0;
3132 
3133     /*** Prepare scaling data ***/
3134     int dwm1 = destWidth - 1;
3135     int sfxi = (dwm1 !is 0) ? cast(int)(((cast(long)srcWidth << 16) - 1) / dwm1) : 0;
3136     int dhm1 = destHeight - 1;
3137     int sfyi = (dhm1 !is 0) ? cast(int)(((cast(long)srcHeight << 16) - 1) / dhm1) : 0;
3138 
3139     /*** Prepare source-related data ***/
3140     int sbpp, stype;
3141     switch (srcDepth) {
3142         case 8:
3143             sbpp = 1;
3144             stype = TYPE_GENERIC_8;
3145             break;
3146         case 16:
3147             sbpp = 2;
3148             stype = (srcOrder is MSB_FIRST) ? TYPE_GENERIC_16_MSB : TYPE_GENERIC_16_LSB;
3149             break;
3150         case 24:
3151             sbpp = 3;
3152             stype = TYPE_GENERIC_24;
3153             break;
3154         case 32:
3155             sbpp = 4;
3156             stype = (srcOrder is MSB_FIRST) ? TYPE_GENERIC_32_MSB : TYPE_GENERIC_32_LSB;
3157             break;
3158         default:
3159             //throw new IllegalArgumentException("Invalid source type");
3160             return;
3161     }
3162     int spr = srcY * srcStride + srcX * sbpp;
3163 
3164     /*** Prepare destination-related data ***/
3165     int dtype;
3166     switch (destDepth) {
3167         case 8:
3168             dtype = TYPE_INDEX_8;
3169             break;
3170         case 4:
3171             destStride <<= 1;
3172             dtype = TYPE_INDEX_4;
3173             break;
3174         case 2:
3175             destStride <<= 2;
3176             dtype = TYPE_INDEX_2;
3177             break;
3178         case 1:
3179             destStride <<= 3;
3180             dtype = (destOrder is MSB_FIRST) ? TYPE_INDEX_1_MSB : TYPE_INDEX_1_LSB;
3181             break;
3182         default:
3183             //throw new IllegalArgumentException("Invalid source type");
3184             return;
3185     }
3186     int dpr = ((flipY) ? destY + dhm1 : destY) * destStride + ((flipX) ? destX + dwm1 : destX);
3187     int dprxi = (flipX) ? -1 : 1;
3188     int dpryi = (flipY) ? -destStride : destStride;
3189 
3190     /*** Prepare special processing data ***/
3191     int apr;
3192     if ((op & BLIT_ALPHA) !is 0) {
3193         switch (alphaMode) {
3194             case ALPHA_MASK_UNPACKED:
3195             case ALPHA_CHANNEL_SEPARATE:
3196                 if (alphaData is null) alphaMode = 0x10000;
3197                 apr = alphaY * alphaStride + alphaX;
3198                 break;
3199             case ALPHA_MASK_PACKED:
3200                 if (alphaData is null) alphaMode = 0x10000;
3201                 alphaStride <<= 3;
3202                 apr = alphaY * alphaStride + alphaX;
3203                 break;
3204             case ALPHA_MASK_INDEX:
3205                 //throw new IllegalArgumentException("Invalid alpha type");
3206                 return;
3207             case ALPHA_MASK_RGB:
3208                 if (alphaData is null) alphaMode = 0x10000;
3209                 apr = 0;
3210                 break;
3211             default:
3212                 alphaMode = (alphaMode << 16) / 255; // prescale
3213                 goto case ALPHA_CHANNEL_SOURCE;
3214             case ALPHA_CHANNEL_SOURCE:
3215                 apr = 0;
3216                 break;
3217         }
3218     } else {
3219         alphaMode = 0x10000;
3220         apr = 0;
3221     }
3222     bool ditherEnabled = (op & BLIT_DITHER) !is 0;
3223 
3224     /*** Comprehensive blit (apply transformations) ***/
3225     int srcRedShift = getChannelShift(srcRedMask);
3226     byte[] srcReds = ANY_TO_EIGHT[getChannelWidth(srcRedMask, srcRedShift)];
3227     int srcGreenShift = getChannelShift(srcGreenMask);
3228     byte[] srcGreens = ANY_TO_EIGHT[getChannelWidth(srcGreenMask, srcGreenShift)];
3229     int srcBlueShift = getChannelShift(srcBlueMask);
3230     byte[] srcBlues = ANY_TO_EIGHT[getChannelWidth(srcBlueMask, srcBlueShift)];
3231     int srcAlphaShift = getChannelShift(srcAlphaMask);
3232     byte[] srcAlphas = ANY_TO_EIGHT[getChannelWidth(srcAlphaMask, srcAlphaShift)];
3233 
3234     int dp = dpr;
3235     int sp = spr;
3236     int ap = apr, alpha = alphaMode;
3237     int r = 0, g = 0, b = 0, a = 0;
3238     int indexq = 0;
3239     int lastindex = 0, lastr = -1, lastg = -1, lastb = -1;
3240     int[] rerr, gerr, berr;
3241     int destPaletteSize = 1 << destDepth;
3242     if ((destReds !is null) && (destReds.length < destPaletteSize))
3243         destPaletteSize = cast(int)/*64bit*/destReds.length;
3244     if (ditherEnabled) {
3245         rerr = new int[destWidth + 2];
3246         gerr = new int[destWidth + 2];
3247         berr = new int[destWidth + 2];
3248     } else {
3249         rerr = null; gerr = null; berr = null;
3250     }
3251     for (int dy = destHeight, sfy = sfyi; dy > 0; --dy,
3252             sp = spr += (sfy >>> 16) * srcStride,
3253             ap = apr += (sfy >>> 16) * alphaStride,
3254             sfy = (sfy & 0xffff) + sfyi,
3255             dp = dpr += dpryi) {
3256         int lrerr = 0, lgerr = 0, lberr = 0;
3257         for (int dx = destWidth, sfx = sfxi; dx > 0; --dx,
3258                 dp += dprxi,
3259                 sfx = (sfx & 0xffff) + sfxi) {
3260             /*** READ NEXT PIXEL ***/
3261             switch (stype) {
3262                 case TYPE_GENERIC_8: {
3263                     int data = srcData[sp] & 0xff;
3264                     sp += (sfx >>> 16);
3265                     r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
3266                     g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
3267                     b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
3268                     a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
3269                 } break;
3270                 case TYPE_GENERIC_16_MSB: {
3271                     int data = ((srcData[sp] & 0xff) << 8) | (srcData[sp + 1] & 0xff);
3272                     sp += (sfx >>> 16) * 2;
3273                     r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
3274                     g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
3275                     b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
3276                     a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
3277                 } break;
3278                 case TYPE_GENERIC_16_LSB: {
3279                     int data = ((srcData[sp + 1] & 0xff) << 8) | (srcData[sp] & 0xff);
3280                     sp += (sfx >>> 16) * 2;
3281                     r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
3282                     g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
3283                     b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
3284                     a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
3285                 } break;
3286                 case TYPE_GENERIC_24: {
3287                     int data = (( ((srcData[sp] & 0xff) << 8) |
3288                         (srcData[sp + 1] & 0xff)) << 8) |
3289                         (srcData[sp + 2] & 0xff);
3290                     sp += (sfx >>> 16) * 3;
3291                     r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
3292                     g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
3293                     b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
3294                     a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
3295                 } break;
3296                 case TYPE_GENERIC_32_MSB: {
3297                     int data = (( (( ((srcData[sp] & 0xff) << 8) |
3298                         (srcData[sp + 1] & 0xff)) << 8) |
3299                         (srcData[sp + 2] & 0xff)) << 8) |
3300                         (srcData[sp + 3] & 0xff);
3301                     sp += (sfx >>> 16) * 4;
3302                     r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
3303                     g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
3304                     b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
3305                     a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
3306                 } break;
3307                 case TYPE_GENERIC_32_LSB: {
3308                     int data = (( (( ((srcData[sp + 3] & 0xff) << 8) |
3309                         (srcData[sp + 2] & 0xff)) << 8) |
3310                         (srcData[sp + 1] & 0xff)) << 8) |
3311                         (srcData[sp] & 0xff);
3312                     sp += (sfx >>> 16) * 4;
3313                     r = srcReds[(data & srcRedMask) >>> srcRedShift] & 0xff;
3314                     g = srcGreens[(data & srcGreenMask) >>> srcGreenShift] & 0xff;
3315                     b = srcBlues[(data & srcBlueMask) >>> srcBlueShift] & 0xff;
3316                     a = srcAlphas[(data & srcAlphaMask) >>> srcAlphaShift] & 0xff;
3317                 } break;
3318                 default:
3319             }
3320 
3321             /*** DO SPECIAL PROCESSING IF REQUIRED ***/
3322             switch (alphaMode) {
3323                 case ALPHA_CHANNEL_SEPARATE:
3324                     alpha = ((alphaData[ap] & 0xff) << 16) / 255;
3325                     ap += (sfx >> 16);
3326                     break;
3327                 case ALPHA_CHANNEL_SOURCE:
3328                     alpha = (a << 16) / 255;
3329                     break;
3330                 case ALPHA_MASK_UNPACKED:
3331                     alpha = (alphaData[ap] !is 0) ? 0x10000 : 0;
3332                     ap += (sfx >> 16);
3333                     break;
3334                 case ALPHA_MASK_PACKED:
3335                     alpha = (alphaData[ap >> 3] << ((ap & 7) + 9)) & 0x10000;
3336                     ap += (sfx >> 16);
3337                     break;
3338                 case ALPHA_MASK_RGB:
3339                     alpha = 0x10000;
3340                     for (int i = 0; i < alphaData.length; i += 3) {
3341                         if ((r is alphaData[i]) && (g is alphaData[i + 1]) && (b is alphaData[i + 2])) {
3342                             alpha = 0x0000;
3343                             break;
3344                         }
3345                     }
3346                     break;
3347                 default:
3348             }
3349             if (alpha !is 0x10000) {
3350                 if (alpha is 0x0000) continue;
3351                 switch (dtype) {
3352                     case TYPE_INDEX_8:
3353                         indexq = destData[dp] & 0xff;
3354                         break;
3355                     case TYPE_INDEX_4:
3356                         if ((dp & 1) !is 0) indexq = destData[dp >> 1] & 0x0f;
3357                         else indexq = (destData[dp >> 1] >>> 4) & 0x0f;
3358                         break;
3359                     case TYPE_INDEX_2:
3360                         indexq = (destData[dp >> 2] >>> (6 - (dp & 3) * 2)) & 0x03;
3361                         break;
3362                     case TYPE_INDEX_1_MSB:
3363                         indexq = (destData[dp >> 3] >>> (7 - (dp & 7))) & 0x01;
3364                         break;
3365                     case TYPE_INDEX_1_LSB:
3366                         indexq = (destData[dp >> 3] >>> (dp & 7)) & 0x01;
3367                         break;
3368                     default:
3369                 }
3370                 // Perform alpha blending
3371                 int rq = destReds[indexq] & 0xff;
3372                 int gq = destGreens[indexq] & 0xff;
3373                 int bq = destBlues[indexq] & 0xff;
3374                 r = rq + ((r - rq) * alpha >> 16);
3375                 g = gq + ((g - gq) * alpha >> 16);
3376                 b = bq + ((b - bq) * alpha >> 16);
3377             }
3378 
3379             /*** MAP COLOR TO THE PALETTE ***/
3380             if (ditherEnabled) {
3381                 // Floyd-Steinberg error diffusion
3382                 r += rerr[dx] >> 4;
3383                 if (r < 0) r = 0; else if (r > 255) r = 255;
3384                 g += gerr[dx] >> 4;
3385                 if (g < 0) g = 0; else if (g > 255) g = 255;
3386                 b += berr[dx] >> 4;
3387                 if (b < 0) b = 0; else if (b > 255) b = 255;
3388                 rerr[dx] = lrerr;
3389                 gerr[dx] = lgerr;
3390                 berr[dx] = lberr;
3391             }
3392             if (r !is lastr || g !is lastg || b !is lastb) {
3393                 // moving the variable declarations out seems to make the JDK JIT happier...
3394                 for (int j = 0, dr, dg, db, distance, minDistance = 0x7fffffff; j < destPaletteSize; ++j) {
3395                     dr = (destReds[j] & 0xff) - r;
3396                     dg = (destGreens[j] & 0xff) - g;
3397                     db = (destBlues[j] & 0xff) - b;
3398                     distance = dr * dr + dg * dg + db * db;
3399                     if (distance < minDistance) {
3400                         lastindex = j;
3401                         if (distance is 0) break;
3402                         minDistance = distance;
3403                     }
3404                 }
3405                 lastr = r; lastg = g; lastb = b;
3406             }
3407             if (ditherEnabled) {
3408                 // Floyd-Steinberg error diffusion, cont'd...
3409                 int dxm1 = dx - 1, dxp1 = dx + 1;
3410                 int acc;
3411                 rerr[dxp1] += acc = (lrerr = r - (destReds[lastindex] & 0xff)) + lrerr + lrerr;
3412                 rerr[dx] += acc += lrerr + lrerr;
3413                 rerr[dxm1] += acc + lrerr + lrerr;
3414                 gerr[dxp1] += acc = (lgerr = g - (destGreens[lastindex] & 0xff)) + lgerr + lgerr;
3415                 gerr[dx] += acc += lgerr + lgerr;
3416                 gerr[dxm1] += acc + lgerr + lgerr;
3417                 berr[dxp1] += acc = (lberr = b - (destBlues[lastindex] & 0xff)) + lberr + lberr;
3418                 berr[dx] += acc += lberr + lberr;
3419                 berr[dxm1] += acc + lberr + lberr;
3420             }
3421 
3422             /*** WRITE NEXT PIXEL ***/
3423             switch (dtype) {
3424                 case TYPE_INDEX_8:
3425                     destData[dp] = cast(byte) lastindex;
3426                     break;
3427                 case TYPE_INDEX_4:
3428                     if ((dp & 1) !is 0) destData[dp >> 1] = cast(byte)((destData[dp >> 1] & 0xf0) | lastindex);
3429                     else destData[dp >> 1] = cast(byte)((destData[dp >> 1] & 0x0f) | (lastindex << 4));
3430                     break;
3431                 case TYPE_INDEX_2: {
3432                     int shift = 6 - (dp & 3) * 2;
3433                     destData[dp >> 2] = cast(byte)(destData[dp >> 2] & ~(0x03 << shift) | (lastindex << shift));
3434                 } break;
3435                 case TYPE_INDEX_1_MSB: {
3436                     int shift = 7 - (dp & 7);
3437                     destData[dp >> 3] = cast(byte)(destData[dp >> 3] & ~(0x01 << shift) | (lastindex << shift));
3438                 } break;
3439                 case TYPE_INDEX_1_LSB: {
3440                     int shift = dp & 7;
3441                     destData[dp >> 3] = cast(byte)(destData[dp >> 3] & ~(0x01 << shift) | (lastindex << shift));
3442                 } break;
3443                 default:
3444             }
3445         }
3446     }
3447 }
3448 
3449 /**
3450  * Computes the required channel shift from a mask.
3451  */
3452 static int getChannelShift(int mask) {
3453     if (mask is 0) return 0;
3454     int i;
3455     for (i = 0; ((mask & 1) is 0) && (i < 32); ++i) {
3456         mask >>>= 1;
3457     }
3458     return i;
3459 }
3460 
3461 /**
3462  * Computes the required channel width (depth) from a mask.
3463  */
3464 static int getChannelWidth(int mask, int shift) {
3465     if (mask is 0) return 0;
3466     int i;
3467     mask >>>= shift;
3468     for (i = shift; ((mask & 1) !is 0) && (i < 32); ++i) {
3469         mask >>>= 1;
3470     }
3471     return i - shift;
3472 }
3473 
3474 /**
3475  * Extracts a field from packed RGB data given a mask for that field.
3476  */
3477 static byte getChannelField(int data, int mask) {
3478     static_this();
3479     int shift = getChannelShift(mask);
3480     return ANY_TO_EIGHT[getChannelWidth(mask, shift)][(data & mask) >>> shift];
3481 }
3482 
3483 /**
3484  * Creates an ImageData containing one band's worth of a gradient filled
3485  * block.  If <code>vertical</code> is true, the band must be tiled
3486  * horizontally to fill a region, otherwise it must be tiled vertically.
3487  *
3488  * @param width the width of the region to be filled
3489  * @param height the height of the region to be filled
3490  * @param vertical if true sweeps from top to bottom, else
3491  *        sweeps from left to right
3492  * @param fromRGB the color to start with
3493  * @param toRGB the color to end with
3494  * @param redBits the number of significant red bits, 0 for palette modes
3495  * @param greenBits the number of significant green bits, 0 for palette modes
3496  * @param blueBits the number of significant blue bits, 0 for palette modes
3497  * @return the new ImageData
3498  */
3499 static ImageData createGradientBand(
3500     int width, int height, bool vertical,
3501     RGB fromRGB, RGB toRGB,
3502     int redBits, int greenBits, int blueBits) {
3503     /* Gradients are drawn as tiled bands */
3504     int bandWidth, bandHeight, bitmapDepth;
3505     byte[] bitmapData;
3506     PaletteData paletteData;
3507     /* Select an algorithm depending on the depth of the screen */
3508     if (redBits !is 0 && greenBits !is 0 && blueBits !is 0) {
3509         paletteData = new PaletteData(0x0000ff00, 0x00ff0000, 0xff000000);
3510         bitmapDepth = 32;
3511         if (redBits >= 8 && greenBits >= 8 && blueBits >= 8) {
3512             /* Precise color */
3513             int steps;
3514             if (vertical) {
3515                 bandWidth = 1;
3516                 bandHeight = height;
3517                 steps = bandHeight > 1 ? bandHeight - 1 : 1;
3518             } else {
3519                 bandWidth = width;
3520                 bandHeight = 1;
3521                 steps = bandWidth > 1 ? bandWidth - 1 : 1;
3522             }
3523             int bytesPerLine = bandWidth * 4;
3524             bitmapData = new byte[bandHeight * bytesPerLine];
3525             buildPreciseGradientChannel(fromRGB.blue, toRGB.blue, steps, bandWidth, bandHeight, vertical, bitmapData, 0, bytesPerLine);
3526             buildPreciseGradientChannel(fromRGB.green, toRGB.green, steps, bandWidth, bandHeight, vertical, bitmapData, 1, bytesPerLine);
3527             buildPreciseGradientChannel(fromRGB.red, toRGB.red, steps, bandWidth, bandHeight, vertical, bitmapData, 2, bytesPerLine);
3528         } else {
3529             /* Dithered color */
3530             int steps;
3531             if (vertical) {
3532                 bandWidth = (width < 8) ? width : 8;
3533                 bandHeight = height;
3534                 steps = bandHeight > 1 ? bandHeight - 1 : 1;
3535             } else {
3536                 bandWidth = width;
3537                 bandHeight = (height < 8) ? height : 8;
3538                 steps = bandWidth > 1 ? bandWidth - 1 : 1;
3539             }
3540             int bytesPerLine = bandWidth * 4;
3541             bitmapData = new byte[bandHeight * bytesPerLine];
3542             buildDitheredGradientChannel(fromRGB.blue, toRGB.blue, steps, bandWidth, bandHeight, vertical, bitmapData, 0, bytesPerLine, blueBits);
3543             buildDitheredGradientChannel(fromRGB.green, toRGB.green, steps, bandWidth, bandHeight, vertical, bitmapData, 1, bytesPerLine, greenBits);
3544             buildDitheredGradientChannel(fromRGB.red, toRGB.red, steps, bandWidth, bandHeight, vertical, bitmapData, 2, bytesPerLine, redBits);
3545         }
3546     } else {
3547         /* Dithered two tone */
3548         paletteData = new PaletteData([ fromRGB, toRGB ]);
3549         bitmapDepth = 8;
3550         int blendi;
3551         if (vertical) {
3552             bandWidth = (width < 8) ? width : 8;
3553             bandHeight = height;
3554             blendi = (bandHeight > 1) ? 0x1040000 / (bandHeight - 1) + 1 : 1;
3555         } else {
3556             bandWidth = width;
3557             bandHeight = (height < 8) ? height : 8;
3558             blendi = (bandWidth > 1) ? 0x1040000 / (bandWidth - 1) + 1 : 1;
3559         }
3560         int bytesPerLine = (bandWidth + 3) & -4;
3561         bitmapData = new byte[bandHeight * bytesPerLine];
3562         if (vertical) {
3563             for (int dy = 0, blend = 0, dp = 0; dy < bandHeight;
3564                 ++dy, blend += blendi, dp += bytesPerLine) {
3565                 for (int dx = 0; dx < bandWidth; ++dx) {
3566                     bitmapData[dp + dx] = (blend + DITHER_MATRIX[dy & 7][dx]) <
3567                         0x1000000 ? cast(byte)0 : cast(byte)1;
3568                 }
3569             }
3570         } else {
3571             for (int dx = 0, blend = 0; dx < bandWidth; ++dx, blend += blendi) {
3572                 for (int dy = 0, dptr = dx; dy < bandHeight; ++dy, dptr += bytesPerLine) {
3573                     bitmapData[dptr] = (blend + DITHER_MATRIX[dy][dx & 7]) <
3574                         0x1000000 ? cast(byte)0 : cast(byte)1;
3575                 }
3576             }
3577         }
3578     }
3579     return new ImageData(bandWidth, bandHeight, bitmapDepth, paletteData, 4, bitmapData);
3580 }
3581 
3582 /*
3583  * Fill in gradated values for a color channel
3584  */
3585 static final void buildPreciseGradientChannel(int from, int to, int steps,
3586     int bandWidth, int bandHeight, bool vertical,
3587     byte[] bitmapData, int dp, int bytesPerLine) {
3588     int val = from << 16;
3589     int inc = ((to << 16) - val) / steps + 1;
3590     if (vertical) {
3591         for (int dy = 0; dy < bandHeight; ++dy, dp += bytesPerLine) {
3592             bitmapData[dp] = cast(byte)(val >>> 16);
3593             val += inc;
3594         }
3595     } else {
3596         for (int dx = 0; dx < bandWidth; ++dx, dp += 4) {
3597             bitmapData[dp] = cast(byte)(val >>> 16);
3598             val += inc;
3599         }
3600     }
3601 }
3602 
3603 /*
3604  * Fill in dithered gradated values for a color channel
3605  */
3606 static final void buildDitheredGradientChannel(int from, int to, int steps,
3607     int bandWidth, int bandHeight, bool vertical,
3608     byte[] bitmapData, int dp, int bytesPerLine, int bits) {
3609     int mask = 0xff00 >>> bits;
3610     int val = from << 16;
3611     int inc = ((to << 16) - val) / steps + 1;
3612     if (vertical) {
3613         for (int dy = 0; dy < bandHeight; ++dy, dp += bytesPerLine) {
3614             for (int dx = 0, dptr = dp; dx < bandWidth; ++dx, dptr += 4) {
3615                 int thresh = DITHER_MATRIX[dy & 7][dx] >>> bits;
3616                 int temp = val + thresh;
3617                 if (temp > 0xffffff) bitmapData[dptr] = -1;
3618                 else bitmapData[dptr] = cast(byte)((temp >>> 16) & mask);
3619             }
3620             val += inc;
3621         }
3622     } else {
3623         for (int dx = 0; dx < bandWidth; ++dx, dp += 4) {
3624             for (int dy = 0, dptr = dp; dy < bandHeight; ++dy, dptr += bytesPerLine) {
3625                 int thresh = DITHER_MATRIX[dy][dx & 7] >>> bits;
3626                 int temp = val + thresh;
3627                 if (temp > 0xffffff) bitmapData[dptr] = -1;
3628                 else bitmapData[dptr] = cast(byte)((temp >>> 16) & mask);
3629             }
3630             val += inc;
3631         }
3632     }
3633 }
3634 
3635 /**
3636  * Renders a gradient onto a GC.
3637  * <p>
3638  * This is a GC helper.
3639  * </p>
3640  *
3641  * @param gc the GC to render the gradient onto
3642  * @param device the device the GC belongs to
3643  * @param x the top-left x coordinate of the region to be filled
3644  * @param y the top-left y coordinate of the region to be filled
3645  * @param width the width of the region to be filled
3646  * @param height the height of the region to be filled
3647  * @param vertical if true sweeps from top to bottom, else
3648  *        sweeps from left to right
3649  * @param fromRGB the color to start with
3650  * @param toRGB the color to end with
3651  * @param redBits the number of significant red bits, 0 for palette modes
3652  * @param greenBits the number of significant green bits, 0 for palette modes
3653  * @param blueBits the number of significant blue bits, 0 for palette modes
3654  */
3655 static void fillGradientRectangle(GC gc, Device device,
3656     int x, int y, int width, int height, bool vertical,
3657     RGB fromRGB, RGB toRGB,
3658     int redBits, int greenBits, int blueBits) {
3659     /* Create the bitmap and tile it */
3660     ImageData band = createGradientBand(width, height, vertical,
3661         fromRGB, toRGB, redBits, greenBits, blueBits);
3662     Image image = new Image(device, band);
3663     if ((band.width is 1) || (band.height is 1)) {
3664         gc.drawImage(image, 0, 0, band.width, band.height, x, y, width, height);
3665     } else {
3666         if (vertical) {
3667             for (int dx = 0; dx < width; dx += band.width) {
3668                 int blitWidth = width - dx;
3669                 if (blitWidth > band.width) blitWidth = band.width;
3670                 gc.drawImage(image, 0, 0, blitWidth, band.height, dx + x, y, blitWidth, band.height);
3671             }
3672         } else {
3673             for (int dy = 0; dy < height; dy += band.height) {
3674                 int blitHeight = height - dy;
3675                 if (blitHeight > band.height) blitHeight = band.height;
3676                 gc.drawImage(image, 0, 0, band.width, blitHeight, x, dy + y, band.width, blitHeight);
3677             }
3678         }
3679     }
3680     image.dispose();
3681 }
3682 
3683 }