Mercurial > projects > dwt-mac
comparison dwt/internal/image/GIFFileFormat.d @ 34:5123b17c98ef
Ported dwt.events.*, dwt.graphics.GC, Region, dwt.internal.image.*
author | Jacob Carlborg <doob@me.com> <jacob.carlborg@gmail.com> |
---|---|
date | Sun, 14 Sep 2008 01:45:57 +0200 |
parents | e831403a80a9 |
children | d8635bb48c7c |
comparison
equal
deleted
inserted
replaced
33:965ac0a77267 | 34:5123b17c98ef |
---|---|
1 /******************************************************************************* | 1 /******************************************************************************* |
2 * Copyright (c) 2000, 2005 IBM Corporation and others. | 2 * Copyright (c) 2000, 2008 IBM Corporation and others. |
3 * All rights reserved. This program and the accompanying materials | 3 * All rights reserved. This program and the accompanying materials |
4 * are made available under the terms of the Eclipse Public License v1.0 | 4 * are made available under the terms of the Eclipse Public License v1.0 |
5 * which accompanies this distribution, and is available at | 5 * which accompanies this distribution, and is available at |
6 * http://www.eclipse.org/legal/epl-v10.html | 6 * http://www.eclipse.org/legal/epl-v10.html |
7 * | 7 * |
8 * Contributors: | 8 * Contributors: |
9 * IBM Corporation - initial API and implementation | 9 * IBM Corporation - initial API and implementation |
10 * Port to the D programming language: | |
11 * Frank Benoit <benoit@tionex.de> | |
10 *******************************************************************************/ | 12 *******************************************************************************/ |
11 module dwt.internal.image; | 13 module dwt.internal.image.GIFFileFormat; |
12 | 14 |
13 | 15 public import dwt.internal.image.FileFormat; |
14 import java.io.IOException; | 16 public import dwt.graphics.PaletteData; |
15 | 17 import dwt.internal.image.LEDataInputStream; |
18 import dwt.internal.image.LZWCodec; | |
19 import dwt.graphics.RGB; | |
16 import dwt.DWT; | 20 import dwt.DWT; |
17 import dwt.graphics.ImageData; | 21 import dwt.graphics.ImageData; |
22 import dwt.graphics.ImageLoaderEvent; | |
18 import dwt.graphics.ImageLoader; | 23 import dwt.graphics.ImageLoader; |
19 import dwt.graphics.ImageLoaderEvent; | 24 import tango.core.Exception; |
20 import dwt.graphics.PaletteData; | 25 import dwt.dwthelper.utils; |
21 import dwt.graphics.RGB; | 26 |
22 | 27 |
23 public final class GIFFileFormat : FileFormat { | 28 final class GIFFileFormat : FileFormat { |
24 String signature; | 29 String signature; |
25 int screenWidth, screenHeight, backgroundPixel, bitsPerPixel, defaultDepth; | 30 int screenWidth, screenHeight, backgroundPixel, bitsPerPixel, defaultDepth; |
26 int disposalMethod = 0; | 31 int disposalMethod = 0; |
27 int delayTime = 0; | 32 int delayTime = 0; |
28 int transparentPixel = -1; | 33 int transparentPixel = -1; |
29 int repeatCount = 1; | 34 int repeatCount = 1; |
30 | 35 |
31 static final int GIF_APPLICATION_EXTENSION_BLOCK_ID = 0xFF; | 36 static final int GIF_APPLICATION_EXTENSION_BLOCK_ID = 0xFF; |
32 static final int GIF_GRAPHICS_CONTROL_BLOCK_ID = 0xF9; | 37 static final int GIF_GRAPHICS_CONTROL_BLOCK_ID = 0xF9; |
33 static final int GIF_PLAIN_TEXT_BLOCK_ID = 0x01; | 38 static final int GIF_PLAIN_TEXT_BLOCK_ID = 0x01; |
34 static final int GIF_COMMENT_BLOCK_ID = 0xFE; | 39 static final int GIF_COMMENT_BLOCK_ID = 0xFE; |
35 static final int GIF_EXTENSION_BLOCK_ID = 0x21; | 40 static final int GIF_EXTENSION_BLOCK_ID = 0x21; |
36 static final int GIF_IMAGE_BLOCK_ID = 0x2C; | 41 static final int GIF_IMAGE_BLOCK_ID = 0x2C; |
37 static final int GIF_TRAILER_ID = 0x3B; | 42 static final int GIF_TRAILER_ID = 0x3B; |
38 static final byte [] GIF89a = new byte[] { cast(byte)'G', cast(byte)'I', cast(byte)'F', cast(byte)'8', cast(byte)'9', cast(byte)'a' }; | 43 static final byte[] GIF89a = cast(byte[])"GIF89a"; |
39 static final byte [] NETSCAPE2_0 = new byte[] { cast(byte)'N', cast(byte)'E', cast(byte)'T', cast(byte)'S', cast(byte)'C', cast(byte)'A', cast(byte)'P', cast(byte)'E', cast(byte)'2', cast(byte)'.', cast(byte)'0' }; | 44 static final byte[] NETSCAPE2_0 = cast(byte[])"NETSCAPE2.0"; |
40 | 45 |
41 /** | 46 /** |
42 * Answer a palette containing numGrays | 47 * Answer a palette containing numGrays |
43 * shades of gray, ranging from black to white. | 48 * shades of gray, ranging from black to white. |
44 */ | 49 */ |
45 static PaletteData grayRamp(int numGrays) { | 50 static PaletteData grayRamp(int numGrays) { |
50 colors[i] = new RGB(intensity, intensity, intensity); | 55 colors[i] = new RGB(intensity, intensity, intensity); |
51 } | 56 } |
52 return new PaletteData(colors); | 57 return new PaletteData(colors); |
53 } | 58 } |
54 | 59 |
55 bool isFileFormat(LEDataInputStream stream) { | 60 override bool isFileFormat(LEDataInputStream stream) { |
56 try { | 61 try { |
57 byte[] signature = new byte[3]; | 62 byte[3] signature; |
58 stream.read(signature); | 63 stream.read(signature); |
59 stream.unread(signature); | 64 stream.unread(signature); |
60 return signature[0] is 'G' && signature[1] is 'I' && signature[2] is 'F'; | 65 return signature[0] is 'G' && signature[1] is 'I' && signature[2] is 'F'; |
61 } catch (Exception e) { | 66 } catch (Exception e) { |
62 return false; | 67 return false; |
65 | 70 |
66 /** | 71 /** |
67 * Load the GIF image(s) stored in the input stream. | 72 * Load the GIF image(s) stored in the input stream. |
68 * Return an array of ImageData representing the image(s). | 73 * Return an array of ImageData representing the image(s). |
69 */ | 74 */ |
70 ImageData[] loadFromByteStream() { | 75 override ImageData[] loadFromByteStream() { |
71 byte[] signature = new byte[3]; | 76 byte[3] signature; |
72 byte[] versionBytes = new byte[3]; | 77 byte[3] versionBytes; |
73 byte[] block = new byte[7]; | 78 byte[7] block; |
74 try { | 79 try { |
75 inputStream.read(signature); | 80 inputStream.read(signature); |
76 if (!(signature[0] is 'G' && signature[1] is 'I' && signature[2] is 'F')) | 81 if (!(signature[0] is 'G' && signature[1] is 'I' && signature[2] is 'F')) |
77 DWT.error(DWT.ERROR_INVALID_IMAGE); | 82 DWT.error(DWT.ERROR_INVALID_IMAGE); |
78 | 83 |
114 } | 119 } |
115 ImageData[] oldImages = images; | 120 ImageData[] oldImages = images; |
116 images = new ImageData[oldImages.length + 1]; | 121 images = new ImageData[oldImages.length + 1]; |
117 System.arraycopy(oldImages, 0, images, 0, oldImages.length); | 122 System.arraycopy(oldImages, 0, images, 0, oldImages.length); |
118 images[images.length - 1] = image; | 123 images[images.length - 1] = image; |
124 //images ~= image; | |
119 try { | 125 try { |
120 /* Read the 0-byte terminator at the end of the image. */ | 126 /* Read the 0-byte terminator at the end of the image. */ |
121 id = inputStream.read(); | 127 id = inputStream.read(); |
122 if (id > 0) { | 128 if (id > 0) { |
123 /* We read the terminator earlier. */ | 129 /* We read the terminator earlier. */ |
124 inputStream.unread(new byte[] {cast(byte)id}); | 130 byte[1] arr; |
131 arr[0] = id; | |
132 inputStream.unread( arr ); | |
125 } | 133 } |
126 } catch (IOException e) { | 134 } catch (IOException e) { |
127 DWT.error(DWT.ERROR_IO, e); | 135 DWT.error(DWT.ERROR_IO, e); |
128 } | 136 } |
129 getExtensions(); | 137 getExtensions(); |
162 } | 170 } |
163 id = readID(); | 171 id = readID(); |
164 } | 172 } |
165 if (id is GIF_IMAGE_BLOCK_ID || id is GIF_TRAILER_ID) { | 173 if (id is GIF_IMAGE_BLOCK_ID || id is GIF_TRAILER_ID) { |
166 try { | 174 try { |
167 inputStream.unread(new byte[] {cast(byte)id}); | 175 byte[1] arr; |
176 arr[0] = id; | |
177 inputStream.unread(arr); | |
168 } catch (IOException e) { | 178 } catch (IOException e) { |
169 DWT.error(DWT.ERROR_IO, e); | 179 DWT.error(DWT.ERROR_IO, e); |
170 } | 180 } |
171 } | 181 } |
172 } | 182 } |
215 while ((size > 0) && (inputStream.read(block, 0, size) !is -1)) { | 225 while ((size > 0) && (inputStream.read(block, 0, size) !is -1)) { |
216 byte[] oldComment = comment; | 226 byte[] oldComment = comment; |
217 comment = new byte[oldComment.length + size]; | 227 comment = new byte[oldComment.length + size]; |
218 System.arraycopy(oldComment, 0, comment, 0, oldComment.length); | 228 System.arraycopy(oldComment, 0, comment, 0, oldComment.length); |
219 System.arraycopy(block, 0, comment, oldComment.length, size); | 229 System.arraycopy(block, 0, comment, oldComment.length, size); |
230 //comment ~= block[ 0 .. size ]; | |
220 size = inputStream.read(); | 231 size = inputStream.read(); |
221 } | 232 } |
222 return comment; | 233 return comment; |
223 } catch (Exception e) { | 234 } catch (Exception e) { |
224 DWT.error(DWT.ERROR_IO, e); | 235 DWT.error(DWT.ERROR_IO, e); |
245 while ((size > 0) && (inputStream.read(block, 0, size) !is -1)) { | 256 while ((size > 0) && (inputStream.read(block, 0, size) !is -1)) { |
246 byte[] oldText = text; | 257 byte[] oldText = text; |
247 text = new byte[oldText.length + size]; | 258 text = new byte[oldText.length + size]; |
248 System.arraycopy(oldText, 0, text, 0, oldText.length); | 259 System.arraycopy(oldText, 0, text, 0, oldText.length); |
249 System.arraycopy(block, 0, text, oldText.length, size); | 260 System.arraycopy(block, 0, text, oldText.length, size); |
261 //text ~= block[ 0 .. size ]; | |
250 size = inputStream.read(); | 262 size = inputStream.read(); |
251 } | 263 } |
252 return text; | 264 return text; |
253 } catch (Exception e) { | 265 } catch (Exception e) { |
254 DWT.error(DWT.ERROR_IO, e); | 266 DWT.error(DWT.ERROR_IO, e); |
312 while ((size > 0) && (inputStream.read(block, 0, size) !is -1)) { | 324 while ((size > 0) && (inputStream.read(block, 0, size) !is -1)) { |
313 byte[] oldData = data; | 325 byte[] oldData = data; |
314 data = new byte[oldData.length + size]; | 326 data = new byte[oldData.length + size]; |
315 System.arraycopy(oldData, 0, data, 0, oldData.length); | 327 System.arraycopy(oldData, 0, data, 0, oldData.length); |
316 System.arraycopy(block, 0, data, oldData.length, size); | 328 System.arraycopy(block, 0, data, oldData.length, size); |
329 //data ~= block[ 0 .. size ]; | |
317 size = inputStream.read(); | 330 size = inputStream.read(); |
318 } | 331 } |
319 // Look for the NETSCAPE 'repeat count' field for an animated GIF. | 332 // Look for the NETSCAPE 'repeat count' field for an animated GIF. |
320 bool netscape = | 333 bool netscape = |
321 application[0] is 'N' && | 334 application[0] is 'N' && |
410 transparentPixel, | 423 transparentPixel, |
411 DWT.IMAGE_GIF, | 424 DWT.IMAGE_GIF, |
412 left, | 425 left, |
413 top, | 426 top, |
414 disposalMethod, | 427 disposalMethod, |
415 delayTime); | 428 delayTime); |
416 LZWCodec codec = new LZWCodec(); | 429 LZWCodec codec = new LZWCodec(); |
417 codec.decode(inputStream, loader, image, interlaced, initialCodeSize); | 430 codec.decode(inputStream, loader, image, interlaced, initialCodeSize); |
418 return image; | 431 return image; |
419 } | 432 } |
420 | 433 |
429 } catch (IOException e) { | 442 } catch (IOException e) { |
430 DWT.error(DWT.ERROR_IO, e); | 443 DWT.error(DWT.ERROR_IO, e); |
431 } | 444 } |
432 RGB[] colors = new RGB[numColors]; | 445 RGB[] colors = new RGB[numColors]; |
433 for (int i = 0; i < numColors; i++) | 446 for (int i = 0; i < numColors; i++) |
434 colors[i] = new RGB(bytes[i*3] & 0xFF, | 447 colors[i] = new RGB(bytes[i*3] & 0xFF, |
435 bytes[i*3+1] & 0xFF, bytes[i*3+2] & 0xFF); | 448 bytes[i*3+1] & 0xFF, bytes[i*3+2] & 0xFF); |
436 return new PaletteData(colors); | 449 return new PaletteData(colors); |
437 } | 450 } |
438 | 451 |
439 void unloadIntoByteStream(ImageLoader loader) { | 452 override void unloadIntoByteStream(ImageLoader loader) { |
440 | 453 |
441 /* Step 1: Acquire GIF parameters. */ | 454 /* Step 1: Acquire GIF parameters. */ |
442 ImageData[] data = loader.data; | 455 ImageData[] data = loader.data; |
443 int frameCount = data.length; | 456 int frameCount = data.length; |
444 bool multi = frameCount > 1; | 457 bool multi = frameCount > 1; |
445 ImageData firstImage = data[0]; | 458 ImageData firstImage = data[0]; |
448 int backgroundPixel = loader.backgroundPixel; | 461 int backgroundPixel = loader.backgroundPixel; |
449 int depth = firstImage.depth; | 462 int depth = firstImage.depth; |
450 PaletteData palette = firstImage.palette; | 463 PaletteData palette = firstImage.palette; |
451 RGB[] colors = palette.getRGBs(); | 464 RGB[] colors = palette.getRGBs(); |
452 short globalTable = 1; | 465 short globalTable = 1; |
453 | 466 |
454 /* Step 2: Check for validity and global/local color map. */ | 467 /* Step 2: Check for validity and global/local color map. */ |
455 if (!(depth is 1 || depth is 4 || depth is 8)) { | 468 if (!(depth is 1 || depth is 4 || depth is 8)) { |
456 DWT.error(DWT.ERROR_UNSUPPORTED_DEPTH); | 469 DWT.error(DWT.ERROR_UNSUPPORTED_DEPTH); |
457 } | 470 } |
458 for (int i=0; i<frameCount; i++) { | 471 for (int i=0; i<frameCount; i++) { |
465 } | 478 } |
466 if (globalTable is 1) { | 479 if (globalTable is 1) { |
467 RGB rgbs[] = data[i].palette.getRGBs(); | 480 RGB rgbs[] = data[i].palette.getRGBs(); |
468 if (rgbs.length !is colors.length) { | 481 if (rgbs.length !is colors.length) { |
469 globalTable = 0; | 482 globalTable = 0; |
470 } else { | 483 } else { |
471 for (int j=0; j<colors.length; j++) { | 484 for (int j=0; j<colors.length; j++) { |
472 if (!(rgbs[j].red is colors[j].red && | 485 if (!(rgbs[j].red is colors[j].red && |
473 rgbs[j].green is colors[j].green && | 486 rgbs[j].green is colors[j].green && |
474 rgbs[j].blue is colors[j].blue)) | 487 rgbs[j].blue is colors[j].blue)) |
475 globalTable = 0; | 488 globalTable = 0; |
476 } | 489 } |
477 } | 490 } |
478 } | 491 } |
479 } | 492 } |
480 } | 493 } |
481 | 494 |
482 try { | 495 try { |
483 /* Step 3: Write the GIF89a Header and Logical Screen Descriptor. */ | 496 /* Step 3: Write the GIF89a Header and Logical Screen Descriptor. */ |
484 outputStream.write(GIF89a); | 497 outputStream.write(GIF89a); |
485 int bitField = globalTable*128 + (depth-1)*16 + depth-1; | 498 int bitField = globalTable*128 + (depth-1)*16 + depth-1; |
486 outputStream.writeShort(cast(short)logicalScreenWidth); | 499 outputStream.writeShort(cast(short)logicalScreenWidth); |
489 outputStream.write(backgroundPixel); | 502 outputStream.write(backgroundPixel); |
490 outputStream.write(0); // Aspect ratio is 1:1 | 503 outputStream.write(0); // Aspect ratio is 1:1 |
491 } catch (IOException e) { | 504 } catch (IOException e) { |
492 DWT.error(DWT.ERROR_IO, e); | 505 DWT.error(DWT.ERROR_IO, e); |
493 } | 506 } |
494 | 507 |
495 /* Step 4: Write Global Color Table if applicable. */ | 508 /* Step 4: Write Global Color Table if applicable. */ |
496 if (globalTable is 1) { | 509 if (globalTable is 1) { |
497 writePalette(palette, depth); | 510 writePalette(palette, depth); |
498 } | 511 } |
499 | 512 |
511 outputStream.write(0); // Block terminator | 524 outputStream.write(0); // Block terminator |
512 } catch (IOException e) { | 525 } catch (IOException e) { |
513 DWT.error(DWT.ERROR_IO, e); | 526 DWT.error(DWT.ERROR_IO, e); |
514 } | 527 } |
515 } | 528 } |
516 | 529 |
517 for (int frame=0; frame<frameCount; frame++) { | 530 for (int frame=0; frame<frameCount; frame++) { |
518 | 531 |
519 /* Step 6: Write Graphics Control Block for each frame if applicable. */ | 532 /* Step 6: Write Graphics Control Block for each frame if applicable. */ |
520 if (multi || data[frame].transparentPixel !is -1) { | 533 if (multi || data[frame].transparentPixel !is -1) { |
521 writeGraphicsControlBlock(data[frame]); | 534 writeGraphicsControlBlock(data[frame]); |
522 } | 535 } |
523 | 536 |
524 /* Step 7: Write Image Header for each frame. */ | 537 /* Step 7: Write Image Header for each frame. */ |
525 int x = data[frame].x; | 538 int x = data[frame].x; |
526 int y = data[frame].y; | 539 int y = data[frame].y; |
527 int width = data[frame].width; | 540 int width = data[frame].width; |
528 int height = data[frame].height; | 541 int height = data[frame].height; |
534 block[2] = cast(byte)(y & 0xFF); | 547 block[2] = cast(byte)(y & 0xFF); |
535 block[3] = cast(byte)((y >> 8) & 0xFF); | 548 block[3] = cast(byte)((y >> 8) & 0xFF); |
536 block[4] = cast(byte)(width & 0xFF); | 549 block[4] = cast(byte)(width & 0xFF); |
537 block[5] = cast(byte)((width >> 8) & 0xFF); | 550 block[5] = cast(byte)((width >> 8) & 0xFF); |
538 block[6] = cast(byte)(height & 0xFF); | 551 block[6] = cast(byte)(height & 0xFF); |
539 block[7] = cast(byte)((height >> 8) & 0xFF); | 552 block[7] = cast(byte)((height >> 8) & 0xFF); |
540 block[8] = cast(byte)(globalTable is 0 ? (depth-1) | 0x80 : 0x00); | 553 block[8] = cast(byte)(globalTable is 0 ? (depth-1) | 0x80 : 0x00); |
541 outputStream.write(block); | 554 outputStream.write(block); |
542 } catch (IOException e) { | 555 } catch (IOException e) { |
543 DWT.error(DWT.ERROR_IO, e); | 556 DWT.error(DWT.ERROR_IO, e); |
544 } | 557 } |
545 | 558 |
546 /* Step 8: Write Local Color Table for each frame if applicable. */ | 559 /* Step 8: Write Local Color Table for each frame if applicable. */ |
547 if (globalTable is 0) { | 560 if (globalTable is 0) { |
548 writePalette(data[frame].palette, depth); | 561 writePalette(data[frame].palette, depth); |
549 } | 562 } |
550 | 563 |
551 /* Step 9: Write the actual data for each frame. */ | 564 /* Step 9: Write the actual data for each frame. */ |
552 try { | 565 try { |
553 outputStream.write(depth); // Minimum LZW Code size | 566 outputStream.write(depth); // Minimum LZW Code size |
554 } catch (IOException e) { | 567 } catch (IOException e) { |
555 DWT.error(DWT.ERROR_IO, e); | 568 DWT.error(DWT.ERROR_IO, e); |
556 } | 569 } |
557 new LZWCodec().encode(outputStream, data[frame]); | 570 (new LZWCodec()).encode(outputStream, data[frame]); |
558 } | 571 } |
559 | 572 |
560 /* Step 10: Write GIF terminator. */ | 573 /* Step 10: Write GIF terminator. */ |
561 try { | 574 try { |
562 outputStream.write(0x3B); | 575 outputStream.write(0x3B); |