mimetexrb 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ require 'mkmf'
2
+
3
+ dir_config("mimetexrb")
4
+
5
+ with_cflags("-DAA") do
6
+ create_makefile("mimetexrb", "src")
7
+ end
@@ -0,0 +1,1123 @@
1
+ /* $Id: gifsave.c,v 1.2 1998/07/05 16:29:56 sverrehu Exp $ */
2
+ /**************************************************************************
3
+ *
4
+ * FILE gifsave.c
5
+ *
6
+ * DESCRIPTION Routines to create a GIF-file. See README for
7
+ * a description.
8
+ *
9
+ * The functions were originally written using Borland's
10
+ * C-compiler on an IBM PC -compatible computer, but they
11
+ * are compiled and tested on Linux and SunOS as well.
12
+ *
13
+ * WRITTEN BY Sverre H. Huseby <sverrehu@online.no>
14
+ *
15
+ **************************************************************************/
16
+
17
+ #include <stdlib.h>
18
+ #include <stdio.h>
19
+ /* #include <unistd.h> */ /* (added by j.forkosh) to get STDOUT_FILENO*/
20
+ #include <string.h> /* " */
21
+ /* --- windows-specific header info --- */
22
+ #ifndef WINDOWS /* -DWINDOWS not supplied by user */
23
+ #if defined(_WINDOWS) || defined(_WIN32) || defined(WIN32) \
24
+ || defined(DJGPP) /* try to recognize windows compilers */ \
25
+ || defined(_USRDLL) /* must be WINDOWS if compiling for DLL */
26
+ #define WINDOWS /* signal windows */
27
+ #endif
28
+ #endif
29
+ #ifdef WINDOWS /* " if filename=NULL passed to GIF_Create()*/
30
+ #include <fcntl.h> /* " OutFile=stdout used. But Windows opens*/
31
+ #include <io.h> /* " stdout in char mode, and precedes every*/
32
+ /* " 0x0A with spurious 0x0D. */
33
+ #if defined(_O_BINARY) && !defined(O_BINARY) /* only have _O_BINARY */
34
+ #define O_BINARY _O_BINARY /* make O_BINARY available, etc... */
35
+ #define setmode _setmode
36
+ #define fileno _fileno
37
+ #endif
38
+ #if defined(_O_BINARY) || defined(O_BINARY) /* setmode() now available */
39
+ #define HAVE_SETMODE /* so we'll use setmode() */
40
+ #endif
41
+ #endif
42
+
43
+ /* #include "gifsave.h" */ /* (j.forkosh) explcitly include header */
44
+ enum GIF_Code {
45
+ GIF_OK = 0,
46
+ GIF_ERRCREATE,
47
+ GIF_ERRWRITE,
48
+ GIF_OUTMEM
49
+ };
50
+
51
+ int GIF_Create(char *buffer, int width, int height,
52
+ int numcolors, int colorres);
53
+ void GIF_SetColor(int colornum, int red, int green, int blue);
54
+ void GIF_SetTransparent(int colornum); /* (added by j.forkosh) */
55
+ int GIF_CompressImage(int left, int top, int width, int height,
56
+ int (*getpixel)(int x, int y));
57
+ int GIF_Close(void);
58
+ /* --- end-of-header gifsave.h --- */
59
+
60
+
61
+ /**************************************************************************
62
+ * *
63
+ * P R I V A T E D A T A *
64
+ * *
65
+ **************************************************************************/
66
+
67
+ typedef unsigned Word; /* at least two bytes (16 bits) */
68
+ typedef unsigned char Byte; /* exactly one byte (8 bits) */
69
+
70
+ /* used by IO-routines */
71
+ static FILE *OutFile = NULL; /* file to write to */
72
+ static Byte *OutBuffer = NULL; /* (added by j.forkosh) */
73
+ static int isCloseOutFile = 0; /* " */
74
+ #if !defined(MAXGIFSZ) /* " */
75
+ #define MAXGIFSZ 131072 /* " max #bytes comprising gif image */
76
+ #endif /* " */
77
+ int gifSize = 0; /* " #bytes comprising gif */
78
+ int maxgifSize = MAXGIFSZ; /* " max #bytes written to OutBuffer */
79
+
80
+ /* used when writing to a file bitwise */
81
+ static Byte Buffer[256]; /* there must be one more than `needed' */
82
+ static int Index, /* current byte in buffer */
83
+ BitsLeft; /* bits left to fill in current byte. These
84
+ * are right-justified */
85
+
86
+ /* used by routines maintaining an LZW string table */
87
+ #define RES_CODES 2
88
+
89
+ #define HASH_FREE 0xFFFF
90
+ #define NEXT_FIRST 0xFFFF
91
+
92
+ #define MAXBITS 12
93
+ #define MAXSTR (1 << MAXBITS)
94
+
95
+ #define HASHSIZE 9973
96
+ #define HASHSTEP 2039
97
+
98
+ #define HASH(index, lastbyte) (((lastbyte << 8) ^ index) % HASHSIZE)
99
+
100
+ static Byte *StrChr = NULL;
101
+ static Word *StrNxt = NULL,
102
+ *StrHsh = NULL,
103
+ NumStrings;
104
+
105
+ /* used in the main routines */
106
+ typedef struct {
107
+ Word LocalScreenWidth,
108
+ LocalScreenHeight;
109
+ Byte GlobalColorTableSize : 3,
110
+ SortFlag : 1,
111
+ ColorResolution : 3,
112
+ GlobalColorTableFlag : 1;
113
+ Byte BackgroundColorIndex;
114
+ Byte PixelAspectRatio;
115
+ } ScreenDescriptor;
116
+
117
+ typedef struct {
118
+ Byte Separator;
119
+ Word LeftPosition,
120
+ TopPosition;
121
+ Word Width,
122
+ Height;
123
+ Byte LocalColorTableSize : 3,
124
+ Reserved : 2,
125
+ SortFlag : 1,
126
+ InterlaceFlag : 1,
127
+ LocalColorTableFlag : 1;
128
+ } ImageDescriptor;
129
+
130
+ static int BitsPrPrimColor, /* bits pr primary color */
131
+ NumColors; /* number of colors in color table */
132
+ static int TransparentColorIndex=(-1); /* (added by j.forkosh) */
133
+ static Byte *ColorTable = NULL;
134
+ static Word ScreenHeight,
135
+ ScreenWidth,
136
+ ImageHeight,
137
+ ImageWidth,
138
+ ImageLeft,
139
+ ImageTop,
140
+ RelPixX, RelPixY; /* used by InputByte() -function */
141
+ static int (*GetPixel)(int x, int y);
142
+
143
+
144
+
145
+ /**************************************************************************
146
+ * *
147
+ * P R I V A T E F U N C T I O N S *
148
+ * *
149
+ **************************************************************************/
150
+
151
+ /*========================================================================*
152
+ = Routines to do file IO =
153
+ *========================================================================*/
154
+
155
+ /*-------------------------------------------------------------------------
156
+ *
157
+ * NAME Create
158
+ *
159
+ * DESCRIPTION Creates a new file, and enables referencing using the
160
+ * global variable OutFile. This variable is only used
161
+ * by these IO-functions, making it relatively simple to
162
+ * rewrite file IO.
163
+ *
164
+ * INPUT filename
165
+ * name of file to create,
166
+ * or NULL for stdout,
167
+ * or if *filename='\000' then it's the address of
168
+ * a memory buffer to which gif will be written
169
+ *
170
+ * RETURNS GIF_OK - OK
171
+ * GIF_ERRWRITE - Error opening the file
172
+ */
173
+ static int Create(char *buffer) {
174
+ OutBuffer = NULL; /* (added by j.forkosh) */
175
+ isCloseOutFile = 0; /* " */
176
+
177
+ char *filename = NULL;
178
+ if (filename == NULL) {
179
+ // OutFile = stdout; /* " */
180
+ OutBuffer = (Byte *)buffer; /* " */
181
+ /*OutFile = fdopen(STDOUT_FILENO,"wb");*//* " doesn't work, */
182
+ #ifdef WINDOWS /* " so instead... */
183
+ #ifdef HAVE_SETMODE /* " try to use setmode()*/
184
+ if ( setmode ( fileno (stdout), O_BINARY) /* to set stdout */
185
+ == -1 ); /* handle error *//* " to binary mode */
186
+ #else /* " setmode not available */
187
+ #if 1 /* " */
188
+ freopen ("CON", "wb", stdout); /* " freopen stdout binary */
189
+ #else /* " */
190
+ stdout = fdopen (STDOUT_FILENO, "wb"); /*fdopen stdout binary*/
191
+ #endif /* " */
192
+ #endif /* " */
193
+ #endif /* " */
194
+ } else if ( *filename != '\000') {
195
+ if ((OutFile = fopen(filename, "wb")) == NULL)
196
+ return GIF_ERRCREATE;
197
+ isCloseOutFile = 1;
198
+ } else {
199
+ OutBuffer = (Byte *)filename; /* " */
200
+ }
201
+ return GIF_OK;
202
+ }
203
+
204
+
205
+
206
+ /*-------------------------------------------------------------------------
207
+ *
208
+ * NAME Write
209
+ *
210
+ * DESCRIPTION Output bytes to the current OutFile.
211
+ *
212
+ * INPUT buf pointer to buffer to write
213
+ * len number of bytes to write
214
+ *
215
+ * RETURNS GIF_OK - OK
216
+ * GIF_ERRWRITE - Error writing to the file
217
+ */
218
+ static int
219
+ Write(const void *buf, unsigned len)
220
+ {
221
+ if ( OutBuffer == NULL ) /* (added by j.forkosh) */
222
+ { if (fwrite(buf, sizeof(Byte), len, OutFile) < len)
223
+ return GIF_ERRWRITE; }
224
+ else { /* (added by j.forkosh) */
225
+ if ( gifSize+len <= maxgifSize ) /* " */
226
+ memcpy(OutBuffer+gifSize,buf,len); } /* " */
227
+ gifSize += len; /* " */
228
+ return GIF_OK;
229
+ }
230
+
231
+
232
+
233
+ /*-------------------------------------------------------------------------
234
+ *
235
+ * NAME WriteByte
236
+ *
237
+ * DESCRIPTION Output one byte to the current OutFile.
238
+ *
239
+ * INPUT b byte to write
240
+ *
241
+ * RETURNS GIF_OK - OK
242
+ * GIF_ERRWRITE - Error writing to the file
243
+ */
244
+ static int
245
+ WriteByte(Byte b)
246
+ {
247
+ if ( OutBuffer == NULL ) /* (added by j.forkosh) */
248
+ { if (putc(b, OutFile) == EOF)
249
+ return GIF_ERRWRITE; }
250
+ else /* (added by j.forkosh) */
251
+ { if ( gifSize < maxgifSize ) /* " */
252
+ OutBuffer[gifSize] = b; } /* " */
253
+ gifSize++; /* " */
254
+ return GIF_OK;
255
+ }
256
+
257
+
258
+
259
+ /*-------------------------------------------------------------------------
260
+ *
261
+ * NAME WriteWord
262
+ *
263
+ * DESCRIPTION Output one word (2 bytes with byte-swapping, like on
264
+ * the IBM PC) to the current OutFile.
265
+ *
266
+ * INPUT w word to write
267
+ *
268
+ * RETURNS GIF_OK - OK
269
+ * GIF_ERRWRITE - Error writing to the file
270
+ */
271
+ static int
272
+ WriteWord(Word w)
273
+ {
274
+ if ( OutBuffer == NULL ) /* (added by j.forkosh) */
275
+ { if (putc(w & 0xFF, OutFile) == EOF)
276
+ return GIF_ERRWRITE;
277
+ if (putc((w >> 8), OutFile) == EOF)
278
+ return GIF_ERRWRITE; }
279
+ else /* (added by j.forkosh) */
280
+ if ( gifSize+1 < maxgifSize ) /* " */
281
+ { OutBuffer[gifSize] = (Byte)(w & 0xFF); /* " */
282
+ OutBuffer[gifSize+1] = (Byte)(w >> 8); } /* " */
283
+ gifSize += 2; /* " */
284
+ return GIF_OK;
285
+ }
286
+
287
+
288
+
289
+ /*-------------------------------------------------------------------------
290
+ *
291
+ * NAME Close
292
+ *
293
+ * DESCRIPTION Close current OutFile.
294
+ */
295
+ static void
296
+ Close(void)
297
+ {
298
+ if ( isCloseOutFile ) /* (added by j.forkosh) */
299
+ fclose(OutFile);
300
+ OutBuffer = NULL; /* (added by j.forkosh) */
301
+ isCloseOutFile = 0; /* " */
302
+ }
303
+
304
+
305
+
306
+
307
+
308
+ /*========================================================================*
309
+ = =
310
+ = Routines to write a bit-file =
311
+ = =
312
+ *========================================================================*/
313
+
314
+ /*-------------------------------------------------------------------------
315
+ *
316
+ * NAME InitBitFile
317
+ *
318
+ * DESCRIPTION Initiate for using a bitfile. All output is sent to
319
+ * the current OutFile using the I/O-routines above.
320
+ */
321
+ static void
322
+ InitBitFile(void)
323
+ {
324
+ Buffer[Index = 0] = 0;
325
+ BitsLeft = 8;
326
+ }
327
+
328
+
329
+
330
+ /*-------------------------------------------------------------------------
331
+ *
332
+ * NAME ResetOutBitFile
333
+ *
334
+ * DESCRIPTION Tidy up after using a bitfile
335
+ *
336
+ * RETURNS 0 - OK, -1 - error
337
+ */
338
+ static int
339
+ ResetOutBitFile(void)
340
+ {
341
+ Byte numbytes;
342
+
343
+ /* how much is in the buffer? */
344
+ numbytes = Index + (BitsLeft == 8 ? 0 : 1);
345
+
346
+ /* write whatever is in the buffer to the file */
347
+ if (numbytes) {
348
+ if (WriteByte(numbytes) != GIF_OK)
349
+ return -1;
350
+
351
+ if (Write(Buffer, numbytes) != GIF_OK)
352
+ return -1;
353
+
354
+ Buffer[Index = 0] = 0;
355
+ BitsLeft = 8;
356
+ }
357
+ return 0;
358
+ }
359
+
360
+
361
+
362
+ /*-------------------------------------------------------------------------
363
+ *
364
+ * NAME WriteBits
365
+ *
366
+ * DESCRIPTION Put the given number of bits to the outfile.
367
+ *
368
+ * INPUT bits bits to write from (right justified)
369
+ * numbits number of bits to write
370
+ *
371
+ * RETURNS bits written, or -1 on error.
372
+ *
373
+ */
374
+ static int
375
+ WriteBits(int bits, int numbits)
376
+ {
377
+ int bitswritten = 0;
378
+ Byte numbytes = 255;
379
+
380
+ do {
381
+ /* if the buffer is full, write it */
382
+ if ((Index == 254 && !BitsLeft) || Index > 254) {
383
+ if (WriteByte(numbytes) != GIF_OK)
384
+ return -1;
385
+
386
+ if (Write(Buffer, numbytes) != GIF_OK)
387
+ return -1;
388
+
389
+ Buffer[Index = 0] = 0;
390
+ BitsLeft = 8;
391
+ }
392
+
393
+ /* now take care of the two specialcases */
394
+ if (numbits <= BitsLeft) {
395
+ Buffer[Index] |= (bits & ((1 << numbits) - 1)) << (8 - BitsLeft);
396
+ bitswritten += numbits;
397
+ BitsLeft -= numbits;
398
+ numbits = 0;
399
+ } else {
400
+ Buffer[Index] |= (bits & ((1 << BitsLeft) - 1)) << (8 - BitsLeft);
401
+ bitswritten += BitsLeft;
402
+ bits >>= BitsLeft;
403
+ numbits -= BitsLeft;
404
+
405
+ Buffer[++Index] = 0;
406
+ BitsLeft = 8;
407
+ }
408
+ } while (numbits);
409
+
410
+ return bitswritten;
411
+ }
412
+
413
+
414
+
415
+ /*========================================================================*
416
+ = Routines to maintain an LZW-string table =
417
+ *========================================================================*/
418
+
419
+ /*-------------------------------------------------------------------------
420
+ *
421
+ * NAME FreeStrtab
422
+ *
423
+ * DESCRIPTION Free arrays used in string table routines
424
+ */
425
+ static void
426
+ FreeStrtab(void)
427
+ {
428
+ if (StrHsh) {
429
+ free(StrHsh);
430
+ StrHsh = NULL;
431
+ }
432
+ if (StrNxt) {
433
+ free(StrNxt);
434
+ StrNxt = NULL;
435
+ }
436
+ if (StrChr) {
437
+ free(StrChr);
438
+ StrChr = NULL;
439
+ }
440
+ }
441
+
442
+
443
+
444
+ /*-------------------------------------------------------------------------
445
+ *
446
+ * NAME AllocStrtab
447
+ *
448
+ * DESCRIPTION Allocate arrays used in string table routines
449
+ *
450
+ * RETURNS GIF_OK - OK
451
+ * GIF_OUTMEM - Out of memory
452
+ */
453
+ static int
454
+ AllocStrtab(void)
455
+ {
456
+ /* just in case */
457
+ FreeStrtab();
458
+
459
+ if ((StrChr = (Byte *) malloc(MAXSTR * sizeof(Byte))) == 0) {
460
+ FreeStrtab();
461
+ return GIF_OUTMEM;
462
+ }
463
+ if ((StrNxt = (Word *) malloc(MAXSTR * sizeof(Word))) == 0) {
464
+ FreeStrtab();
465
+ return GIF_OUTMEM;
466
+ }
467
+ if ((StrHsh = (Word *) malloc(HASHSIZE * sizeof(Word))) == 0) {
468
+ FreeStrtab();
469
+ return GIF_OUTMEM;
470
+ }
471
+ return GIF_OK;
472
+ }
473
+
474
+
475
+
476
+ /*-------------------------------------------------------------------------
477
+ *
478
+ * NAME AddCharString
479
+ *
480
+ * DESCRIPTION Add a string consisting of the string of index plus
481
+ * the byte b.
482
+ *
483
+ * If a string of length 1 is wanted, the index should
484
+ * be 0xFFFF.
485
+ *
486
+ * INPUT index index to first part of string, or 0xFFFF is
487
+ * only 1 byte is wanted
488
+ * b last byte in new string
489
+ *
490
+ * RETURNS Index to new string, or 0xFFFF if no more room
491
+ */
492
+ static Word
493
+ AddCharString(Word index, Byte b)
494
+ {
495
+ Word hshidx;
496
+
497
+ /* check if there is more room */
498
+ if (NumStrings >= MAXSTR)
499
+ return 0xFFFF;
500
+
501
+ /* search the string table until a free position is found */
502
+ hshidx = HASH(index, b);
503
+ while (StrHsh[hshidx] != 0xFFFF)
504
+ hshidx = (hshidx + HASHSTEP) % HASHSIZE;
505
+
506
+ /* insert new string */
507
+ StrHsh[hshidx] = NumStrings;
508
+ StrChr[NumStrings] = b;
509
+ StrNxt[NumStrings] = (index != 0xFFFF) ? index : NEXT_FIRST;
510
+
511
+ return NumStrings++;
512
+ }
513
+
514
+
515
+
516
+ /*-------------------------------------------------------------------------
517
+ *
518
+ * NAME FindCharString
519
+ *
520
+ * DESCRIPTION Find index of string consisting of the string of index
521
+ * plus the byte b.
522
+ *
523
+ * If a string of length 1 is wanted, the index should
524
+ * be 0xFFFF.
525
+ *
526
+ * INPUT index index to first part of string, or 0xFFFF is
527
+ * only 1 byte is wanted
528
+ * b last byte in string
529
+ *
530
+ * RETURNS Index to string, or 0xFFFF if not found
531
+ */
532
+ static Word
533
+ FindCharString(Word index, Byte b)
534
+ {
535
+ Word hshidx, nxtidx;
536
+
537
+ /* check if index is 0xFFFF. in that case we need only return b,
538
+ * since all one-character strings has their bytevalue as their
539
+ * index */
540
+ if (index == 0xFFFF)
541
+ return b;
542
+
543
+ /* search the string table until the string is found, or we find
544
+ * HASH_FREE. in that case the string does not exist. */
545
+ hshidx = HASH(index, b);
546
+ while ((nxtidx = StrHsh[hshidx]) != 0xFFFF) {
547
+ if (StrNxt[nxtidx] == index && StrChr[nxtidx] == b)
548
+ return nxtidx;
549
+ hshidx = (hshidx + HASHSTEP) % HASHSIZE;
550
+ }
551
+
552
+ /* no match is found */
553
+ return 0xFFFF;
554
+ }
555
+
556
+
557
+
558
+ /*-------------------------------------------------------------------------
559
+ *
560
+ * NAME ClearStrtab
561
+ *
562
+ * DESCRIPTION Mark the entire table as free, enter the 2**codesize
563
+ * one-byte strings, and reserve the RES_CODES reserved
564
+ * codes.
565
+ *
566
+ * INPUT codesize
567
+ * number of bits to encode one pixel
568
+ */
569
+ static void
570
+ ClearStrtab(int codesize)
571
+ {
572
+ int q, w;
573
+ Word *wp;
574
+
575
+ /* no strings currently in the table */
576
+ NumStrings = 0;
577
+
578
+ /* mark entire hashtable as free */
579
+ wp = StrHsh;
580
+ for (q = 0; q < HASHSIZE; q++)
581
+ *wp++ = HASH_FREE;
582
+
583
+ /* insert 2**codesize one-character strings, and reserved codes */
584
+ w = (1 << codesize) + RES_CODES;
585
+ for (q = 0; q < w; q++)
586
+ AddCharString(0xFFFF, q);
587
+ }
588
+
589
+
590
+
591
+ /*========================================================================*
592
+ = LZW compression routine =
593
+ *========================================================================*/
594
+
595
+ /*-------------------------------------------------------------------------
596
+ *
597
+ * NAME LZW_Compress
598
+ *
599
+ * DESCRIPTION Perform LZW compression as specified in the
600
+ * GIF-standard.
601
+ *
602
+ * INPUT codesize
603
+ * number of bits needed to represent
604
+ * one pixelvalue.
605
+ * inputbyte
606
+ * function that fetches each byte to compress.
607
+ * must return -1 when no more bytes.
608
+ *
609
+ * RETURNS GIF_OK - OK
610
+ * GIF_OUTMEM - Out of memory
611
+ */
612
+ static int
613
+ LZW_Compress(int codesize, int (*inputbyte)(void))
614
+ {
615
+ register int c;
616
+ register Word index;
617
+ int clearcode, endofinfo, numbits, limit, errcode;
618
+ Word prefix = 0xFFFF;
619
+
620
+ /* set up the given outfile */
621
+ InitBitFile();
622
+
623
+ /* set up variables and tables */
624
+ clearcode = 1 << codesize;
625
+ endofinfo = clearcode + 1;
626
+
627
+ numbits = codesize + 1;
628
+ limit = (1 << numbits) - 1;
629
+
630
+ if ((errcode = AllocStrtab()) != GIF_OK)
631
+ return errcode;
632
+ ClearStrtab(codesize);
633
+
634
+ /* first send a code telling the unpacker to clear the stringtable */
635
+ WriteBits(clearcode, numbits);
636
+
637
+ /* pack image */
638
+ while ((c = inputbyte()) != -1) {
639
+ /* now perform the packing. check if the prefix + the new
640
+ * character is a string that exists in the table */
641
+ if ((index = FindCharString(prefix, c)) != 0xFFFF) {
642
+ /* the string exists in the table. make this string the
643
+ * new prefix. */
644
+ prefix = index;
645
+ } else {
646
+ /* the string does not exist in the table. first write
647
+ * code of the old prefix to the file. */
648
+ WriteBits(prefix, numbits);
649
+
650
+ /* add the new string (the prefix + the new character) to
651
+ * the stringtable */
652
+ if (AddCharString(prefix, c) > limit) {
653
+ if (++numbits > 12) {
654
+ WriteBits(clearcode, numbits - 1);
655
+ ClearStrtab(codesize);
656
+ numbits = codesize + 1;
657
+ }
658
+ limit = (1 << numbits) - 1;
659
+ }
660
+
661
+ /* set prefix to a string containing only the character
662
+ * read. since all possible one-character strings exists
663
+ * int the table, there's no need to check if it is found. */
664
+ prefix = c;
665
+ }
666
+ }
667
+
668
+ /* end of info is reached. write last prefix. */
669
+ if (prefix != 0xFFFF)
670
+ WriteBits(prefix, numbits);
671
+
672
+ /* erite end of info -mark, flush the buffer, and tidy up */
673
+ WriteBits(endofinfo, numbits);
674
+ ResetOutBitFile();
675
+ FreeStrtab();
676
+
677
+ return GIF_OK;
678
+ }
679
+
680
+
681
+
682
+ /*========================================================================*
683
+ = Other routines =
684
+ *========================================================================*/
685
+
686
+ /*-------------------------------------------------------------------------
687
+ *
688
+ * NAME BitsNeeded
689
+ *
690
+ * DESCRIPTION Calculates number of bits needed to store numbers
691
+ * between 0 and n - 1
692
+ *
693
+ * INPUT n number of numbers to store (0 to n - 1)
694
+ *
695
+ * RETURNS Number of bits needed
696
+ */
697
+ static int
698
+ BitsNeeded(Word n)
699
+ {
700
+ int ret = 1;
701
+
702
+ if (!n--)
703
+ return 0;
704
+ while (n >>= 1)
705
+ ++ret;
706
+ return ret;
707
+ }
708
+
709
+
710
+
711
+ /*-------------------------------------------------------------------------
712
+ *
713
+ * NAME InputByte
714
+ *
715
+ * DESCRIPTION Get next pixel from image. Called by the
716
+ * LZW_Compress()-function
717
+ *
718
+ * RETURNS Next pixelvalue, or -1 if no more pixels
719
+ */
720
+ static int
721
+ InputByte(void)
722
+ {
723
+ int ret;
724
+
725
+ if (RelPixY >= ImageHeight)
726
+ return -1;
727
+ ret = GetPixel(ImageLeft + RelPixX, ImageTop + RelPixY);
728
+ if (++RelPixX >= ImageWidth) {
729
+ RelPixX = 0;
730
+ ++RelPixY;
731
+ }
732
+ return ret;
733
+ }
734
+
735
+
736
+
737
+ /*-------------------------------------------------------------------------
738
+ *
739
+ * NAME WriteScreenDescriptor
740
+ *
741
+ * DESCRIPTION Output a screen descriptor to the current GIF-file
742
+ *
743
+ * INPUT sd pointer to screen descriptor to output
744
+ *
745
+ * RETURNS GIF_OK - OK
746
+ * GIF_ERRWRITE - Error writing to the file
747
+ */
748
+ static int
749
+ WriteScreenDescriptor(ScreenDescriptor *sd)
750
+ {
751
+ Byte tmp;
752
+
753
+ if (WriteWord(sd->LocalScreenWidth) != GIF_OK)
754
+ return GIF_ERRWRITE;
755
+ if (WriteWord(sd->LocalScreenHeight) != GIF_OK)
756
+ return GIF_ERRWRITE;
757
+ tmp = (sd->GlobalColorTableFlag << 7)
758
+ | (sd->ColorResolution << 4)
759
+ | (sd->SortFlag << 3)
760
+ | sd->GlobalColorTableSize;
761
+ if (WriteByte(tmp) != GIF_OK)
762
+ return GIF_ERRWRITE;
763
+ if (WriteByte(sd->BackgroundColorIndex) != GIF_OK)
764
+ return GIF_ERRWRITE;
765
+ if (WriteByte(sd->PixelAspectRatio) != GIF_OK)
766
+ return GIF_ERRWRITE;
767
+
768
+ return GIF_OK;
769
+ }
770
+
771
+
772
+
773
+ /*-------------------------------------------------------------------------
774
+ *
775
+ * NAME WriteTransparentColorIndex (added by j.forkosh)
776
+ *
777
+ * DESCRIPTION Output a graphic extension block setting transparent
778
+ * colormap index
779
+ *
780
+ * INPUT colornum colormap index of color to be transparent
781
+ *
782
+ * RETURNS GIF_OK - OK
783
+ * GIF_ERRWRITE - Error writing to the file
784
+ */
785
+ static int
786
+ WriteTransparentColorIndex(int colornum)
787
+ {
788
+ if ( colornum < 0 ) return GIF_OK; /*no transparent color set*/
789
+ if (WriteByte((Byte)(0x21)) != GIF_OK) /*magic:Extension Introducer*/
790
+ return GIF_ERRWRITE;
791
+ if (WriteByte((Byte)(0xf9)) != GIF_OK) /*magic:Graphic Control Label*/
792
+ return GIF_ERRWRITE;
793
+ if (WriteByte((Byte)(4)) != GIF_OK) /* #bytes in block */
794
+ return GIF_ERRWRITE;
795
+ if (WriteByte((Byte)(1)) != GIF_OK) /*transparent index indicator*/
796
+ return GIF_ERRWRITE;
797
+ if (WriteWord((Word)(0)) != GIF_OK) /* delay time */
798
+ return GIF_ERRWRITE;
799
+ if (WriteByte((Byte)(colornum)) != GIF_OK) /* transparent color index */
800
+ return GIF_ERRWRITE;
801
+ if (WriteByte((Byte)(0)) != GIF_OK) /* terminator */
802
+ return GIF_ERRWRITE;
803
+
804
+ return GIF_OK;
805
+ }
806
+
807
+
808
+
809
+ /*-------------------------------------------------------------------------
810
+ *
811
+ * NAME WriteImageDescriptor
812
+ *
813
+ * DESCRIPTION Output an image descriptor to the current GIF-file
814
+ *
815
+ * INPUT id pointer to image descriptor to output
816
+ *
817
+ * RETURNS GIF_OK - OK
818
+ * GIF_ERRWRITE - Error writing to the file
819
+ */
820
+ static int
821
+ WriteImageDescriptor(ImageDescriptor *id)
822
+ {
823
+ Byte tmp;
824
+
825
+ if (WriteByte(id->Separator) != GIF_OK)
826
+ return GIF_ERRWRITE;
827
+ if (WriteWord(id->LeftPosition) != GIF_OK)
828
+ return GIF_ERRWRITE;
829
+ if (WriteWord(id->TopPosition) != GIF_OK)
830
+ return GIF_ERRWRITE;
831
+ if (WriteWord(id->Width) != GIF_OK)
832
+ return GIF_ERRWRITE;
833
+ if (WriteWord(id->Height) != GIF_OK)
834
+ return GIF_ERRWRITE;
835
+ tmp = (id->LocalColorTableFlag << 7)
836
+ | (id->InterlaceFlag << 6)
837
+ | (id->SortFlag << 5)
838
+ | (id->Reserved << 3)
839
+ | id->LocalColorTableSize;
840
+ if (WriteByte(tmp) != GIF_OK)
841
+ return GIF_ERRWRITE;
842
+
843
+ return GIF_OK;
844
+ }
845
+
846
+
847
+
848
+ /**************************************************************************
849
+ * *
850
+ * P U B L I C F U N C T I O N S *
851
+ * *
852
+ **************************************************************************/
853
+
854
+ /*-------------------------------------------------------------------------
855
+ *
856
+ * NAME GIF_Create
857
+ *
858
+ * DESCRIPTION Create a GIF-file, and write headers for both screen
859
+ * and image.
860
+ *
861
+ * INPUT filename
862
+ * name of file to create (including extension)
863
+ * width number of horisontal pixels on screen
864
+ * height number of vertical pixels on screen
865
+ * numcolors
866
+ * number of colors in the colormaps
867
+ * colorres
868
+ * color resolution. Number of bits for each
869
+ * primary color
870
+ *
871
+ * RETURNS GIF_OK - OK
872
+ * GIF_ERRCREATE - Couldn't create file
873
+ * GIF_ERRWRITE - Error writing to the file
874
+ * GIF_OUTMEM - Out of memory allocating color table
875
+ */
876
+ int
877
+ GIF_Create(char *buffer, int width, int height,
878
+ int numcolors, int colorres)
879
+ {
880
+ int q, tabsize;
881
+ Byte *bp;
882
+ ScreenDescriptor SD;
883
+
884
+ /* initiate variables for new GIF-file */
885
+ NumColors = numcolors ? (1 << BitsNeeded(numcolors)) : 0;
886
+ BitsPrPrimColor = colorres;
887
+ ScreenHeight = height;
888
+ ScreenWidth = width;
889
+
890
+ /* create file specified */
891
+ if (Create(buffer) != GIF_OK)
892
+ return GIF_ERRCREATE;
893
+
894
+ /* write GIF signature */
895
+ if ((Write("GIF87a", 6)) != GIF_OK)
896
+ return GIF_ERRWRITE;
897
+
898
+ /* initiate and write screen descriptor */
899
+ SD.LocalScreenWidth = width;
900
+ SD.LocalScreenHeight = height;
901
+ if (NumColors) {
902
+ SD.GlobalColorTableSize = BitsNeeded(NumColors) - 1;
903
+ SD.GlobalColorTableFlag = 1;
904
+ } else {
905
+ SD.GlobalColorTableSize = 0;
906
+ SD.GlobalColorTableFlag = 0;
907
+ }
908
+ SD.SortFlag = 0;
909
+ SD.ColorResolution = colorres - 1;
910
+ SD.BackgroundColorIndex = 0;
911
+ SD.PixelAspectRatio = 0;
912
+ if (WriteScreenDescriptor(&SD) != GIF_OK)
913
+ return GIF_ERRWRITE;
914
+
915
+ /* allocate color table */
916
+ if (ColorTable) {
917
+ free(ColorTable);
918
+ ColorTable = NULL;
919
+ }
920
+ if (NumColors) {
921
+ tabsize = NumColors * 3;
922
+ if ((ColorTable = (Byte *) malloc(tabsize * sizeof(Byte))) == NULL)
923
+ return GIF_OUTMEM;
924
+ else {
925
+ bp = ColorTable;
926
+ for (q = 0; q < tabsize; q++)
927
+ *bp++ = 0;
928
+ }
929
+ }
930
+ return 0;
931
+ }
932
+
933
+
934
+
935
+ /*-------------------------------------------------------------------------
936
+ *
937
+ * NAME GIF_SetColor
938
+ *
939
+ * DESCRIPTION Set red, green and blue components of one of the
940
+ * colors. The color components are all in the range
941
+ * [0, (1 << BitsPrPrimColor) - 1]
942
+ *
943
+ * INPUT colornum
944
+ * color number to set. [0, NumColors - 1]
945
+ * red red component of color
946
+ * green green component of color
947
+ * blue blue component of color
948
+ */
949
+ void
950
+ GIF_SetColor(int colornum, int red, int green, int blue)
951
+ {
952
+ long maxcolor;
953
+ Byte *p;
954
+
955
+ maxcolor = (1L << BitsPrPrimColor) - 1L;
956
+ p = ColorTable + colornum * 3;
957
+ *p++ = (Byte) ((red * 255L) / maxcolor);
958
+ *p++ = (Byte) ((green * 255L) / maxcolor);
959
+ *p++ = (Byte) ((blue * 255L) / maxcolor);
960
+ }
961
+
962
+
963
+
964
+ /*-------------------------------------------------------------------------
965
+ *
966
+ * NAME GIF_SetTransparent (added by j.forkosh)
967
+ *
968
+ * DESCRIPTION Set colormap index of color to be transparent
969
+ *
970
+ * INPUT colornum
971
+ * color number to set transparent. [0, NumColors - 1]
972
+ */
973
+ void
974
+ GIF_SetTransparent(int colornum)
975
+ {
976
+ TransparentColorIndex = colornum;
977
+ }
978
+
979
+
980
+
981
+ /*-------------------------------------------------------------------------
982
+ *
983
+ * NAME GIF_CompressImage
984
+ *
985
+ * DESCRIPTION Compress an image into the GIF-file previousely
986
+ * created using GIF_Create(). All color values should
987
+ * have been specified before this function is called.
988
+ *
989
+ * The pixels are retrieved using a user defined callback
990
+ * function. This function should accept two parameters,
991
+ * x and y, specifying which pixel to retrieve. The pixel
992
+ * values sent to this function are as follows:
993
+ *
994
+ * x : [ImageLeft, ImageLeft + ImageWidth - 1]
995
+ * y : [ImageTop, ImageTop + ImageHeight - 1]
996
+ *
997
+ * The function should return the pixel value for the
998
+ * point given, in the interval [0, NumColors - 1]
999
+ *
1000
+ * INPUT left screen-relative leftmost pixel x-coordinate
1001
+ * of the image
1002
+ * top screen-relative uppermost pixel y-coordinate
1003
+ * of the image
1004
+ * width width of the image, or -1 if as wide as
1005
+ * the screen
1006
+ * height height of the image, or -1 if as high as
1007
+ * the screen
1008
+ * getpixel
1009
+ * address of user defined callback function.
1010
+ * (see above)
1011
+ *
1012
+ * RETURNS GIF_OK - OK
1013
+ * GIF_OUTMEM - Out of memory
1014
+ * GIF_ERRWRITE - Error writing to the file
1015
+ */
1016
+ int
1017
+ GIF_CompressImage(int left, int top, int width, int height,
1018
+ int (*getpixel)(int x, int y))
1019
+ {
1020
+ int codesize, errcode;
1021
+ ImageDescriptor ID;
1022
+
1023
+ if (width < 0) {
1024
+ width = ScreenWidth;
1025
+ left = 0;
1026
+ }
1027
+ if (height < 0) {
1028
+ height = ScreenHeight;
1029
+ top = 0;
1030
+ }
1031
+ if (left < 0)
1032
+ left = 0;
1033
+ if (top < 0)
1034
+ top = 0;
1035
+
1036
+ /* write global colortable if any */
1037
+ if (NumColors)
1038
+ if ((Write(ColorTable, NumColors * 3)) != GIF_OK)
1039
+ return GIF_ERRWRITE;
1040
+
1041
+ /* write graphic extension block with transparent color index */
1042
+ if ( TransparentColorIndex >= 0 ) /* (added by j.forkosh) */
1043
+ if ( WriteTransparentColorIndex(TransparentColorIndex)
1044
+ != GIF_OK ) return GIF_ERRWRITE;
1045
+
1046
+ /* initiate and write image descriptor */
1047
+ ID.Separator = ',';
1048
+ ID.LeftPosition = ImageLeft = left;
1049
+ ID.TopPosition = ImageTop = top;
1050
+ ID.Width = ImageWidth = width;
1051
+ ID.Height = ImageHeight = height;
1052
+ ID.LocalColorTableSize = 0;
1053
+ ID.Reserved = 0;
1054
+ ID.SortFlag = 0;
1055
+ ID.InterlaceFlag = 0;
1056
+ ID.LocalColorTableFlag = 0;
1057
+
1058
+ if (WriteImageDescriptor(&ID) != GIF_OK)
1059
+ return GIF_ERRWRITE;
1060
+
1061
+ /* write code size */
1062
+ codesize = BitsNeeded(NumColors);
1063
+ if (codesize == 1)
1064
+ ++codesize;
1065
+ if (WriteByte(codesize) != GIF_OK)
1066
+ return GIF_ERRWRITE;
1067
+
1068
+ /* perform compression */
1069
+ RelPixX = RelPixY = 0;
1070
+ GetPixel = getpixel;
1071
+ if ((errcode = LZW_Compress(codesize, InputByte)) != GIF_OK)
1072
+ return errcode;
1073
+
1074
+ /* write terminating 0-byte */
1075
+ if (WriteByte(0) != GIF_OK)
1076
+ return GIF_ERRWRITE;
1077
+
1078
+ return GIF_OK;
1079
+ }
1080
+
1081
+
1082
+
1083
+ /*-------------------------------------------------------------------------
1084
+ *
1085
+ * NAME GIF_Close
1086
+ *
1087
+ * DESCRIPTION Close the GIF-file
1088
+ *
1089
+ * RETURNS GIF_OK - OK
1090
+ * GIF_ERRWRITE - Error writing to file
1091
+ */
1092
+ int
1093
+ GIF_Close(void)
1094
+ {
1095
+ ImageDescriptor ID;
1096
+
1097
+ /* initiate and write ending image descriptor */
1098
+ ID.Separator = ';';
1099
+ ID.LeftPosition = 0; /* (added by j.forkosh) */
1100
+ ID.TopPosition = 0; /* " initialize entire ID structure */
1101
+ ID.Width = 0; /* " and ditto for other ID.x=0; below */
1102
+ ID.Height = 0;
1103
+ ID.LocalColorTableSize = 0;
1104
+ ID.Reserved = 0;
1105
+ ID.SortFlag = 0;
1106
+ ID.InterlaceFlag = 0;
1107
+ ID.LocalColorTableFlag = 0;
1108
+
1109
+ if (WriteImageDescriptor(&ID) != GIF_OK)
1110
+ return GIF_ERRWRITE;
1111
+
1112
+ /* close file */
1113
+ Close();
1114
+
1115
+ /* release color table */
1116
+ if (ColorTable) {
1117
+ free(ColorTable);
1118
+ ColorTable = NULL;
1119
+ }
1120
+
1121
+ return gifSize;
1122
+ }
1123
+ /* --- end-of-file gifsave.c --- */