| 1 |
/******************************************************************************* |
|---|
| 2 |
* Copyright (c) 2000, 2008 IBM Corporation and others. |
|---|
| 3 |
* All rights reserved. This program and the accompanying materials |
|---|
| 4 |
* are made available under the terms of the Eclipse Public License v1.0 |
|---|
| 5 |
* which accompanies this distribution, and is available at |
|---|
| 6 |
* http://www.eclipse.org/legal/epl-v10.html |
|---|
| 7 |
* |
|---|
| 8 |
* Contributors: |
|---|
| 9 |
* IBM Corporation - initial API and implementation |
|---|
| 10 |
* Port to the D programming language: |
|---|
| 11 |
* Frank Benoit <benoit@tionex.de> |
|---|
| 12 |
*******************************************************************************/ |
|---|
| 13 |
module dwt.graphics.ImageData; |
|---|
| 14 |
|
|---|
| 15 |
|
|---|
| 16 |
import dwt.graphics.PaletteData; |
|---|
| 17 |
import dwt.graphics.RGB; |
|---|
| 18 |
import dwt.graphics.Image; |
|---|
| 19 |
import dwt.graphics.GC; |
|---|
| 20 |
import dwt.graphics.Device; |
|---|
| 21 |
import dwt.graphics.ImageDataLoader; |
|---|
| 22 |
import dwt.DWT; |
|---|
| 23 |
import dwt.internal.CloneableCompatibility; |
|---|
| 24 |
|
|---|
| 25 |
public import dwt.dwthelper.InputStream; |
|---|
| 26 |
import dwt.dwthelper.System; |
|---|
| 27 |
import dwt.dwthelper.utils; |
|---|
| 28 |
|
|---|
| 29 |
|
|---|
| 30 |
/** |
|---|
| 31 |
* Instances of this class are device-independent descriptions |
|---|
| 32 |
* of images. They are typically used as an intermediate format |
|---|
| 33 |
* between loading from or writing to streams and creating an |
|---|
| 34 |
* <code>Image</code>. |
|---|
| 35 |
* <p> |
|---|
| 36 |
* Note that the public fields <code>x</code>, <code>y</code>, |
|---|
| 37 |
* <code>disposalMethod</code> and <code>delayTime</code> are |
|---|
| 38 |
* typically only used when the image is in a set of images used |
|---|
| 39 |
* for animation. |
|---|
| 40 |
* </p> |
|---|
| 41 |
* |
|---|
| 42 |
* @see Image |
|---|
| 43 |
* @see ImageLoader |
|---|
| 44 |
* @see <a href="http://www.eclipse.org/swt/snippets/#image">ImageData snippets</a> |
|---|
| 45 |
* @see <a href="http://www.eclipse.org/swt/examples.php">DWT Example: ImageAnalyzer</a> |
|---|
| 46 |
* @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> |
|---|
| 47 |
*/ |
|---|
| 48 |
|
|---|
| 49 |
public final class ImageData : CloneableCompatibility { |
|---|
| 50 |
|
|---|
| 51 |
/** |
|---|
| 52 |
* The width of the image, in pixels. |
|---|
| 53 |
*/ |
|---|
| 54 |
public int width; |
|---|
| 55 |
|
|---|
| 56 |
/** |
|---|
| 57 |
* The height of the image, in pixels. |
|---|
| 58 |
*/ |
|---|
| 59 |
public int height; |
|---|
| 60 |
|
|---|
| 61 |
/** |
|---|
| 62 |
* The color depth of the image, in bits per pixel. |
|---|
| 63 |
* <p> |
|---|
| 64 |
* Note that a depth of 8 or less does not necessarily |
|---|
| 65 |
* mean that the image is palette indexed, or |
|---|
| 66 |
* conversely that a depth greater than 8 means that |
|---|
| 67 |
* the image is direct color. Check the associated |
|---|
| 68 |
* PaletteData's isDirect field for such determinations. |
|---|
| 69 |
*/ |
|---|
| 70 |
public int depth; |
|---|
| 71 |
|
|---|
| 72 |
/** |
|---|
| 73 |
* The scanline padding. |
|---|
| 74 |
* <p> |
|---|
| 75 |
* If one scanline of the image is not a multiple of |
|---|
| 76 |
* this number, it will be padded with zeros until it is. |
|---|
| 77 |
* </p> |
|---|
| 78 |
*/ |
|---|
| 79 |
public int scanlinePad; |
|---|
| 80 |
|
|---|
| 81 |
/** |
|---|
| 82 |
* The number of bytes per scanline. |
|---|
| 83 |
* <p> |
|---|
| 84 |
* This is a multiple of the scanline padding. |
|---|
| 85 |
* </p> |
|---|
| 86 |
*/ |
|---|
| 87 |
public int bytesPerLine; |
|---|
| 88 |
|
|---|
| 89 |
/** |
|---|
| 90 |
* The pixel data of the image. |
|---|
| 91 |
* <p> |
|---|
| 92 |
* Note that for 16 bit depth images the pixel data is stored |
|---|
| 93 |
* in least significant byte order; however, for 24bit and |
|---|
| 94 |
* 32bit depth images the pixel data is stored in most |
|---|
| 95 |
* significant byte order. |
|---|
| 96 |
* </p> |
|---|
| 97 |
*/ |
|---|
| 98 |
public byte[] data; |
|---|
| 99 |
|
|---|
| 100 |
/** |
|---|
| 101 |
* The color table for the image. |
|---|
| 102 |
*/ |
|---|
| 103 |
public PaletteData palette; |
|---|
| 104 |
|
|---|
| 105 |
/** |
|---|
| 106 |
* The transparent pixel. |
|---|
| 107 |
* <p> |
|---|
| 108 |
* Pixels with this value are transparent. |
|---|
| 109 |
* </p><p> |
|---|
| 110 |
* The default is -1 which means 'no transparent pixel'. |
|---|
| 111 |
* </p> |
|---|
| 112 |
*/ |
|---|
| 113 |
public int transparentPixel; |
|---|
| 114 |
|
|---|
| 115 |
/** |
|---|
| 116 |
* An icon-specific field containing the data from the icon mask. |
|---|
| 117 |
* <p> |
|---|
| 118 |
* This is a 1 bit bitmap stored with the most significant |
|---|
| 119 |
* bit first. The number of bytes per scanline is |
|---|
| 120 |
* '((width + 7) / 8 + (maskPad - 1)) / maskPad * maskPad'. |
|---|
| 121 |
* </p><p> |
|---|
| 122 |
* The default is null which means 'no transparency mask'. |
|---|
| 123 |
* </p> |
|---|
| 124 |
*/ |
|---|
| 125 |
public byte[] maskData; |
|---|
| 126 |
|
|---|
| 127 |
/** |
|---|
| 128 |
* An icon-specific field containing the scanline pad of the mask. |
|---|
| 129 |
* <p> |
|---|
| 130 |
* If one scanline of the transparency mask is not a |
|---|
| 131 |
* multiple of this number, it will be padded with zeros until |
|---|
| 132 |
* it is. |
|---|
| 133 |
* </p> |
|---|
| 134 |
*/ |
|---|
| 135 |
public int maskPad; |
|---|
| 136 |
|
|---|
| 137 |
/** |
|---|
| 138 |
* The alpha data of the image. |
|---|
| 139 |
* <p> |
|---|
| 140 |
* Every pixel can have an <em>alpha blending</em> value that |
|---|
| 141 |
* varies from 0, meaning fully transparent, to 255 meaning |
|---|
| 142 |
* fully opaque. The number of bytes per scanline is |
|---|
| 143 |
* 'width'. |
|---|
| 144 |
* </p> |
|---|
| 145 |
*/ |
|---|
| 146 |
public byte[] alphaData; |
|---|
| 147 |
|
|---|
| 148 |
/** |
|---|
| 149 |
* The global alpha value to be used for every pixel. |
|---|
| 150 |
* <p> |
|---|
| 151 |
* If this value is set, the <code>alphaData</code> field |
|---|
| 152 |
* is ignored and when the image is rendered each pixel |
|---|
| 153 |
* will be blended with the background an amount |
|---|
| 154 |
* proportional to this value. |
|---|
| 155 |
* </p><p> |
|---|
| 156 |
* The default is -1 which means 'no global alpha value' |
|---|
| 157 |
* </p> |
|---|
| 158 |
*/ |
|---|
| 159 |
public int alpha; |
|---|
| 160 |
|
|---|
| 161 |
/** |
|---|
| 162 |
* The type of file from which the image was read. |
|---|
| 163 |
* |
|---|
| 164 |
* It is expressed as one of the following values: |
|---|
| 165 |
* <dl> |
|---|
| 166 |
* <dt><code>IMAGE_BMP</code></dt> |
|---|
| 167 |
* <dd>Windows BMP file format, no compression</dd> |
|---|
| 168 |
* <dt><code>IMAGE_BMP_RLE</code></dt> |
|---|
| 169 |
* <dd>Windows BMP file format, RLE compression if appropriate</dd> |
|---|
| 170 |
* <dt><code>IMAGE_GIF</code></dt> |
|---|
| 171 |
* <dd>GIF file format</dd> |
|---|
| 172 |
* <dt><code>IMAGE_ICO</code></dt> |
|---|
| 173 |
* <dd>Windows ICO file format</dd> |
|---|
| 174 |
* <dt><code>IMAGE_JPEG</code></dt> |
|---|
| 175 |
* <dd>JPEG file format</dd> |
|---|
| 176 |
* <dt><code>IMAGE_PNG</code></dt> |
|---|
| 177 |
* <dd>PNG file format</dd> |
|---|
| 178 |
* </dl> |
|---|
| 179 |
*/ |
|---|
| 180 |
public int type; |
|---|
| 181 |
|
|---|
| 182 |
/** |
|---|
| 183 |
* The x coordinate of the top left corner of the image |
|---|
| 184 |
* within the logical screen (this field corresponds to |
|---|
| 185 |
* the GIF89a Image Left Position value). |
|---|
| 186 |
*/ |
|---|
| 187 |
public int x; |
|---|
| 188 |
|
|---|
| 189 |
/** |
|---|
| 190 |
* The y coordinate of the top left corner of the image |
|---|
| 191 |
* within the logical screen (this field corresponds to |
|---|
| 192 |
* the GIF89a Image Top Position value). |
|---|
| 193 |
*/ |
|---|
| 194 |
public int y; |
|---|
| 195 |
|
|---|
| 196 |
/** |
|---|
| 197 |
* A description of how to dispose of the current image |
|---|
| 198 |
* before displaying the next. |
|---|
| 199 |
* |
|---|
| 200 |
* It is expressed as one of the following values: |
|---|
| 201 |
* <dl> |
|---|
| 202 |
* <dt><code>DM_UNSPECIFIED</code></dt> |
|---|
| 203 |
* <dd>disposal method not specified</dd> |
|---|
| 204 |
* <dt><code>DM_FILL_NONE</code></dt> |
|---|
| 205 |
* <dd>do nothing - leave the image in place</dd> |
|---|
| 206 |
* <dt><code>DM_FILL_BACKGROUND</code></dt> |
|---|
| 207 |
* <dd>fill with the background color</dd> |
|---|
| 208 |
* <dt><code>DM_FILL_PREVIOUS</code></dt> |
|---|
| 209 |
* <dd>restore the previous picture</dd> |
|---|
| 210 |
* </dl> |
|---|
| 211 |
* (this field corresponds to the GIF89a Disposal Method value) |
|---|
| 212 |
*/ |
|---|
| 213 |
public int disposalMethod; |
|---|
| 214 |
|
|---|
| 215 |
/** |
|---|
| 216 |
* The time to delay before displaying the next image |
|---|
| 217 |
* in an animation (this field corresponds to the GIF89a |
|---|
| 218 |
* Delay Time value). |
|---|
| 219 |
*/ |
|---|
| 220 |
public int delayTime; |
|---|
| 221 |
|
|---|
| 222 |
/** |
|---|
| 223 |
* Arbitrary channel width data to 8-bit conversion table. |
|---|
| 224 |
*/ |
|---|
| 225 |
private static byte[][] ANY_TO_EIGHT; |
|---|
| 226 |
private static byte[] ONE_TO_ONE_MAPPING; |
|---|
| 227 |
|
|---|
| 228 |
private static bool static_this_completed = false; |
|---|
| 229 |
private static void static_this() { |
|---|
| 230 |
if( static_this_completed ) return; |
|---|
| 231 |
synchronized { |
|---|
| 232 |
if( static_this_completed ) return; |
|---|
| 233 |
ANY_TO_EIGHT = new byte[][](9); |
|---|
| 234 |
for (int b = 0; b < 9; ++b) { |
|---|
| 235 |
byte[] data = ANY_TO_EIGHT[b] = new byte[1 << b]; |
|---|
| 236 |
if (b is 0) continue; |
|---|
| 237 |
int inc = 0; |
|---|
| 238 |
for (int bit = 0x10000; (bit >>= b) !is 0;) inc |= bit; |
|---|
| 239 |
for (int v = 0, p = 0; v < 0x10000; v+= inc) data[p++] = cast(byte)(v >> 8); |
|---|
| 240 |
} |
|---|
| 241 |
ONE_TO_ONE_MAPPING = ANY_TO_EIGHT[8]; |
|---|
| 242 |
static_this_completed = true; |
|---|
| 243 |
} |
|---|
| 244 |
} |
|---|
| 245 |
|
|---|
| 246 |
/** |
|---|
| 247 |
* Scaled 8x8 Bayer dither matrix. |
|---|
| 248 |
*/ |
|---|
| 249 |
static const int[][] DITHER_MATRIX = [ |
|---|
| 250 |
[ 0xfc0000, 0x7c0000, 0xdc0000, 0x5c0000, 0xf40000, 0x740000, 0xd40000, 0x540000 ], |
|---|
| 251 |
[ 0x3c0000, 0xbc0000, 0x1c0000, 0x9c0000, 0x340000, 0xb40000, 0x140000, 0x940000 ], |
|---|
| 252 |
[ 0xcc0000, 0x4c0000, 0xec0000, 0x6c0000, 0xc40000, 0x440000, 0xe40000, 0x640000 ], |
|---|
| 253 |
[ 0x0c0000, 0x8c0000, 0x2c0000, 0xac0000, 0x040000, 0x840000, 0x240000, 0xa40000 ], |
|---|
| 254 |
[ 0xf00000, 0x700000, 0xd00000, 0x500000, 0xf80000, 0x780000, 0xd80000, 0x580000 ], |
|---|
| 255 |
[ 0x300000, 0xb00000, 0x100000, 0x900000, 0x380000, 0xb80000, 0x180000, 0x980000 ], |
|---|
| 256 |
[ 0xc00000, 0x400000, 0xe00000, 0x600000, 0xc80000, 0x480000, 0xe80000, 0x680000 ], |
|---|
| 257 |
[ 0x000000, 0x800000, 0x200000, 0xa00000, 0x080000, 0x880000, 0x280000, 0xa80000 ] |
|---|
| 258 |
]; |
|---|
| 259 |
|
|---|
| 260 |
/** |
|---|
| 261 |
* Constructs a new, empty ImageData with the given width, height, |
|---|
| 262 |
* depth and palette. The data will be initialized to an (all zero) |
|---|
| 263 |
* array of the appropriate size. |
|---|
| 264 |
* |
|---|
| 265 |
* @param width the width of the image |
|---|
| 266 |
* @param height the height of the image |
|---|
| 267 |
* @param depth the depth of the image |
|---|
| 268 |
* @param palette the palette of the image (must not be null) |
|---|
| 269 |
* |
|---|
| 270 |
* @exception IllegalArgumentException <ul> |
|---|
| 271 |
* <li>ERROR_INVALID_ARGUMENT - if the width or height is negative, or if the depth is not |
|---|
| 272 |
* one of 1, 2, 4, 8, 16, 24 or 32</li> |
|---|
| 273 |
* <li>ERROR_NULL_ARGUMENT - if the palette is null</li> |
|---|
| 274 |
* </ul> |
|---|
| 275 |
*/ |
|---|
| 276 |
public this(int width, int height, int depth, PaletteData palette) { |
|---|
| 277 |
this(width, height, depth, palette, |
|---|
| 278 |
4, null, 0, null, |
|---|
| 279 |
null, -1, -1, DWT.IMAGE_UNDEFINED, |
|---|
| 280 |
0, 0, 0, 0); |
|---|
| 281 |
} |
|---|
| 282 |
|
|---|
| 283 |
/** |
|---|
| 284 |
* Constructs a new, empty ImageData with the given width, height, |
|---|
| 285 |
* depth, palette, scanlinePad and data. |
|---|
| 286 |
* |
|---|
| 287 |
* @param width the width of the image |
|---|
| 288 |
* @param height the height of the image |
|---|
| 289 |
* @param depth the depth of the image |
|---|
| 290 |
* @param palette the palette of the image |
|---|
| 291 |
* @param scanlinePad the padding of each line, in bytes |
|---|
| 292 |
* @param data the data of the image |
|---|
| 293 |
* |
|---|
| 294 |
* @exception IllegalArgumentException <ul> |
|---|
| 295 |
* <li>ERROR_INVALID_ARGUMENT - if the width or height is negative, or if the depth is not |
|---|
| 296 |
* one of 1, 2, 4, 8, 16, 24 or 32, or the data array is too small to contain the image data</li> |
|---|
| 297 |
* <li>ERROR_NULL_ARGUMENT - if the palette or data is null</li> |
|---|
| 298 |
* <li>ERROR_CANNOT_BE_ZERO - if the scanlinePad is zero</li> |
|---|
| 299 |
* </ul> |
|---|
| 300 |
*/ |
|---|
| 301 |
public this(int width, int height, int depth, PaletteData palette, int scanlinePad, byte[] data) { |
|---|
| 302 |
this(width, height, depth, palette, |
|---|
| 303 |
scanlinePad, checkData(data), 0, null, |
|---|
| 304 |
null, -1, -1, DWT.IMAGE_UNDEFINED, |
|---|
| 305 |
0, 0, 0, 0); |
|---|
| 306 |
} |
|---|
| 307 |
|
|---|
| 308 |
/** |
|---|
| 309 |
* Constructs an <code>ImageData</code> loaded from the specified |
|---|
| 310 |
* input stream. Throws an error if an error occurs while loading |
|---|
| 311 |
* the image, or if the image has an unsupported type. Application |
|---|
| 312 |
* code is still responsible for closing the input stream. |
|---|
| 313 |
* <p> |
|---|
| 314 |
* This constructor is provided for convenience when loading a single |
|---|
| 315 |
* image only. If the stream contains multiple images, only the first |
|---|
| 316 |
* one will be loaded. To load multiple images, use |
|---|
| 317 |
* <code>ImageLoader.load()</code>. |
|---|
| 318 |
* </p><p> |
|---|
| 319 |
* This constructor may be used to load a resource as follows: |
|---|
| 320 |
* </p> |
|---|
| 321 |
* <pre> |
|---|
| 322 |
* static ImageData loadImageData (Class clazz, String string) { |
|---|
| 323 |
* InputStream stream = clazz.getResourceAsStream (string); |
|---|
| 324 |
* if (stream is null) return null; |
|---|
| 325 |
* ImageData imageData = null; |
|---|
| 326 |
* try { |
|---|
| 327 |
* imageData = new ImageData (stream); |
|---|
| 328 |
* } catch (DWTException ex) { |
|---|
| 329 |
* } finally { |
|---|
| 330 |
* try { |
|---|
| 331 |
* stream.close (); |
|---|
| 332 |
* } catch (IOException ex) {} |
|---|
| 333 |
* } |
|---|
| 334 |
* return imageData; |
|---|
| 335 |
* } |
|---|
| 336 |
* </pre> |
|---|
| 337 |
* |
|---|
| 338 |
* @param stream the input stream to load the image from (must not be null) |
|---|
| 339 |
* |
|---|
| 340 |
* @exception IllegalArgumentException <ul> |
|---|
| 341 |
* <li>ERROR_NULL_ARGUMENT - if the stream is null</li> |
|---|
| 342 |
* </ul> |
|---|
| 343 |
* @exception DWTException <ul> |
|---|
| 344 |
* <li>ERROR_IO - if an IO error occurs while reading from the stream</li> |
|---|
| 345 |
* <li>ERROR_INVALID_IMAGE - if the image stream contains invalid data</li> |
|---|
| 346 |
* <li>ERROR_UNSUPPORTED_FORMAT - if the image stream contains an unrecognized format</li> |
|---|
| 347 |
* </ul> |
|---|
| 348 |
* |
|---|
| 349 |
* @see ImageLoader#load(InputStream) |
|---|
| 350 |
*/ |
|---|
| 351 |
public this(InputStream stream) { |
|---|
| 352 |
ImageData[] data = ImageDataLoader.load(stream); |
|---|
| 353 |
if (data.length < 1) DWT.error(DWT.ERROR_INVALID_IMAGE); |
|---|
| 354 |
ImageData i = data[0]; |
|---|
| 355 |
setAllFields( |
|---|
| 356 |
i.width, |
|---|
| 357 |
i.height, |
|---|
| 358 |
i.depth, |
|---|
| 359 |
i.scanlinePad, |
|---|
| 360 |
i.bytesPerLine, |
|---|
| 361 |
i.data, |
|---|
| 362 |
i.palette, |
|---|
| 363 |
i.transparentPixel, |
|---|
| 364 |
i.maskData, |
|---|
| 365 |
i.maskPad, |
|---|
| 366 |
i.alphaData, |
|---|
| 367 |
i.alpha, |
|---|
| 368 |
i.type, |
|---|
| 369 |
i.x, |
|---|
| 370 |
i.y, |
|---|
| 371 |
i.disposalMethod, |
|---|
| 372 |
i.delayTime); |
|---|
| 373 |
} |
|---|
| 374 |
|
|---|
| 375 |
/** |
|---|
| 376 |
* Constructs an <code>ImageData</code> loaded from a file with the |
|---|
| 377 |
* specified name. Throws an error if an error occurs loading the |
|---|
| 378 |
* image, or if the image has an unsupported type. |
|---|
| 379 |
* <p> |
|---|
| 380 |
* This constructor is provided for convenience when loading a single |
|---|
| 381 |
* image only. If the file contains multiple images, only the first |
|---|
| 382 |
* one will be loaded. To load multiple images, use |
|---|
| 383 |
* <code>ImageLoader.load()</code>. |
|---|
| 384 |
* </p> |
|---|
| 385 |
* |
|---|
| 386 |
* @param filename the name of the file to load the image from (must not be null) |
|---|
| 387 |
* |
|---|
| 388 |
* @exception IllegalArgumentException <ul> |
|---|
| 389 |
* <li>ERROR_NULL_ARGUMENT - if the file name is null</li> |
|---|
| 390 |
* </ul> |
|---|
| 391 |
* @exception DWTException <ul> |
|---|
| 392 |
* <li>ERROR_IO - if an IO error occurs while reading from the file</li> |
|---|
| 393 |
* <li>ERROR_INVALID_IMAGE - if the image file contains invalid data</li> |
|---|
| 394 |
* <li>ERROR_UNSUPPORTED_FORMAT - if the image file contains an unrecognized format</li> |
|---|
| 395 |
* </ul> |
|---|
| 396 |
*/ |
|---|
| 397 |
public this(String filename) { |
|---|
| 398 |
ImageData[] data = ImageDataLoader.load(filename); |
|---|
| 399 |
if (data.length < 1) DWT.error(DWT.ERROR_INVALID_IMAGE); |
|---|
| 400 |
ImageData i = data[0]; |
|---|
| 401 |
setAllFields( |
|---|
| 402 |
i.width, |
|---|
| 403 |
i.height, |
|---|
| 404 |
i.depth, |
|---|
| 405 |
i.scanlinePad, |
|---|
| 406 |
i.bytesPerLine, |
|---|
| 407 |
i.data, |
|---|
| 408 |
i.palette, |
|---|
| 409 |
i.transparentPixel, |
|---|
| 410 |
i.maskData, |
|---|
| 411 |
i.maskPad, |
|---|
| 412 |
i.alphaData, |
|---|
| 413 |
i.alpha, |
|---|
| 414 |
i.type, |
|---|
| 415 |
i.x, |
|---|
| 416 |
i.y, |
|---|
| 417 |
i.disposalMethod, |
|---|
| 418 |
i.delayTime); |
|---|
| 419 |
} |
|---|
| 420 |
|
|---|
| 421 |
/** |
|---|
| 422 |
* Prevents uninitialized instances from being created outside the package. |
|---|
| 423 |
*/ |
|---|
| 424 |
private this() { |
|---|
| 425 |
} |
|---|
| 426 |
|
|---|
| 427 |
/** |
|---|
| 428 |
* Constructs an image data by giving values for all non-computable fields. |
|---|
| 429 |
* <p> |
|---|
| 430 |
* This method is for internal use, and is not described further. |
|---|
| 431 |
* </p> |
|---|
| 432 |
*/ |
|---|
| 433 |
this( |
|---|
| 434 |
int width, int height, int depth, PaletteData palette, |
|---|
| 435 |
int scanlinePad, byte[] data, int maskPad, byte[] maskData, |
|---|
| 436 |
byte[] alphaData, int alpha, int transparentPixel, int type, |
|---|
| 437 |
int x, int y, int disposalMethod, int delayTime) |
|---|
| 438 |
{ |
|---|
| 439 |
if (palette is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); |
|---|
| 440 |
if (!(depth is 1 || depth is 2 || depth is 4 || depth is 8 |
|---|
| 441 |
|| depth is 16 || depth is 24 || depth is 32)) { |
|---|
| 442 |
DWT.error(DWT.ERROR_INVALID_ARGUMENT); |
|---|
| 443 |
} |
|---|
| 444 |
if (width <= 0 || height <= 0) { |
|---|
| 445 |
DWT.error(DWT.ERROR_INVALID_ARGUMENT); |
|---|
| 446 |
} |
|---|
| 447 |
if (scanlinePad is 0) DWT.error (DWT.ERROR_CANNOT_BE_ZERO); |
|---|
| 448 |
|
|---|
| 449 |
int bytesPerLine = (((width * depth + 7) / 8) + (scanlinePad - 1)) |
|---|
| 450 |
/ scanlinePad * scanlinePad; |
|---|
| 451 |
|
|---|
| 452 |
/* |
|---|
| 453 |
* When the image is being loaded from a PNG, we need to use the theoretical minimum |
|---|
| 454 |
* number of bytes per line to check whether there is enough data, because the actual |
|---|
| 455 |
* number of bytes per line is calculated based on the given depth, which may be larger |
|---|
| 456 |
* than the actual depth of the PNG. |
|---|
| 457 |
*/ |
|---|
| 458 |
int minBytesPerLine = type is DWT.IMAGE_PNG ? ((((width + 7) / 8) + 3) / 4) * 4 : bytesPerLine; |
|---|
| 459 |
if (data !is null && data.length < minBytesPerLine * height) { |
|---|
| 460 |
DWT.error(DWT.ERROR_INVALID_ARGUMENT); |
|---|
| 461 |
} |
|---|
| 462 |
setAllFields( |
|---|
| 463 |
width, |
|---|
| 464 |
height, |
|---|
| 465 |
depth, |
|---|
| 466 |
scanlinePad, |
|---|
| 467 |
bytesPerLine, |
|---|
| 468 |
data !is null ? data : new byte[bytesPerLine * height], |
|---|
| 469 |
palette, |
|---|
| 470 |
transparentPixel, |
|---|
| 471 |
maskData, |
|---|
| 472 |
maskPad, |
|---|
| 473 |
alphaData, |
|---|
| 474 |
alpha, |
|---|
| 475 |
type, |
|---|
| 476 |
x, |
|---|
| 477 |
y, |
|---|
| 478 |
disposalMethod, |
|---|
| 479 |
delayTime); |
|---|
| 480 |
} |
|---|
| 481 |
|
|---|
| 482 |
/** |
|---|
| 483 |
* Initializes all fields in the receiver. This method must be called |
|---|
| 484 |
* by all public constructors to ensure that all fields are initialized |
|---|
| 485 |
* for a new ImageData object. If a new field is added to the class, |
|---|
| 486 |
* then it must be added to this method. |
|---|
| 487 |
* <p> |
|---|
| 488 |
* This method is for internal use, and is not described further. |
|---|
| 489 |
* </p> |
|---|
| 490 |
*/ |
|---|
| 491 |
void setAllFields(int width, int height, int depth, int scanlinePad, |
|---|
| 492 |
int bytesPerLine, byte[] data, PaletteData palette, int transparentPixel, |
|---|
| 493 |
byte[] maskData, int maskPad, byte[] alphaData, int alpha, |
|---|
| 494 |
int type, int x, int y, int disposalMethod, int delayTime) { |
|---|
| 495 |
|
|---|
| 496 |
this.width = width; |
|---|
| 497 |
this.height = height; |
|---|
| 498 |
this.depth = depth; |
|---|
| 499 |
this.scanlinePad = scanlinePad; |
|---|
| 500 |
this.bytesPerLine = bytesPerLine; |
|---|
| 501 |
this.data = data; |
|---|
| 502 |
this.palette = palette; |
|---|
| 503 |
this.transparentPixel = transparentPixel; |
|---|
| 504 |
this.maskData = maskData; |
|---|
| 505 |
this.maskPad = maskPad; |
|---|
| 506 |
this.alphaData = alphaData; |
|---|
| 507 |
this.alpha = alpha; |
|---|
| 508 |
this.type = type; |
|---|
| 509 |
this.x = x; |
|---|
| 510 |
this.y = y; |
|---|
| 511 |
this.disposalMethod = disposalMethod; |
|---|
| 512 |
this.delayTime = delayTime; |
|---|
| 513 |
} |
|---|
| 514 |
|
|---|
| 515 |
/** |
|---|
| 516 |
* Invokes internal DWT functionality to create a new instance of |
|---|
| 517 |
* this class. |
|---|
| 518 |
* <p> |
|---|
| 519 |
* <b>IMPORTANT:</b> This method is <em>not</em> part of the public |
|---|
| 520 |
* API for <code>ImageData</code>. It is marked public only so that it |
|---|
| 521 |
* can be shared within the packages provided by DWT. It is subject |
|---|
| 522 |
* to change without notice, and should never be called from |
|---|
| 523 |
* application code. |
|---|
| 524 |
* </p> |
|---|
| 525 |
* <p> |
|---|
| 526 |
* This method is for internal use, and is not described further. |
|---|
| 527 |
* </p> |
|---|
| 528 |
*/ |
|---|
| 529 |
public static ImageData internal_new( |
|---|
| 530 |
int width, int height, int depth, PaletteData palette, |
|---|
| 531 |
int scanlinePad, byte[] data, int maskPad, byte[] maskData, |
|---|
| 532 |
byte[] alphaData, int alpha, int transparentPixel, int type, |
|---|
| 533 |
int x, int y, int disposalMethod, int delayTime) |
|---|
| 534 |
{ |
|---|
| 535 |
return new ImageData( |
|---|
| 536 |
width, height, depth, palette, scanlinePad, data, maskPad, maskData, |
|---|
| 537 |
alphaData, alpha, transparentPixel, type, x, y, disposalMethod, delayTime); |
|---|
| 538 |
} |
|---|
| 539 |
|
|---|
| 540 |
ImageData colorMaskImage(int pixel) { |
|---|
| 541 |
ImageData mask = new ImageData(width, height, 1, bwPalette(), |
|---|
| 542 |
2, null, 0, null, null, -1, -1, DWT.IMAGE_UNDEFINED, |
|---|
| 543 |
0, 0, 0, 0); |
|---|
| 544 |
int[] row = new int[width]; |
|---|
| 545 |
for (int y = 0; y < height; y++) { |
|---|
| 546 |
getPixels(0, y, width, row, 0); |
|---|
| 547 |
for (int i = 0; i < width; i++) { |
|---|
| 548 |
if (pixel !is -1 && row[i] is pixel) { |
|---|
| 549 |
row[i] = 0; |
|---|
| 550 |
} else { |
|---|
| 551 |
row[i] = 1; |
|---|
| 552 |
} |
|---|
| 553 |
} |
|---|
| 554 |
mask.setPixels(0, y, width, row, 0); |
|---|
| 555 |
} |
|---|
| 556 |
return mask; |
|---|
| 557 |
} |
|---|
| 558 |
|
|---|
| 559 |
static byte[] checkData(byte [] data) { |
|---|
| 560 |
if (data is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); |
|---|
| 561 |
return data; |
|---|
| 562 |
} |
|---|
| 563 |
|
|---|
| 564 |
/** |
|---|
| 565 |
* Returns a new instance of the same class as the receiver, |
|---|
| 566 |
* whose slots have been filled in with <em>copies</em> of |
|---|
| 567 |
* the values in the slots of the receiver. That is, the |
|---|
| 568 |
* returned object is a <em>deep copy</em> of the receiver. |
|---|
| 569 |
* |
|---|
| 570 |
* @return a copy of the receiver. |
|---|
| 571 |
*/ |
|---|
| 572 |
public Object clone() { |
|---|
| 573 |
byte[] cloneData = new byte[data.length]; |
|---|
| 574 |
System.arraycopy(data, 0, cloneData, 0, data.length); |
|---|
| 575 |
byte[] cloneMaskData = null; |
|---|
| 576 |
if (maskData !is null) { |
|---|
| 577 |
cloneMaskData = new byte[maskData.length]; |
|---|
| 578 |
System.arraycopy(maskData, 0, cloneMaskData, 0, maskData.length); |
|---|
| 579 |
} |
|---|
| 580 |
byte[] cloneAlphaData = null; |
|---|
| 581 |
if (alphaData !is null) { |
|---|
| 582 |
cloneAlphaData = new byte[alphaData.length]; |
|---|
| 583 |
System.arraycopy(alphaData, 0, cloneAlphaData, 0, alphaData.length); |
|---|
| 584 |
} |
|---|
| 585 |
return new ImageData( |
|---|
| 586 |
width, |
|---|
| 587 |
height, |
|---|
| 588 |
depth, |
|---|
| 589 |
palette, |
|---|
| 590 |
scanlinePad, |
|---|
| 591 |
cloneData, |
|---|
| 592 |
maskPad, |
|---|
| 593 |
cloneMaskData, |
|---|
| 594 |
cloneAlphaData, |
|---|
| 595 |
alpha, |
|---|
| 596 |
transparentPixel, |
|---|
| 597 |
type, |
|---|
| 598 |
x, |
|---|
| 599 |
y, |
|---|
| 600 |
disposalMethod, |
|---|
| 601 |
delayTime); |
|---|
| 602 |
} |
|---|
| 603 |
|
|---|
| 604 |
/** |
|---|
| 605 |
* Returns the alpha value at offset <code>x</code> in |
|---|
| 606 |
* scanline <code>y</code> in the receiver's alpha data. |
|---|
| 607 |
* The alpha value is between 0 (transparent) and |
|---|
| 608 |
* 255 (opaque). |
|---|
| 609 |
* |
|---|
| 610 |
* @param x the x coordinate of the pixel to get the alpha value of |
|---|
| 611 |
* @param y the y coordinate of the pixel to get the alpha value of |
|---|
| 612 |
* @return the alpha value at the given coordinates |
|---|
| 613 |
* |
|---|
| 614 |
* @exception IllegalArgumentException <ul> |
|---|
| 615 |
* <li>ERROR_INVALID_ARGUMENT - if either argument is out of range</li> |
|---|
| 616 |
* </ul> |
|---|
| 617 |
*/ |
|---|
| 618 |
public int getAlpha(int x, int y) { |
|---|
| 619 |
if (x >= width || y >= height || x < 0 || y < 0) DWT.error(DWT.ERROR_INVALID_ARGUMENT); |
|---|
| 620 |
|
|---|
| 621 |
if (alphaData is null) return 255; |
|---|
| 622 |
return alphaData[y * width + x] & 0xFF; |
|---|
| 623 |
} |
|---|
| 624 |
|
|---|
| 625 |
/** |
|---|
| 626 |
* Returns <code>getWidth</code> alpha values starting at offset |
|---|
| 627 |
* <code>x</code> in scanline <code>y</code> in the receiver's alpha |
|---|
| 628 |
* data starting at <code>startIndex</code>. The alpha values |
|---|
| 629 |
* are unsigned, between <code>(byte)0</code> (transparent) and |
|---|
| 630 |
* <code>(byte)255</code> (opaque). |
|---|
| 631 |
* |
|---|
| 632 |
* @param x the x position of the pixel to begin getting alpha values |
|---|
| 633 |
* @param y the y position of the pixel to begin getting alpha values |
|---|
| 634 |
* @param getWidth the width of the data to get |
|---|
| 635 |
* @param alphas the buffer in which to put the alpha values |
|---|
| 636 |
* @param startIndex the offset into the image to begin getting alpha values |
|---|
| 637 |
* |
|---|
| 638 |
* @exception IndexOutOfBoundsException if getWidth is too large |
|---|
| 639 |
* @exception IllegalArgumentException <ul> |
|---|
| 640 |
* <li>ERROR_NULL_ARGUMENT - if pixels is null</li> |
|---|
| 641 |
* <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li> |
|---|
| 642 |
* <li>ERROR_INVALID_ARGUMENT - if getWidth is negative</li> |
|---|
| 643 |
* </ul> |
|---|
| 644 |
*/ |
|---|
| 645 |
public void getAlphas(int x, int y, int getWidth, byte[] alphas, int startIndex) { |
|---|
| 646 |
if (alphas is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); |
|---|
| 647 |
if (getWidth < 0 || x >= width || y >= height || x < 0 || y < 0) DWT.error(DWT.ERROR_INVALID_ARGUMENT); |
|---|
| 648 |
if (getWidth is 0) return; |
|---|
| 649 |
|
|---|
| 650 |
if (alphaData is null) { |
|---|
| 651 |
int endIndex = startIndex + getWidth; |
|---|
| 652 |
for (int i = startIndex; i < endIndex; i++) { |
|---|
| 653 |
alphas[i] = cast(byte)255; |
|---|
| 654 |
} |
|---|
| 655 |
return; |
|---|
| 656 |
} |
|---|
| 657 |
// may throw an IndexOutOfBoundsException |
|---|
| 658 |
System.arraycopy(alphaData, y * width + x, alphas, startIndex, getWidth); |
|---|
| 659 |
} |
|---|
| 660 |
|
|---|
| 661 |
/** |
|---|
| 662 |
* Returns the pixel value at offset <code>x</code> in |
|---|
| 663 |
* scanline <code>y</code> in the receiver's data. |
|---|
| 664 |
* |
|---|
| 665 |
* @param x the x position of the pixel to get |
|---|
| 666 |
* @param y the y position of the pixel to get |
|---|
| 667 |
* @return the pixel at the given coordinates |
|---|
| 668 |
* |
|---|
| 669 |
* @exception IllegalArgumentException <ul> |
|---|
| 670 |
* <li>ERROR_INVALID_ARGUMENT - if either argument is out of bounds</li> |
|---|
| 671 |
* </ul> |
|---|
| 672 |
* @exception DWTException <ul> |
|---|
| 673 |
* <li>ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8, 16, 24 or 32</li> |
|---|
| 674 |
* </ul> |
|---|
| 675 |
*/ |
|---|
| 676 |
public int getPixel(int x, int y) { |
|---|
| 677 |
if (x >= width || y >= height || x < 0 || y < 0) DWT.error(DWT.ERROR_INVALID_ARGUMENT); |
|---|
| 678 |
int index; |
|---|
| 679 |
int theByte; |
|---|
|
|---|