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