Mercurial > projects > dwt2
comparison org.eclipse.swt.win32.win32.x86/src/org/eclipse/swt/internal/image/GIFFileFormat.d @ 0:6dd524f61e62
add dwt win and basic java stuff
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Mon, 02 Mar 2009 14:44:16 +0100 |
parents | |
children | f36c67707cb3 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:6dd524f61e62 |
---|---|
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 org.eclipse.swt.internal.image.GIFFileFormat; | |
14 | |
15 public import org.eclipse.swt.internal.image.FileFormat; | |
16 public import org.eclipse.swt.graphics.PaletteData; | |
17 import org.eclipse.swt.internal.image.LEDataInputStream; | |
18 import org.eclipse.swt.internal.image.LZWCodec; | |
19 import org.eclipse.swt.graphics.RGB; | |
20 import org.eclipse.swt.SWT; | |
21 import org.eclipse.swt.graphics.ImageData; | |
22 import org.eclipse.swt.graphics.ImageLoaderEvent; | |
23 import org.eclipse.swt.graphics.ImageLoader; | |
24 import tango.core.Exception; | |
25 import java.lang.all; | |
26 | |
27 | |
28 final class GIFFileFormat : FileFormat { | |
29 String signature; | |
30 int screenWidth, screenHeight, backgroundPixel, bitsPerPixel, defaultDepth; | |
31 int disposalMethod = 0; | |
32 int delayTime = 0; | |
33 int transparentPixel = -1; | |
34 int repeatCount = 1; | |
35 | |
36 static final int GIF_APPLICATION_EXTENSION_BLOCK_ID = 0xFF; | |
37 static final int GIF_GRAPHICS_CONTROL_BLOCK_ID = 0xF9; | |
38 static final int GIF_PLAIN_TEXT_BLOCK_ID = 0x01; | |
39 static final int GIF_COMMENT_BLOCK_ID = 0xFE; | |
40 static final int GIF_EXTENSION_BLOCK_ID = 0x21; | |
41 static final int GIF_IMAGE_BLOCK_ID = 0x2C; | |
42 static final int GIF_TRAILER_ID = 0x3B; | |
43 static final byte[] GIF89a = cast(byte[])"GIF89a"; | |
44 static final byte[] NETSCAPE2_0 = cast(byte[])"NETSCAPE2.0"; | |
45 | |
46 /** | |
47 * Answer a palette containing numGrays | |
48 * shades of gray, ranging from black to white. | |
49 */ | |
50 static PaletteData grayRamp(int numGrays) { | |
51 int n = numGrays - 1; | |
52 RGB[] colors = new RGB[numGrays]; | |
53 for (int i = 0; i < numGrays; i++) { | |
54 int intensity = cast(byte)((i * 3) * 256 / n); | |
55 colors[i] = new RGB(intensity, intensity, intensity); | |
56 } | |
57 return new PaletteData(colors); | |
58 } | |
59 | |
60 override bool isFileFormat(LEDataInputStream stream) { | |
61 try { | |
62 byte[3] signature; | |
63 stream.read(signature); | |
64 stream.unread(signature); | |
65 return signature[0] is 'G' && signature[1] is 'I' && signature[2] is 'F'; | |
66 } catch (Exception e) { | |
67 return false; | |
68 } | |
69 } | |
70 | |
71 /** | |
72 * Load the GIF image(s) stored in the input stream. | |
73 * Return an array of ImageData representing the image(s). | |
74 */ | |
75 override ImageData[] loadFromByteStream() { | |
76 byte[3] signature; | |
77 byte[3] versionBytes; | |
78 byte[7] block; | |
79 try { | |
80 inputStream.read(signature); | |
81 if (!(signature[0] is 'G' && signature[1] is 'I' && signature[2] is 'F')) | |
82 SWT.error(SWT.ERROR_INVALID_IMAGE); | |
83 | |
84 inputStream.read(versionBytes); | |
85 | |
86 inputStream.read(block); | |
87 } catch (IOException e) { | |
88 SWT.error(SWT.ERROR_IO, e); | |
89 } | |
90 screenWidth = (block[0] & 0xFF) | ((block[1] & 0xFF) << 8); | |
91 loader.logicalScreenWidth = screenWidth; | |
92 screenHeight = (block[2] & 0xFF) | ((block[3] & 0xFF) << 8); | |
93 loader.logicalScreenHeight = screenHeight; | |
94 byte bitField = block[4]; | |
95 backgroundPixel = block[5] & 0xFF; | |
96 //aspect = block[6] & 0xFF; | |
97 bitsPerPixel = ((bitField >> 4) & 0x07) + 1; | |
98 defaultDepth = (bitField & 0x7) + 1; | |
99 PaletteData palette = null; | |
100 if ((bitField & 0x80) !is 0) { | |
101 // Global palette. | |
102 //sorted = (bitField & 0x8) !is 0; | |
103 palette = readPalette(1 << defaultDepth); | |
104 } else { | |
105 // No global palette. | |
106 //sorted = false; | |
107 backgroundPixel = -1; | |
108 defaultDepth = bitsPerPixel; | |
109 } | |
110 loader.backgroundPixel = backgroundPixel; | |
111 | |
112 getExtensions(); | |
113 int id = readID(); | |
114 ImageData[] images = new ImageData[0]; | |
115 while (id is GIF_IMAGE_BLOCK_ID) { | |
116 ImageData image = readImageBlock(palette); | |
117 if (loader.hasListeners()) { | |
118 loader.notifyListeners(new ImageLoaderEvent(loader, image, 3, true)); | |
119 } | |
120 ImageData[] oldImages = images; | |
121 images = new ImageData[oldImages.length + 1]; | |
122 System.arraycopy(oldImages, 0, images, 0, oldImages.length); | |
123 images[images.length - 1] = image; | |
124 //images ~= image; | |
125 try { | |
126 /* Read the 0-byte terminator at the end of the image. */ | |
127 id = inputStream.read(); | |
128 if (id > 0) { | |
129 /* We read the terminator earlier. */ | |
130 byte[1] arr; | |
131 arr[0] = id; | |
132 inputStream.unread( arr ); | |
133 } | |
134 } catch (IOException e) { | |
135 SWT.error(SWT.ERROR_IO, e); | |
136 } | |
137 getExtensions(); | |
138 id = readID(); | |
139 } | |
140 return images; | |
141 } | |
142 | |
143 /** | |
144 * Read and return the next block or extension identifier from the file. | |
145 */ | |
146 int readID() { | |
147 try { | |
148 return inputStream.read(); | |
149 } catch (IOException e) { | |
150 SWT.error(SWT.ERROR_IO, e); | |
151 } | |
152 return -1; | |
153 } | |
154 | |
155 /** | |
156 * Read extensions until an image descriptor appears. | |
157 * In the future, if we care about the extensions, they | |
158 * should be properly grouped with the image data before | |
159 * which they appeared. Right now, the interesting parts | |
160 * of some extensions are kept, but the rest is discarded. | |
161 * Throw an error if an error occurs. | |
162 */ | |
163 void getExtensions() { | |
164 int id = readID(); | |
165 while (id !is GIF_IMAGE_BLOCK_ID && id !is GIF_TRAILER_ID && id > 0) { | |
166 if (id is GIF_EXTENSION_BLOCK_ID) { | |
167 readExtension(); | |
168 } else { | |
169 SWT.error(SWT.ERROR_INVALID_IMAGE); | |
170 } | |
171 id = readID(); | |
172 } | |
173 if (id is GIF_IMAGE_BLOCK_ID || id is GIF_TRAILER_ID) { | |
174 try { | |
175 byte[1] arr; | |
176 arr[0] = id; | |
177 inputStream.unread(arr); | |
178 } catch (IOException e) { | |
179 SWT.error(SWT.ERROR_IO, e); | |
180 } | |
181 } | |
182 } | |
183 | |
184 /** | |
185 * Read a control extension. | |
186 * Return the extension block data. | |
187 */ | |
188 byte[] readExtension() { | |
189 int extensionID = readID(); | |
190 if (extensionID is GIF_COMMENT_BLOCK_ID) | |
191 return readCommentExtension(); | |
192 if (extensionID is GIF_PLAIN_TEXT_BLOCK_ID) | |
193 return readPlainTextExtension(); | |
194 if (extensionID is GIF_GRAPHICS_CONTROL_BLOCK_ID) | |
195 return readGraphicsControlExtension(); | |
196 if (extensionID is GIF_APPLICATION_EXTENSION_BLOCK_ID) | |
197 return readApplicationExtension(); | |
198 // Otherwise, we don't recognize the block. If the | |
199 // field size is correct, we can just skip over | |
200 // the block contents. | |
201 try { | |
202 int extSize = inputStream.read(); | |
203 if (extSize < 0) { | |
204 SWT.error(SWT.ERROR_INVALID_IMAGE); | |
205 } | |
206 byte[] ext = new byte[extSize]; | |
207 inputStream.read(ext, 0, extSize); | |
208 return ext; | |
209 } catch (IOException e) { | |
210 SWT.error(SWT.ERROR_IO, e); | |
211 return null; | |
212 } | |
213 } | |
214 | |
215 /** | |
216 * We have just read the Comment extension identifier | |
217 * from the input stream. Read in the rest of the comment | |
218 * and return it. GIF comment blocks are variable size. | |
219 */ | |
220 byte[] readCommentExtension() { | |
221 try { | |
222 byte[] comment = new byte[0]; | |
223 byte[] block = new byte[255]; | |
224 int size = inputStream.read(); | |
225 while ((size > 0) && (inputStream.read(block, 0, size) !is -1)) { | |
226 byte[] oldComment = comment; | |
227 comment = new byte[oldComment.length + size]; | |
228 System.arraycopy(oldComment, 0, comment, 0, oldComment.length); | |
229 System.arraycopy(block, 0, comment, oldComment.length, size); | |
230 //comment ~= block[ 0 .. size ]; | |
231 size = inputStream.read(); | |
232 } | |
233 return comment; | |
234 } catch (Exception e) { | |
235 SWT.error(SWT.ERROR_IO, e); | |
236 return null; | |
237 } | |
238 } | |
239 | |
240 /** | |
241 * We have just read the PlainText extension identifier | |
242 * from the input stream. Read in the plain text info and text, | |
243 * and return the text. GIF plain text blocks are variable size. | |
244 */ | |
245 byte[] readPlainTextExtension() { | |
246 try { | |
247 // Read size of block = 0x0C. | |
248 inputStream.read(); | |
249 // Read the text information (x, y, width, height, colors). | |
250 byte[] info = new byte[12]; | |
251 inputStream.read(info); | |
252 // Read the text. | |
253 byte[] text = new byte[0]; | |
254 byte[] block = new byte[255]; | |
255 int size = inputStream.read(); | |
256 while ((size > 0) && (inputStream.read(block, 0, size) !is -1)) { | |
257 byte[] oldText = text; | |
258 text = new byte[oldText.length + size]; | |
259 System.arraycopy(oldText, 0, text, 0, oldText.length); | |
260 System.arraycopy(block, 0, text, oldText.length, size); | |
261 //text ~= block[ 0 .. size ]; | |
262 size = inputStream.read(); | |
263 } | |
264 return text; | |
265 } catch (Exception e) { | |
266 SWT.error(SWT.ERROR_IO, e); | |
267 return null; | |
268 } | |
269 } | |
270 | |
271 /** | |
272 * We have just read the GraphicsControl extension identifier | |
273 * from the input stream. Read in the control information, store | |
274 * it, and return it. | |
275 */ | |
276 byte[] readGraphicsControlExtension() { | |
277 try { | |
278 // Read size of block = 0x04. | |
279 inputStream.read(); | |
280 // Read the control block. | |
281 byte[] controlBlock = new byte[4]; | |
282 inputStream.read(controlBlock); | |
283 byte bitField = controlBlock[0]; | |
284 // Store the user input field. | |
285 //userInput = (bitField & 0x02) !is 0; | |
286 // Store the disposal method. | |
287 disposalMethod = (bitField >> 2) & 0x07; | |
288 // Store the delay time. | |
289 delayTime = (controlBlock[1] & 0xFF) | ((controlBlock[2] & 0xFF) << 8); | |
290 // Store the transparent color. | |
291 if ((bitField & 0x01) !is 0) { | |
292 transparentPixel = controlBlock[3] & 0xFF; | |
293 } else { | |
294 transparentPixel = -1; | |
295 } | |
296 // Read block terminator. | |
297 inputStream.read(); | |
298 return controlBlock; | |
299 } catch (Exception e) { | |
300 SWT.error(SWT.ERROR_IO, e); | |
301 return null; | |
302 } | |
303 } | |
304 | |
305 /** | |
306 * We have just read the Application extension identifier | |
307 * from the input stream. Read in the rest of the extension, | |
308 * look for and store 'number of repeats', and return the data. | |
309 */ | |
310 byte[] readApplicationExtension() { | |
311 try { | |
312 // Read size of block = 0x0B. | |
313 inputStream.read(); | |
314 // Read application identifier. | |
315 byte[] application = new byte[8]; | |
316 inputStream.read(application); | |
317 // Read authentication code. | |
318 byte[] authentication = new byte[3]; | |
319 inputStream.read(authentication); | |
320 // Read application data. | |
321 byte[] data = new byte[0]; | |
322 byte[] block = new byte[255]; | |
323 int size = inputStream.read(); | |
324 while ((size > 0) && (inputStream.read(block, 0, size) !is -1)) { | |
325 byte[] oldData = data; | |
326 data = new byte[oldData.length + size]; | |
327 System.arraycopy(oldData, 0, data, 0, oldData.length); | |
328 System.arraycopy(block, 0, data, oldData.length, size); | |
329 //data ~= block[ 0 .. size ]; | |
330 size = inputStream.read(); | |
331 } | |
332 // Look for the NETSCAPE 'repeat count' field for an animated GIF. | |
333 bool netscape = | |
334 application[0] is 'N' && | |
335 application[1] is 'E' && | |
336 application[2] is 'T' && | |
337 application[3] is 'S' && | |
338 application[4] is 'C' && | |
339 application[5] is 'A' && | |
340 application[6] is 'P' && | |
341 application[7] is 'E'; | |
342 bool authentic = | |
343 authentication[0] is '2' && | |
344 authentication[1] is '.' && | |
345 authentication[2] is '0'; | |
346 if (netscape && authentic && data[0] is 01) { //$NON-NLS-1$ //$NON-NLS-2$ | |
347 repeatCount = (data[1] & 0xFF) | ((data[2] & 0xFF) << 8); | |
348 loader.repeatCount = repeatCount; | |
349 } | |
350 return data; | |
351 } catch (Exception e) { | |
352 SWT.error(SWT.ERROR_IO, e); | |
353 return null; | |
354 } | |
355 } | |
356 | |
357 /** | |
358 * Return a DeviceIndependentImage representing the | |
359 * image block at the current position in the input stream. | |
360 * Throw an error if an error occurs. | |
361 */ | |
362 ImageData readImageBlock(PaletteData defaultPalette) { | |
363 int depth; | |
364 PaletteData palette; | |
365 byte[] block = new byte[9]; | |
366 try { | |
367 inputStream.read(block); | |
368 } catch (IOException e) { | |
369 SWT.error(SWT.ERROR_IO, e); | |
370 } | |
371 int left = (block[0] & 0xFF) | ((block[1] & 0xFF) << 8); | |
372 int top = (block[2] & 0xFF) | ((block[3] & 0xFF) << 8); | |
373 int width = (block[4] & 0xFF) | ((block[5] & 0xFF) << 8); | |
374 int height = (block[6] & 0xFF) | ((block[7] & 0xFF) << 8); | |
375 byte bitField = block[8]; | |
376 bool interlaced = (bitField & 0x40) !is 0; | |
377 //bool sorted = (bitField & 0x20) !is 0; | |
378 if ((bitField & 0x80) !is 0) { | |
379 // Local palette. | |
380 depth = (bitField & 0x7) + 1; | |
381 palette = readPalette(1 << depth); | |
382 } else { | |
383 // No local palette. | |
384 depth = defaultDepth; | |
385 palette = defaultPalette; | |
386 } | |
387 /* Work around: Ignore the case where a GIF specifies an | |
388 * invalid index for the transparent pixel that is larger | |
389 * than the number of entries in the palette. */ | |
390 if (transparentPixel > 1 << depth) { | |
391 transparentPixel = -1; | |
392 } | |
393 // Promote depth to next highest supported value. | |
394 if (!(depth is 1 || depth is 4 || depth is 8)) { | |
395 if (depth < 4) | |
396 depth = 4; | |
397 else | |
398 depth = 8; | |
399 } | |
400 if (palette is null) { | |
401 palette = grayRamp(1 << depth); | |
402 } | |
403 int initialCodeSize = -1; | |
404 try { | |
405 initialCodeSize = inputStream.read(); | |
406 } catch (IOException e) { | |
407 SWT.error(SWT.ERROR_IO, e); | |
408 } | |
409 if (initialCodeSize < 0) { | |
410 SWT.error(SWT.ERROR_INVALID_IMAGE); | |
411 } | |
412 ImageData image = ImageData.internal_new( | |
413 width, | |
414 height, | |
415 depth, | |
416 palette, | |
417 4, | |
418 null, | |
419 0, | |
420 null, | |
421 null, | |
422 -1, | |
423 transparentPixel, | |
424 SWT.IMAGE_GIF, | |
425 left, | |
426 top, | |
427 disposalMethod, | |
428 delayTime); | |
429 LZWCodec codec = new LZWCodec(); | |
430 codec.decode(inputStream, loader, image, interlaced, initialCodeSize); | |
431 return image; | |
432 } | |
433 | |
434 /** | |
435 * Read a palette from the input stream. | |
436 */ | |
437 PaletteData readPalette(int numColors) { | |
438 byte[] bytes = new byte[numColors * 3]; | |
439 try { | |
440 if (inputStream.read(bytes) !is bytes.length) | |
441 SWT.error(SWT.ERROR_INVALID_IMAGE); | |
442 } catch (IOException e) { | |
443 SWT.error(SWT.ERROR_IO, e); | |
444 } | |
445 RGB[] colors = new RGB[numColors]; | |
446 for (int i = 0; i < numColors; i++) | |
447 colors[i] = new RGB(bytes[i*3] & 0xFF, | |
448 bytes[i*3+1] & 0xFF, bytes[i*3+2] & 0xFF); | |
449 return new PaletteData(colors); | |
450 } | |
451 | |
452 override void unloadIntoByteStream(ImageLoader loader) { | |
453 | |
454 /* Step 1: Acquire GIF parameters. */ | |
455 ImageData[] data = loader.data; | |
456 int frameCount = data.length; | |
457 bool multi = frameCount > 1; | |
458 ImageData firstImage = data[0]; | |
459 int logicalScreenWidth = multi ? loader.logicalScreenWidth : firstImage.width; | |
460 int logicalScreenHeight = multi ? loader.logicalScreenHeight : firstImage.height; | |
461 int backgroundPixel = loader.backgroundPixel; | |
462 int depth = firstImage.depth; | |
463 PaletteData palette = firstImage.palette; | |
464 RGB[] colors = palette.getRGBs(); | |
465 short globalTable = 1; | |
466 | |
467 /* Step 2: Check for validity and global/local color map. */ | |
468 if (!(depth is 1 || depth is 4 || depth is 8)) { | |
469 SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH); | |
470 } | |
471 for (int i=0; i<frameCount; i++) { | |
472 if (data[i].palette.isDirect) { | |
473 SWT.error(SWT.ERROR_INVALID_IMAGE); | |
474 } | |
475 if (multi) { | |
476 if (!(data[i].height <= logicalScreenHeight && data[i].width <= logicalScreenWidth && data[i].depth is depth)) { | |
477 SWT.error(SWT.ERROR_INVALID_IMAGE); | |
478 } | |
479 if (globalTable is 1) { | |
480 RGB rgbs[] = data[i].palette.getRGBs(); | |
481 if (rgbs.length !is colors.length) { | |
482 globalTable = 0; | |
483 } else { | |
484 for (int j=0; j<colors.length; j++) { | |
485 if (!(rgbs[j].red is colors[j].red && | |
486 rgbs[j].green is colors[j].green && | |
487 rgbs[j].blue is colors[j].blue)) | |
488 globalTable = 0; | |
489 } | |
490 } | |
491 } | |
492 } | |
493 } | |
494 | |
495 try { | |
496 /* Step 3: Write the GIF89a Header and Logical Screen Descriptor. */ | |
497 outputStream.write(GIF89a); | |
498 int bitField = globalTable*128 + (depth-1)*16 + depth-1; | |
499 outputStream.writeShort(cast(short)logicalScreenWidth); | |
500 outputStream.writeShort(cast(short)logicalScreenHeight); | |
501 outputStream.write(bitField); | |
502 outputStream.write(backgroundPixel); | |
503 outputStream.write(0); // Aspect ratio is 1:1 | |
504 } catch (IOException e) { | |
505 SWT.error(SWT.ERROR_IO, e); | |
506 } | |
507 | |
508 /* Step 4: Write Global Color Table if applicable. */ | |
509 if (globalTable is 1) { | |
510 writePalette(palette, depth); | |
511 } | |
512 | |
513 /* Step 5: Write Application Extension if applicable. */ | |
514 if (multi) { | |
515 int repeatCount = loader.repeatCount; | |
516 try { | |
517 outputStream.write(GIF_EXTENSION_BLOCK_ID); | |
518 outputStream.write(GIF_APPLICATION_EXTENSION_BLOCK_ID); | |
519 outputStream.write(NETSCAPE2_0.length); | |
520 outputStream.write(NETSCAPE2_0); | |
521 outputStream.write(3); // Three bytes follow | |
522 outputStream.write(1); // Extension type | |
523 outputStream.writeShort(cast(short) repeatCount); | |
524 outputStream.write(0); // Block terminator | |
525 } catch (IOException e) { | |
526 SWT.error(SWT.ERROR_IO, e); | |
527 } | |
528 } | |
529 | |
530 for (int frame=0; frame<frameCount; frame++) { | |
531 | |
532 /* Step 6: Write Graphics Control Block for each frame if applicable. */ | |
533 if (multi || data[frame].transparentPixel !is -1) { | |
534 writeGraphicsControlBlock(data[frame]); | |
535 } | |
536 | |
537 /* Step 7: Write Image Header for each frame. */ | |
538 int x = data[frame].x; | |
539 int y = data[frame].y; | |
540 int width = data[frame].width; | |
541 int height = data[frame].height; | |
542 try { | |
543 outputStream.write(GIF_IMAGE_BLOCK_ID); | |
544 byte[] block = new byte[9]; | |
545 block[0] = cast(byte)(x & 0xFF); | |
546 block[1] = cast(byte)((x >> 8) & 0xFF); | |
547 block[2] = cast(byte)(y & 0xFF); | |
548 block[3] = cast(byte)((y >> 8) & 0xFF); | |
549 block[4] = cast(byte)(width & 0xFF); | |
550 block[5] = cast(byte)((width >> 8) & 0xFF); | |
551 block[6] = cast(byte)(height & 0xFF); | |
552 block[7] = cast(byte)((height >> 8) & 0xFF); | |
553 block[8] = cast(byte)(globalTable is 0 ? (depth-1) | 0x80 : 0x00); | |
554 outputStream.write(block); | |
555 } catch (IOException e) { | |
556 SWT.error(SWT.ERROR_IO, e); | |
557 } | |
558 | |
559 /* Step 8: Write Local Color Table for each frame if applicable. */ | |
560 if (globalTable is 0) { | |
561 writePalette(data[frame].palette, depth); | |
562 } | |
563 | |
564 /* Step 9: Write the actual data for each frame. */ | |
565 try { | |
566 outputStream.write(depth); // Minimum LZW Code size | |
567 } catch (IOException e) { | |
568 SWT.error(SWT.ERROR_IO, e); | |
569 } | |
570 (new LZWCodec()).encode(outputStream, data[frame]); | |
571 } | |
572 | |
573 /* Step 10: Write GIF terminator. */ | |
574 try { | |
575 outputStream.write(0x3B); | |
576 } catch (IOException e) { | |
577 SWT.error(SWT.ERROR_IO, e); | |
578 } | |
579 } | |
580 | |
581 /** | |
582 * Write out a GraphicsControlBlock to describe | |
583 * the specified device independent image. | |
584 */ | |
585 void writeGraphicsControlBlock(ImageData image) { | |
586 try { | |
587 outputStream.write(GIF_EXTENSION_BLOCK_ID); | |
588 outputStream.write(GIF_GRAPHICS_CONTROL_BLOCK_ID); | |
589 byte[] gcBlock = new byte[4]; | |
590 gcBlock[0] = 0; | |
591 gcBlock[1] = 0; | |
592 gcBlock[2] = 0; | |
593 gcBlock[3] = 0; | |
594 if (image.transparentPixel !is -1) { | |
595 gcBlock[0] = cast(byte)0x01; | |
596 gcBlock[3] = cast(byte)image.transparentPixel; | |
597 } | |
598 if (image.disposalMethod !is 0) { | |
599 gcBlock[0] |= cast(byte)((image.disposalMethod & 0x07) << 2); | |
600 } | |
601 if (image.delayTime !is 0) { | |
602 gcBlock[1] = cast(byte)(image.delayTime & 0xFF); | |
603 gcBlock[2] = cast(byte)((image.delayTime >> 8) & 0xFF); | |
604 } | |
605 outputStream.write(cast(byte)gcBlock.length); | |
606 outputStream.write(gcBlock); | |
607 outputStream.write(0); // Block terminator | |
608 } catch (IOException e) { | |
609 SWT.error(SWT.ERROR_IO, e); | |
610 } | |
611 } | |
612 | |
613 /** | |
614 * Write the specified palette to the output stream. | |
615 */ | |
616 void writePalette(PaletteData palette, int depth) { | |
617 byte[] bytes = new byte[(1 << depth) * 3]; | |
618 int offset = 0; | |
619 for (int i = 0; i < palette.colors.length; i++) { | |
620 RGB color = palette.colors[i]; | |
621 bytes[offset] = cast(byte)color.red; | |
622 bytes[offset + 1] = cast(byte)color.green; | |
623 bytes[offset + 2] = cast(byte)color.blue; | |
624 offset += 3; | |
625 } | |
626 try { | |
627 outputStream.write(bytes); | |
628 } catch (IOException e) { | |
629 SWT.error(SWT.ERROR_IO, e); | |
630 } | |
631 } | |
632 } |