PageRenderTime 411ms CodeModel.GetById 3ms app.highlight 372ms RepoModel.GetById 1ms app.codeStats 2ms

/src/org/eclipse/swt/graphics/ImageData.d

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