PageRenderTime 84ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 1ms

/dwt/graphics/ImageData.d

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