1 /* EXTRAITS DE LA LICENCE
2 Copyright CEA, contributeurs : Luc BILLARD et Damien
3 CALISTE, laboratoire L_Sim, (2001-2005)
4
5 Adresse mèl :
6 BILLARD, non joignable par mèl ;
7 CALISTE, damien P caliste AT cea P fr.
8
9 Ce logiciel est un programme informatique servant à visualiser des
10 structures atomiques dans un rendu pseudo-3D.
11
12 Ce logiciel est régi par la licence CeCILL soumise au droit français et
13 respectant les principes de diffusion des logiciels libres. Vous pouvez
14 utiliser, modifier et/ou redistribuer ce programme sous les conditions
15 de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
16 sur le site "http://www.cecill.info".
17
18 Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
19 pris connaissance de la licence CeCILL, et que vous en avez accepté les
20 termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel).
21 */
22
23 /* LICENCE SUM UP
24 Copyright CEA, contributors : Luc BILLARD et Damien
25 CALISTE, laboratoire L_Sim, (2001-2005)
26
27 E-mail address:
28 BILLARD, not reachable any more ;
29 CALISTE, damien P caliste AT cea P fr.
30
31 This software is a computer program whose purpose is to visualize atomic
32 configurations in 3D.
33
34 This software is governed by the CeCILL license under French law and
35 abiding by the rules of distribution of free software. You can use,
36 modify and/ or redistribute the software under the terms of the CeCILL
37 license as circulated by CEA, CNRS and INRIA at the following URL
38 "http://www.cecill.info".
39
40 The fact that you are presently reading this means that you have had
41 knowledge of the CeCILL license and that you accept its terms. You can
42 find a copy of this licence shipped with this software at Documentation/licence.en.txt.
43 */
44 #include "dumpToGif.h"
45
46 #include "stdlib.h"
47 #include "stdio.h"
48 #include "string.h"
49 #include <visu_tools.h>
50
51 #include <glib.h>
52 /* #include <unistd.h> */
53 #include <time.h>
54
55 /**
56 * SECTION:dumpToGif
57 * @short_description: add an export capability into GIF files.
58 *
59 * <para>This provides a write routine to export V_Sim views into GIF
60 * files.</para>
61 *
62 * <para>Most of the routines used there have been modified by
63 * L. Billard (1997 - 2001) from the original ones taken from the
64 * ImageMagick package of cristy@dupont.com.</para>
65 *
66 * <para>The goal of this is to reduce the colour span into 256 to be
67 * able to output as GIF file.</para>
68 *
69 * <note>
70 * <para>Copyright 1994 E. I. du Pont de Nemours & Company</para>
71 * <para>Permission to use, copy, modify, distribute, and sell this
72 * software and its documentation for any purpose is hereby granted
73 * without fee, provided that the above copyright notice appear in all
74 * copies and that both that copyright notice and this permission
75 * notice appear in supporting documentation, and that the name of
76 * E. I. du Pont de Nemours & Company not be used in advertising or
77 * publicity pertaining to distribution of the software without
78 * specific, written prior permission. E. I. du Pont de Nemours &
79 * Company makes no representations about the suitability of this
80 * software for any purpose. It is provided "as is" without express
81 * or implied warranty.</para>
82 * <para>E. I. du Pont de Nemours & Company disclaims all warranties
83 * with regard to this software, including all implied warranties of
84 * merchantability and fitness, in no event shall E. I. du Pont de
85 * Nemours & Company be liable for any special, indirect or
86 * consequential damages or any damages whatsoever resulting from loss
87 * of use, data or profits, whether in an action of contract,
88 * negligence or other tortious action, arising out of or in
89 * connection with the use or performance of this software.</para>
90 * </note>
91 */
92
93 static unsigned char *image;
94
95 #define _XOPEN_SOURCE_EXTENDED
96
97 static Image *img;
98
99 static FILE *file;
100
101 #define False 0
102 #define True 1
103 #define Max(x,y) (((x) > (y)) ? (x) : (y))
104 #define Min(x,y) (((x) < (y)) ? (x) : (y))
105
106
107 #define MaxMapSize 65535
108 #define MaxRGB 255
109
110
111 #define color_number number_colors
112 #define MaxNodes 266817
113 #define MaxTreeDepth 8 /* Log2(MaxRGB) */
114 #define NodesInAList 2048
115
116 static gpointer waitData;
117 static ToolVoidDataFunc waitFunc;
118
119
120 typedef struct _Node {
121 struct _Node *parent, *child[8];
122 unsigned char id, level, children, mid_red, mid_green, mid_blue;
123 unsigned long number_colors, number_unique,
124 total_red, total_green, total_blue;
125 } Node;
126
127 typedef struct _Nodes {
128 Node nodes[NodesInAList];
129 struct _Nodes *next;
130 } Nodes;
131
132 typedef struct _Cube{
133 Node *root;
134 ColorPacket color, *colormap;
135 guint depth;
136 unsigned long colors, pruning_threshold, next_pruning_threshold,
137 distance, squares[MaxRGB+MaxRGB+1];
138 guint shift[MaxTreeDepth+1], nodes, free_nodes, color_number;
139 Node *next_node;
140 Nodes *node_queue;
141 } Cube;
142
143 static Cube cube;
144
145 static guint tree_depth = 8;
146
147 static guint Assignment();
148 static guint Classification(GError **error);
149 static void ClosestColor(register Node *node);
150 static void Map(register Node *node);
151 static guint DitherImage();
152 static guint InitializeCube(guint number_pixels, GError **error);
153 static Node *InitializeNode(
154 guint id,guint level,Node *parent,
155 guint mid_red,guint mid_green,guint mid_blue);
156 static void PruneChild(register Node *node);
157 static void PruneLevel(register Node *node);
158 static void Reduce(register Node *node);
159 static void Reduction(guint number_colors);
160
161 static guint LZWEncodeImage(guint data_size);
162 static void LSBFirstWriteShort(guint value);
163
164 static gboolean writeViewInGifFormat(ToolFileFormat *format, const char* filename,
165 VisuGlNodeScene *scene, guint width, guint height,
166 GError **error, ToolVoidDataFunc functionWait,
167 gpointer data);
168
169
170 /******************************************************************************/
171 /******************************************************************************/
172
dumpToGif_setImage(Image * data)173 void dumpToGif_setImage(Image *data)
174 {
175 img = data;
176 }
177
178 /******************************************************************************/
179
Assignment()180 guint Assignment() {
181
182
183 img->colormap=g_malloc(cube.colors*sizeof(ColorPacket));
184 cube.colormap=img->colormap;
185 cube.colors=0;
186 Map(cube.root);
187 img->colors=(guint) cube.colors;
188 if (DitherImage()) return 1;
189 return 0;
190 }
191
192 /******************************************************************************/
193
Classification(GError ** error)194 guint Classification(GError **error) {
195
196 register guint i;
197 register Node *node;
198 register ColorPacket *p;
199 register guint bisect, id, level;
200
201 p=img->pixels;
202 for (i=0; i < img->packets; i++) {
203 if (cube.nodes > MaxNodes) {
204 /* Prune one level if the color tree is too large. */
205 PruneLevel(cube.root);
206 cube.depth--;
207 }
208 /* Start at the root and descend the color cube tree. */
209 node=cube.root;
210 for (level=1; level <= cube.depth; level++) {
211 id=(p->red > node->mid_red ? 1 : 0) |
212 (p->green > node->mid_green ? 1 : 0) << 1 |
213 (p->blue > node->mid_blue ? 1 : 0) << 2;
214 if (node->child[id] == (Node *) NULL) {
215 /* Set colors of new node to contain pixel. */
216 node->children|=1 << id;
217 bisect=(guint) (1 << (MaxTreeDepth-level)) >> 1;
218 node->child[id]=InitializeNode(id,level,node,
219 node->mid_red+(id & 1 ? bisect : -bisect),
220 node->mid_green+(id & 2 ? bisect : -bisect),
221 node->mid_blue+(id & 4 ? bisect : -bisect));
222 if (node->child[id] == (Node *) NULL)
223 {
224 *error = g_error_new(VISU_DUMP_ERROR, DUMP_ERROR_ENCODE,
225 _("Unable to quantize image, "
226 "initialisation failed for node child %d."), id);
227 return 1;
228 }
229 if (level == cube.depth) cube.colors++;
230 }
231 /*
232 Record the number of colors represented by this node.
233 Shift by level in the color description tree.
234 */
235 node=node->child[id];
236 node->number_colors+=1 << cube.shift[level];
237 }
238 /*
239 Increment unique color count and sum RGB values for this leaf for later
240 derivation of the mean cube color.
241 */
242 node->number_unique+=1;
243 node->total_red+=p->red;
244 node->total_green+=p->green;
245 node->total_blue+=p->blue;
246 p++;
247 }
248 return 0;
249 }
250
251 /******************************************************************************/
252
ClosestColor(register Node * node)253 void ClosestColor(register Node *node) {
254
255 register guint id;
256
257 /* Traverse any children. */
258 if (node->children != 0)
259 for (id=0; id < 8; id++)
260 if (node->children & (1 << id))
261 ClosestColor(node->child[id]);
262 if (node->number_unique != 0) {
263 register ColorPacket *color;
264 register guint blue_distance, green_distance, red_distance;
265 register unsigned long distance;
266
267 /* Determine if this color is "closest". */
268 color=cube.colormap+node->color_number;
269 red_distance=(int) color->red-(int) cube.color.red+MaxRGB;
270 green_distance=(int) color->green-(int) cube.color.green+MaxRGB;
271 blue_distance=(int) color->blue-(int) cube.color.blue+MaxRGB;
272 distance=cube.squares[red_distance]+
273 cube.squares[green_distance]+
274 cube.squares[blue_distance];
275 if (distance < cube.distance) {
276 cube.distance=distance;
277 cube.color_number=(unsigned short) node->color_number;
278 }
279 }
280 }
281
282 /******************************************************************************/
283
Map(register Node * node)284 void Map(register Node *node) {
285 register guint id;
286
287 /* Traverse any children*/
288 if (node->children != 0)
289 for (id=0; id < 8; id++)
290 if (node->children & (1 << id))
291 Map(node->child[id]);
292 if (node->number_unique > 0) {
293 /* Map entry is defined by the mean color in this cube. */
294 cube.colormap[cube.colors].red=(unsigned char)
295 ((node->total_red+(node->number_unique >> 1))/node->number_unique);
296 cube.colormap[cube.colors].green=(unsigned char)
297 ((node->total_green+(node->number_unique >> 1))/node->number_unique);
298 cube.colormap[cube.colors].blue=(unsigned char)
299 ((node->total_blue+(node->number_unique >> 1))/node->number_unique);
300 node->color_number=cube.colors++;
301 }
302 }
303
304 /******************************************************************************/
305
DitherImage()306 guint DitherImage() {
307
308 #define MaxError 16
309
310 typedef struct {
311 int red, green, blue;
312 } ErrorPacket;
313 ErrorPacket *error;
314 int *cache;
315 register int blue_error, green_error, red_error, step;
316 register Node *node;
317 register ColorPacket *q;
318 register ErrorPacket *cs, *ns;
319 register unsigned char *range_limit;
320 register guint id;
321 unsigned char blue, green, *range_table, red;
322 guint i, x, y;
323 unsigned short index;
324
325
326 cache=g_malloc((1 << 18)*sizeof(int));
327 error=g_malloc(((img->columns+2) << 1)*sizeof(ErrorPacket));
328 range_table=g_malloc(3*(MaxRGB+1)*sizeof(unsigned char));
329
330 for (i=0; i < (1 << 18); i++) cache[i]=(-1);
331 for (i=0; i < ((img->columns+2) << 1); i++) {
332 error[i].red=0;
333 error[i].green=0;
334 error[i].blue=0;
335 }
336 for (i=0; i <= MaxRGB; i++) {
337 range_table[i]=0;
338 range_table[i+(MaxRGB+1)]=(unsigned char) i;
339 range_table[i+(MaxRGB+1)*2]=MaxRGB;
340 }
341 range_limit=range_table+(MaxRGB+1);
342
343 for (y=0; y < img->rows; y++) {
344 q=img->pixels+img->columns*y;
345 cs=error+1;
346 ns=error+(img->columns+2)+1;
347 step=1;
348 if (y & 0x01) {
349 /* Distribute error right-to-left for odd scanlines. */
350 q+=(img->columns-1);
351 cs=error+(img->columns+2)+(img->columns-1)+1;
352 ns=error+(img->columns-1)+1;
353 step=(-1);
354 }
355 for (x=0; x < img->columns; x++) {
356 red_error=(cs->red+8)/16;
357 if (red_error > MaxError) red_error=MaxError;
358 else if (red_error < -MaxError) red_error=(-MaxError);
359 green_error=(cs->green+8)/16;
360 if (green_error > MaxError) green_error=MaxError;
361 else if (green_error < -MaxError) green_error=(-MaxError);
362 blue_error=(cs->blue+8)/16;
363 if (blue_error > MaxError) blue_error=MaxError;
364 else if (blue_error < -MaxError) blue_error=(-MaxError);
365 red=range_limit[q->red+red_error];
366 green=range_limit[q->green+green_error];
367 blue=range_limit[q->blue+blue_error];
368 i=(red >> 2) << 12 | (green >> 2) << 6 | blue >> 2;
369 if (cache[i] < 0) {
370 /* Identify the deepest node containing the pixel's color. */
371 node=cube.root;
372 for ( ; ; ) {
373 id=(red > node->mid_red ? 1 : 0) |
374 (green > node->mid_green ? 1 : 0) << 1 |
375 (blue > node->mid_blue ? 1 : 0) << 2;
376 if ((node->children & (1 << id)) == 0) break;
377 node=node->child[id];
378 }
379 /* Find closest color among siblings and their children. */
380 cube.color.red=red;
381 cube.color.green=green;
382 cube.color.blue=blue;
383 cube.distance=(unsigned long) (~0);
384 ClosestColor(node->parent);
385 cache[i]=cube.color_number;
386 }
387 index=(unsigned short) cache[i];
388 red_error=(int) red-(int) cube.colormap[index].red;
389 green_error=(int) green-(int) cube.colormap[index].green;
390 blue_error=(int) blue-(int) cube.colormap[index].blue;
391 q->index=index;
392 q+=step;
393 /* Propagate the error in these proportions:
394 Q 7/16
395 3/16 5/16 1/16
396 */
397 cs->red=0;
398 cs->green=0;
399 cs->blue=0;
400 cs+=step;
401 cs->red+=7*red_error;
402 cs->green+=7*green_error;
403 cs->blue+=7*blue_error;
404 ns-=step;
405 ns->red+=3*red_error;
406 ns->green+=3*green_error;
407 ns->blue+=3*blue_error;
408 ns+=step;
409 ns->red+=5*red_error;
410 ns->green+=5*green_error;
411 ns->blue+=5*blue_error;
412 ns+=step;
413 ns->red+=red_error;
414 ns->green+=green_error;
415 ns->blue+=blue_error;
416 }
417 }
418
419 g_free(range_table);
420 g_free(error);
421 g_free(cache);
422 return 0;
423 }
424
425 /******************************************************************************/
426
InitializeCube(guint number_pixels,GError ** error)427 guint InitializeCube(guint number_pixels, GError **error) {
428
429 char c;
430 register int i;
431 guint bits, level, max_shift;
432
433 cube.node_queue=(Nodes *) NULL;
434 cube.nodes=0;
435 cube.free_nodes=0;
436 cube.depth=Min(tree_depth,8);
437 /* Initialize the shift values. */
438 c=1;
439 for (bits=0; c != (char) 0; bits++) c<<=1;
440 for (max_shift=sizeof(guint)*bits; number_pixels != 0; max_shift--)
441 number_pixels>>=1;
442 for (level=0; level <= cube.depth; level++) {
443 cube.shift[level]=max_shift;
444 if (max_shift != 0) max_shift--;
445 }
446 /* Initialize root node. */
447 cube.root=InitializeNode(0,0,(Node *) NULL,
448 (MaxRGB+1) >> 1,(MaxRGB+1) >> 1, (MaxRGB+1) >> 1);
449 if (cube.root == (Node *) NULL)
450 {
451 *error = g_error_new(VISU_DUMP_ERROR, DUMP_ERROR_ENCODE,
452 _("Unable to quantize image, initialisation failed."));
453 return 1;
454 }
455 cube.root->parent=cube.root;
456 cube.root->number_colors=(unsigned long) (~0);
457 cube.colors=0;
458 /* Initialize the square values. */
459 for (i=(-MaxRGB); i <= MaxRGB; i++)
460 cube.squares[i+MaxRGB]=i*i;
461
462 return 0;
463 }
464
465 /******************************************************************************/
466
InitializeNode(guint id,guint level,Node * parent,guint mid_red,guint mid_green,guint mid_blue)467 Node *InitializeNode(
468 guint id,guint level,Node *parent,
469 guint mid_red,guint mid_green,guint mid_blue) {
470
471 register int i;
472
473 register Node *node;
474
475 if (cube.free_nodes == 0) {
476 register Nodes *nodes;
477
478 /* Allocate a new nodes of nodes. */
479 nodes=(Nodes *) malloc(sizeof(Nodes));
480 if (nodes == (Nodes *) NULL)
481 return((Node *) NULL);
482 nodes->next=cube.node_queue;
483 cube.node_queue=nodes;
484 cube.next_node=nodes->nodes;
485 cube.free_nodes=NodesInAList;
486 }
487 cube.nodes++;
488 cube.free_nodes--;
489 node=cube.next_node++;
490 node->parent=parent;
491 for (i=0; i < 8; i++)
492 node->child[i]=(Node *) NULL;
493 node->id=id;
494 node->level=level;
495 node->children=0;
496 node->mid_red=mid_red;
497 node->mid_green=mid_green;
498 node->mid_blue=mid_blue;
499 node->number_colors=0;
500 node->number_unique=0;
501 node->total_red=0;
502 node->total_green=0;
503 node->total_blue=0;
504 return(node);
505 }
506
507 /******************************************************************************/
508
PruneChild(register Node * node)509 void PruneChild(register Node *node) {
510 register Node *parent;
511
512 /* Merge color statistics into parent. */
513 parent=node->parent;
514 parent->children&=~(1 << node->id);
515 parent->number_unique+=node->number_unique;
516 parent->total_red+=node->total_red;
517 parent->total_green+=node->total_green;
518 parent->total_blue+=node->total_blue;
519 cube.nodes--;
520 }
521
522 /******************************************************************************/
523
PruneLevel(register Node * node)524 void PruneLevel(register Node *node) {
525 register int id;
526
527 /* Traverse any children. */
528 if (node->children != 0)
529 for (id=0; id < 8; id++)
530 if (node->children & (1 << id))
531 PruneLevel(node->child[id]);
532 if (node->level == cube.depth)
533 PruneChild(node);
534 }
535
536 /******************************************************************************/
537
Reduce(register Node * node)538 void Reduce(register Node *node) {
539 register guint id;
540
541 /* Traverse any children. */
542 if (node->children != 0)
543 for (id=0; id < 8; id++)
544 if (node->children & (1 << id))
545 Reduce(node->child[id]);
546
547 /* Node is a colormap entry if it has unique colors. */
548 if (node->number_unique > 0) cube.colors++;
549
550 /* Find minimum pruning threshold. */
551 if (node->number_colors < cube.next_pruning_threshold)
552 cube.next_pruning_threshold=node->number_colors;
553 if (node->number_colors <= cube.pruning_threshold)
554 PruneChild(node); /* Node has a sub-threshold color count */
555 }
556
557 /******************************************************************************/
558
Reduction(guint number_colors)559 void Reduction(guint number_colors)
560 {
561 float i;
562
563 i = 0.;
564 cube.next_pruning_threshold=1;
565 while (cube.colors > number_colors) {
566 cube.pruning_threshold=cube.next_pruning_threshold;
567 cube.next_pruning_threshold=cube.root->number_colors-1;
568 cube.colors=0;
569 i += 0.025;
570 if (waitFunc && (int)(i * 100.) % 100 == 0 && i < 50.)
571 waitFunc(waitData);
572 Reduce(cube.root);
573 }
574 while (waitFunc && i<50.)
575 {
576 i = i + 1.;
577 waitFunc(waitData);
578 }
579 }
580
581 /******************************************************************************/
582
dumpToGif_quantizeImage(guint number_colors,GError ** error,ToolVoidDataFunc functionWait,gpointer data)583 guint dumpToGif_quantizeImage(guint number_colors, GError **error,
584 ToolVoidDataFunc functionWait, gpointer data)
585 {
586 Nodes *nodes;
587
588 waitFunc = functionWait;
589 waitData = data;
590
591 /* Reduce the number of colors in the continuous tone image. */
592 if (number_colors > MaxMapSize) number_colors=MaxMapSize;
593 if(InitializeCube(img->columns*img->rows, error)) return 1;
594
595 if(Classification(error)) return 1;
596 Reduction(number_colors);
597 if(Assignment(error)) return 1;
598
599 do {
600 nodes=cube.node_queue->next;
601 (void)free(cube.node_queue);
602 cube.node_queue=nodes;
603 }
604 while (cube.node_queue != (Nodes *) NULL);
605
606 return 0;
607
608 }
609
610 /******************************************************************************/
611 /******************************************************************************/
612
613 /* Function LZWEncodeImage compresses an image via LZW-coding. */
LZWEncodeImage(guint data_size)614 guint LZWEncodeImage(guint data_size) {
615 #define MaxCode(number_bits) ((1 << (number_bits))-1)
616 #define MaxHashTable 5003
617 #define MaxLZWBits 12
618 #define MaxLZWTable (1 << MaxLZWBits)
619 #define LZWOutputCode(code) \
620 { \
621 if (bits > 0) datum|=((long) code << bits); \
622 else datum=(long) code; \
623 bits+=number_bits; \
624 while (bits >= 8) { \
625 packet[byte_count++]=(unsigned char) (datum & 0xff); \
626 if (byte_count >= 254) { \
627 (void) fputc(byte_count,file); \
628 (void) fwrite((char *) packet,1,byte_count,file); \
629 byte_count=0; \
630 } \
631 datum>>=8; \
632 bits-=8; \
633 } \
634 if (free_code > max_code) { \
635 number_bits++; \
636 if (number_bits == MaxLZWBits) max_code=MaxLZWTable; \
637 else max_code=MaxCode(number_bits); \
638 } \
639 }
640
641 int bits, byte_count, next_pixel, number_bits;
642 long datum;
643 register unsigned i;
644 register int displacement, j;
645 register ColorPacket *p;
646 short clear_code, end_of_information_code;
647 short free_code, *hash_code, *hash_prefix, index, max_code, waiting_code;
648 unsigned char *packet, *hash_suffix;
649
650
651
652 packet=g_malloc(256*sizeof(unsigned char));
653 hash_code=g_malloc(MaxHashTable*sizeof(short));
654 hash_prefix=g_malloc(MaxHashTable*sizeof(short));
655 hash_suffix=g_malloc(MaxHashTable*sizeof(unsigned char));
656
657 number_bits=data_size;
658 max_code=MaxCode(number_bits);
659 clear_code=((short) 1 << (data_size-1));
660 end_of_information_code=clear_code+1;
661 free_code=clear_code+2;
662 byte_count=0;
663 datum=0;
664 bits=0;
665 for (i=0; i < MaxHashTable; i++) hash_code[i]=0;
666 LZWOutputCode(clear_code);
667
668 p=img->pixels;
669 waiting_code=p->index;
670 for (i=1; i < (img->columns*img->rows); i++) {
671
672 if (waitFunc && i % (img->columns*img->rows / 50) == 0)
673 waitFunc(waitData);
674
675 p++;
676 index=p->index & 0xff;
677 j=(int) ((int) index << (MaxLZWBits-8))+waiting_code;
678 if (j >= MaxHashTable) j-=MaxHashTable;
679 if (hash_code[j] > 0) {
680 if ((hash_prefix[j] == waiting_code) && (hash_suffix[j] == index)) {
681 waiting_code=hash_code[j];
682 continue;
683 }
684 if (j == 0) displacement=1;
685 else displacement=MaxHashTable-j;
686 next_pixel=False;
687 for ( ; ; ) {
688 j-=displacement;
689 if (j < 0) j+=MaxHashTable;
690 if (hash_code[j] == 0) break;
691 if ((hash_prefix[j] == waiting_code) && (hash_suffix[j] == index)) {
692 waiting_code=hash_code[j];
693 next_pixel=True;
694 break;
695 }
696 }
697 if (next_pixel == True) continue;
698 }
699 LZWOutputCode(waiting_code);
700 if (free_code < MaxLZWTable) {
701 hash_code[j]=free_code++;
702 hash_prefix[j]=waiting_code;
703 hash_suffix[j]=(unsigned char)index;
704 }
705 else {
706 for (j=0; j < MaxHashTable; j++) hash_code[j]=0;
707 free_code=clear_code+2;
708 LZWOutputCode(clear_code);
709 number_bits=data_size;
710 max_code=MaxCode(number_bits);
711 }
712 waiting_code=index;
713 }
714
715
716 LZWOutputCode(waiting_code);
717 LZWOutputCode(end_of_information_code);
718 if (bits > 0) {
719 /* Add a character to current packet. */
720 packet[byte_count++]=(unsigned char) (datum & 0xff);
721 if (byte_count >= 254) {
722 (void) fputc(byte_count,file);
723 (void) fwrite((char *) packet,1,byte_count,file);
724 byte_count=0;
725 }
726 }
727
728 if (byte_count > 0) {
729 (void) fputc(byte_count,file);
730 (void) fwrite((char *) packet,1,byte_count,file);
731 }
732
733 g_free(hash_suffix);
734 g_free(hash_prefix);
735 g_free(hash_code);
736 g_free(packet);
737
738 if (i < img->packets) return(False);
739 return(True);
740
741 }
742
743
744 /******************************************************************************/
745
746 /* LSBFirstWriteShort writes a long value as a 16 bit quantity in
747 least-significant byte first order.
748 */
LSBFirstWriteShort(guint value)749 void LSBFirstWriteShort(guint value) {
750
751 unsigned char buffer[2];
752
753 buffer[0]=(unsigned char) (value);
754 buffer[1]=(unsigned char) ((value) >> 8);
755 (void) fwrite((char *) buffer,1,2,file);
756 }
757
758
759 /******************************************************************************/
760
dumpToGif_syncImage(void)761 void dumpToGif_syncImage(void) {
762
763 register guint i;
764 register ColorPacket *p;
765 register unsigned short index;
766
767 p=img->pixels;
768 for (i=0; i < img->packets; i++) {
769 index=p->index;
770 p->red=img->colormap[index].red;
771 p->green=img->colormap[index].green;
772 p->blue=img->colormap[index].blue;
773 p++;
774 }
775 }
776
777 /******************************************************************************/
778
write_comment_comm(unsigned char comm[])779 static void write_comment_comm(unsigned char comm[]) {
780
781 size_t size;
782 unsigned char c[256];
783
784 /* Extension Introducer */
785 c[0] = 0x21;
786 (void)fwrite(c, sizeof(unsigned char), 1, file);
787
788 /* Comment Label */
789 c[0] = 0xFE;
790 (void)fwrite(c, sizeof(unsigned char), 1, file);
791
792 /* Data Size ( entre 1 et 255 ) */
793 size = strlen((char *)comm);
794 c[0] = (unsigned char)size;
795 (void)fwrite(c, sizeof(unsigned char), 1, file);
796
797 /* Data */
798 (void)fwrite(comm, sizeof(unsigned char), size, file);
799
800 /* Block Terminator */
801 c[0] = '\0';
802 (void)fwrite(c, sizeof(unsigned char), 1, file);
803
804 }
805
806 /******************************************************************************/
807
dumpToGif_init()808 VisuDump* dumpToGif_init()
809 {
810 VisuDump *gif;
811 const gchar *typeGIF[] = {"*.gif", (char*)0};
812 #define descrGIF _("Gif (256 colors) file")
813
814 gif = VISU_DUMP(visu_dump_scene_new(descrGIF, typeGIF, writeViewInGifFormat, FALSE));
815
816 waitData = (gpointer)0;
817 waitFunc = (ToolVoidDataFunc)0;
818
819 return gif;
820 }
821
822
writeViewInGifFormat(ToolFileFormat * format _U_,const char * filename,VisuGlNodeScene * scene,guint width,guint height,GError ** error,ToolVoidDataFunc functionWait,gpointer data)823 static gboolean writeViewInGifFormat(ToolFileFormat *format _U_, const char* filename,
824 VisuGlNodeScene *scene, guint width, guint height,
825 GError **error, ToolVoidDataFunc functionWait,
826 gpointer data)
827 {
828 register guint i;
829 register ColorPacket *q;
830 register unsigned char *p;
831 unsigned char bits_per_pixel, c;
832 guint status;
833 GArray *imageData;
834
835 g_return_val_if_fail(error && !*error, FALSE);
836
837 imageData = visu_gl_ext_set_getPixmapData(VISU_GL_EXT_SET(scene),
838 width, height, FALSE);
839 if (!imageData)
840 {
841 *error = g_error_new(VISU_DUMP_ERROR, DUMP_ERROR_OPENGL,
842 _("Can't dump OpenGL area to data.\n"));
843 return FALSE;
844 }
845
846 waitData = data;
847 waitFunc = functionWait;
848 image = (unsigned char*)imageData->data;
849
850 DBG_fprintf(stderr, "Dump Gif : begin export in %dx%d...\n", width, height);
851
852 file = fopen(filename, "wb");
853 if(!file)
854 {
855 *error = g_error_new(VISU_DUMP_ERROR, DUMP_ERROR_FILE,
856 _("Cannot open file (to write in)."));
857 return FALSE;
858 }
859
860 img=g_malloc(sizeof(Image));
861 img->colormap = (ColorPacket*)0;
862
863 img->columns = width;
864 img->rows = height;
865 img->packets=img->columns*img->rows;
866 img->pixels=g_malloc(img->packets*sizeof(ColorPacket));
867 q=img->pixels;
868 p=image;
869 for (i=0; i < img->packets; i++) {
870 q->red=(*p++);
871 q->green=(*p++);
872 q->blue=(*p++);
873 q->index=0;
874 q++;
875 }
876
877 if(dumpToGif_quantizeImage(256, error, waitFunc, data))
878 {
879 g_free(img->pixels);
880 if (img->colormap)
881 g_free(img->colormap);
882 g_free(img);
883 return FALSE;
884 }
885 dumpToGif_syncImage();
886
887 for (bits_per_pixel=1; bits_per_pixel < 8; bits_per_pixel++)
888 if ((1 << bits_per_pixel) >= (int)img->colors) break;
889
890
891 (void) fwrite("GIF89a",1,6,file);
892 LSBFirstWriteShort(img->columns);
893 LSBFirstWriteShort(img->rows);
894 c=0x80; /* global colormap */
895 c|=(8-1) << 4; /* color resolution */
896 c|=(bits_per_pixel-1); /* size of global colormap */
897 (void) fputc((int)(char) c,file);
898 (void) fputc(0x0,file); /* background color */
899 (void) fputc(0x0,file); /* reserved */
900
901
902 for (i=0; i < img->colors; i++) {
903 (void) fputc((int)(char) img->colormap[i].red,file);
904 (void) fputc((int)(char) img->colormap[i].green,file);
905 (void) fputc((int)(char) img->colormap[i].blue,file);
906 }
907 for ( ; i < (guint)(1 << bits_per_pixel) ; i++) {
908 (void) fputc(0x0,file);
909 (void) fputc(0x0,file);
910 (void) fputc(0x0,file);
911 }
912 /* écriture du commentaire */
913 write_comment_comm((unsigned char *)"Image créée par le programme V_Sim\n"
914 "Auteur : L. BILLARD");
915
916 (void) fputc(',',file); /* image separator */
917
918
919 LSBFirstWriteShort(0);
920 LSBFirstWriteShort(0);
921 LSBFirstWriteShort(img->columns);
922 LSBFirstWriteShort(img->rows);
923 (void) fputc(0x0,file);
924 c=Max(bits_per_pixel,2);
925 (void) fputc((int)(char) c,file);
926 status=LZWEncodeImage(Max(bits_per_pixel,2)+1);
927 if (status == False)
928 {
929 *error = g_error_new(VISU_DUMP_ERROR, DUMP_ERROR_ENCODE,
930 _("Fail to compress the GIF file."));
931 g_free(img->pixels);
932 g_free(img->colormap);
933 g_free(img);
934 return FALSE;
935 }
936 (void) fputc(0x0,file);
937 (void) fputc(';',file); /* terminator */
938
939 (void) fclose(file);
940
941 g_free(img->pixels);
942 g_free(img->colormap);
943 g_free(img);
944
945 g_array_free(imageData, TRUE);
946
947 return TRUE;
948 }
949