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