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);