Logo Search packages:      
Sourcecode: giflib version File versions  Download package

icon2gif.c

/*****************************************************************************
*   "Gif-Lib" - Yet another gif library.                         *
*                                                          *
* Written by:  Gershon Elber                    Ver 0.1, Jun. 1989   *
******************************************************************************
* Module to convert an editable text representation into a GIF file.         *
******************************************************************************
* History:                                                 *
* 15 Sep 92 - Version 1.0 by Eric Raymond.                             *
*****************************************************************************/

#ifdef __MSDOS__
#include <dos.h>
#include <alloc.h>
#include <stdlib.h>
#include <graphics.h>
#include <io.h>
#endif /* __MSDOS__ */

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "gif_lib.h"

#define PROGRAM_NAME    "icon2gif"

#ifdef __MSDOS__
extern unsigned int
    _stklen = 16384;                     /* Increase default stack size. */
#endif /* __MSDOS__ */

#ifdef SYSV
static char *VersionStr =
        "Gif compiler,\t\tEric S. Raymond\n\
      (C) Copyright 1992 Eric S. Raymond, all rights reserved.\n";
static char
    *CtrlStr = "GifAsm q%- d%- t%-Characters!s h%- GifFile(s)!*s";
#else
static char
    *VersionStr =
      PROGRAM_NAME
      GIF_LIB_VERSION
      "     Eric Raymond,     "
      __DATE__ ",   " __TIME__ "\n"
      "(C) Copyright 1992 Eric Raymond.\n";
static char
    *CtrlStr =
      PROGRAM_NAME
      " q%- d%- t%-Characters!s h%- GifFile(s)!*s";
#endif /* SYSV */

static char KeyLetters[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#$%&'()*+,-./:<=>?@[\\]^_`{|}~";
#define PRINTABLES      (sizeof(KeyLetters) - 1)

static int HandleGifError(GifFileType *GifFile);
static void QuitGifError(GifFileType *GifFileIn, GifFileType *GifFileOut);
static int MergeImage(GifFileType *BaseFile,
                   GifFileType *Inclusion,
                  SavedImage *NewImage);
static void Icon2Gif(char *FileName, FILE *txtin, int fdout);
static void Gif2Icon(char *FileName,
                 int fdin, int fdout,
                 char NameTable[]);
static void VisibleDumpBuffer(char *buf, int Len);
static int EscapeString(char *cp, char *tp);

/******************************************************************************
* Main Sequence                                             *
******************************************************************************/
void main(int argc, char **argv)
{
    int     i, Error, NumFiles,
      DisasmFlag = FALSE, HelpFlag = FALSE, TextLineFlag = FALSE;
    char *NameTable, **FileNames = NULL, *OutFileName;
    char *TextLines[1];

    if ((Error = GAGetArgs(argc, argv, CtrlStr,
            &GifQuietPrint, &DisasmFlag, &TextLineFlag, &TextLines[0],
            &HelpFlag, &NumFiles, &FileNames)) != FALSE) {
      GAPrintErrMsg(Error);
      GAPrintHowTo(CtrlStr);
      exit(1);
    }

    if (HelpFlag) {
      fprintf(stderr, VersionStr);
      GAPrintHowTo(CtrlStr);
      exit(0);
    }

    if (!DisasmFlag && NumFiles > 1) {
      GIF_MESSAGE("Error in command line parsing - one  text input please.");
      GAPrintHowTo(CtrlStr);
      exit(1);
    }

    if (!DisasmFlag && TextLineFlag) {
      GIF_MESSAGE("Error in command line parsing - -t invalid without -d.");
      GAPrintHowTo(CtrlStr);
      exit(1);
    }


    if (NumFiles == 0)
    {
      if (DisasmFlag)
          Gif2Icon("Stdin", 0, 1, TextLineFlag ? TextLines[0] : KeyLetters);
      else
          Icon2Gif("Stdin", stdin, 1);
    }
    else
      for (i = 0; i < NumFiles; i++)
      {
          FILE    *fp;

          if ((fp = fopen(FileNames[i], "r")) == (FILE *)NULL)
          {
            (void) fprintf(stderr, "Can't open %s\n", FileNames[i]);
            exit(2);
          }

          if (DisasmFlag)
          {
            printf("#\n# GIF information from %s\n", FileNames[i]);
            Gif2Icon(FileNames[i], -1, 1, TextLineFlag ? TextLines[0] : KeyLetters);
          }
          else
          {
            Icon2Gif(FileNames[i], fp, 1);
          }

          (void) fclose(fp);
      }
}

/******************************************************************************
* Parse image directives                                          *
******************************************************************************/
#define PARSE_ERROR(str)  (void) fprintf(stderr,"%s:%d: %s\n",FileName,LineNum,str);

static void Icon2Gif(char *FileName, FILE *txtin, int fdout)
{
    int     ExtCode, ColorMapSize = 0;
    GifColorType GlobalColorMap[256], LocalColorMap[256],
      *ColorMap = GlobalColorMap;
    char GlobalColorKeys[PRINTABLES], LocalColorKeys[PRINTABLES],
      *KeyTable = GlobalColorKeys;

    char buf[BUFSIZ * 2], InclusionFile[64];
    GifFileType *GifFileOut;
    SavedImage *NewImage = NULL;
    int n, LineNum = 0;

    if ((GifFileOut = EGifOpenFileHandle(fdout)) == NULL) {
      (void) HandleGifError(GifFileOut);
    }

    /* OK, interpret directives */
    while (fgets(buf, sizeof(buf), txtin) != (char *)NULL)
    {
      char  *cp;

      ++LineNum;

      /*
       * Skip lines consisting only of whitespace and comments
       */
      for (cp = buf; isspace(*cp); cp++)
          continue;
      if (*cp == '#' || *cp == '\0')
          continue;

      /*
       * If there's a trailing comment, nuke it and all preceding whitespace.
       * But preserve the EOL.
       */
      if ((cp = strchr(buf, '#')) && (cp == strrchr(cp, '#')))
      {
          while (isspace(*--cp))
            continue;
          *++cp = '\n';
          *++cp = '\0';
      }

      /*
       * Explicit header declarations
       */

      if (sscanf(buf, "screen width %d\n", &GifFileOut->SWidth) == 1)
          continue;

      else if (sscanf(buf, "screen height %d\n", &GifFileOut->SHeight) == 1)
          continue;

      else if (sscanf(buf, "screen colors %d\n", &n) == 1)
      {
          int     ResBits = BitSize(n);

          if (n > 256 || n < 0 || n != (1 << ResBits))
          {
            PARSE_ERROR("Invalid color resolution value.");
            exit(1);
          }

          GifFileOut->SColorResolution = ResBits;
          continue;
      }

      else if (sscanf(buf,
                  "screen background %d\n",
                  &GifFileOut->SBackGroundColor) == 1)
          continue;

      /*
       * Color table parsing
       */

      else if (strcmp(buf, "screen map\n") == 0)
      {
          if (GifFileOut->SColorMap != NULL)
          {
            PARSE_ERROR("You've already declared a global color map.");
            exit(1);
          }

          ColorMapSize = 0;
          ColorMap = GlobalColorMap;
          KeyTable = GlobalColorKeys;
          memset(GlobalColorKeys, '\0', sizeof(GlobalColorKeys));
      }

      else if (strcmp(buf, "image map\n") == 0)
      {
          if (NewImage == NULL)
          {
            PARSE_ERROR("No previous image declaration.");
            exit(1);
          }

          ColorMapSize = 0;
          ColorMap = LocalColorMap;
          KeyTable = LocalColorKeys;
          memset(LocalColorKeys, '\0', sizeof(LocalColorKeys));
      }

      else if (sscanf(buf, "  rgb %d %d %d is %c",
               &ColorMap[ColorMapSize].Red,
               &ColorMap[ColorMapSize].Green,
               &ColorMap[ColorMapSize].Blue,
               &KeyTable[ColorMapSize]) == 4)
      {
          ColorMapSize++;
      }

      else if (strcmp(buf, "end\n") == 0)
      {
          ColorMapObject      *NewMap;


          NewMap = MakeMapObject(1 << BitSize(ColorMapSize), ColorMap);
          if (NewMap == (ColorMapObject *)NULL)
          {
            PARSE_ERROR("Out of memory while allocating new color map.");
            exit(1);
          }

          if (NewImage)
            NewImage->ImageDesc.ColorMap = NewMap;
          else
            GifFileOut->SColorMap = NewMap;
      }

      /* GIF inclusion */
      else if (sscanf(buf, "include %s", InclusionFile) == 1)
      {
          GifBooleanType      DoTranslation;
          GifPixelType  Translation[256];

          GifFileType   *Inclusion;
          SavedImage    *NewImage, *CopyFrom;

          if ((Inclusion = DGifOpenFileName(InclusionFile)) == NULL
            || DGifSlurp(Inclusion) == GIF_ERROR)
          {
            PARSE_ERROR("Inclusion read failed.");
            exit(1);
          }

          if (DoTranslation = (GifFileOut->SColorMap!=(ColorMapObject*)NULL))
          {
            ColorMapObject    *UnionMap;

            UnionMap = UnionColorMap(GifFileOut->SColorMap,
                               Inclusion->SColorMap, Translation);

            if (UnionMap == NULL)
            {
                PARSE_ERROR("Inclusion failed --- global map conflict.");
                exit(1);
            }

            FreeMapObject(GifFileOut->SColorMap);
            GifFileOut->SColorMap = UnionMap;
          }

          for (CopyFrom = Inclusion->SavedImages;
             CopyFrom < Inclusion->SavedImages + Inclusion->ImageCount;
             CopyFrom++)
          {
            if ((NewImage = MakeSavedImage(GifFileOut, CopyFrom)) == NULL)
            {
                PARSE_ERROR("Inclusion failed --- out of memory.");
                exit(1);
            }
            else if (DoTranslation)
                ApplyTranslation(NewImage, Translation);

            GifQprintf(
                    "%s: Image %d at (%d, %d) [%dx%d]: from %s\n",
                  PROGRAM_NAME, GifFileOut->ImageCount,
                  NewImage->ImageDesc.Left, NewImage->ImageDesc.Top,
                  NewImage->ImageDesc.Width, NewImage->ImageDesc.Height,
                  InclusionFile);
          }

          (void) DGifCloseFile(Inclusion);
      }

      /*
       * Explicit image declarations 
       */

      else if (strcmp(buf, "image\n") == 0)
      {
          if ((NewImage = MakeSavedImage(GifFileOut, NULL)) == (SavedImage *)NULL)
          {
            PARSE_ERROR("Out of memory while allocating image block.");
            exit(1);
          }

          /* use global table unless user specifies a local one */
          ColorMap = GlobalColorMap;
          KeyTable = GlobalColorKeys;
      }

      /*
       * Nothing past this point is valid unless we've seen a previous
       * image declaration.
       */
      else if (NewImage == (SavedImage *)NULL)
      {
          (void) fputs(buf, stderr);
          PARSE_ERROR("Syntax error in header block.");
          exit(1);
      }

      /*
       * Accept image attributes
       */
      else if (sscanf(buf, "image top %d\n", &NewImage->ImageDesc.Top) == 1)
          continue;

      else if (sscanf(buf, "image left %d\n", &NewImage->ImageDesc.Left)== 1)
          continue;

      else if (strcmp(buf, "image interlaced\n") == 0)
      {
          NewImage->ImageDesc.Interlace = TRUE;
          continue;
      }

      else if (sscanf(buf,
                  "image bits %d by %d\n",
                  &NewImage->ImageDesc.Width,
                  &NewImage->ImageDesc.Height) == 2)
      {
          int i, j;
          static GifPixelType *Raster, *cp;
          int c;

          if ((Raster = (GifPixelType *) malloc(sizeof(GifPixelType) * NewImage->ImageDesc.Width * NewImage->ImageDesc.Height))
            == NULL) {
            PARSE_ERROR("Failed to allocate raster block, aborted.");
            exit(1);
          }

          if (!GifQuietPrint)
            fprintf(stderr, "%s: Image %d at (%d, %d) [%dx%d]:     ",
                PROGRAM_NAME, GifFileOut->ImageCount,
                NewImage->ImageDesc.Left, NewImage->ImageDesc.Top,
                NewImage->ImageDesc.Width, NewImage->ImageDesc.Height);

          cp = Raster;
          for (i = 0; i < NewImage->ImageDesc.Height; i++) {

            char  *dp;

            for (j = 0; j < NewImage->ImageDesc.Width; j++)
                if ((c = fgetc(txtin)) == EOF) {
                  PARSE_ERROR("input file ended prematurely.");
                  exit(1);
                }
                else if (c == '\n')
                {
                  --j;
                  ++LineNum;
                }
                else if (isspace(c))
                  --j;
                else if (dp = strchr(KeyTable, c))
                  *cp++ = (dp - KeyTable);
                else {
                  PARSE_ERROR("Invalid pixel value.");
                  exit(1);
                }

            if (!GifQuietPrint)
                fprintf(stderr, "\b\b\b\b%-4d", i);
          }

          if (!GifQuietPrint)
            putc('\n', stderr);

          NewImage->RasterBits = Raster;
      }
      else if (sscanf(buf, "comment"))
      {
          MakeExtension(NewImage, COMMENT_EXT_FUNC_CODE);
          while (fgets(buf, sizeof(buf), txtin) != (char *)NULL)
            if (strcmp(buf, "end\n") == 0)
                break;
              else
            {
                int Len;

                buf[strlen(buf) - 1] = '\0';
                Len = EscapeString(buf, buf);
                if (AddExtensionBlock(NewImage, Len, buf) == GIF_ERROR) {
                  PARSE_ERROR("out of memory while adding comment block.");
                  exit(1);
                }
            }
      }
      else if (sscanf(buf, "plaintext"))
      {
          MakeExtension(NewImage, PLAINTEXT_EXT_FUNC_CODE);
          while (fgets(buf, sizeof(buf), txtin) != (char *)NULL)
            if (strcmp(buf, "end\n") == 0)
                break;
              else
            {
                int Len;

                buf[strlen(buf) - 1] = '\0';
                Len = EscapeString(buf, buf);
                if (AddExtensionBlock(NewImage, Len, buf) == GIF_ERROR) {
                  PARSE_ERROR("out of memory while adding plaintext block.");
                  exit(1);
                }
            }
      }
      else if (sscanf(buf, "extension %02x", &ExtCode))
      {
          MakeExtension(NewImage, ExtCode);
          while (fgets(buf, sizeof(buf), txtin) != (char *)NULL)
            if (strcmp(buf, "end\n") == 0)
                break;
              else
            {
                int Len;

                buf[strlen(buf) - 1] = '\0';
                Len = EscapeString(buf, buf);
                if (AddExtensionBlock(NewImage, Len, buf) == GIF_ERROR) {
                  PARSE_ERROR("out of memory while adding extension block.");
                  exit(1);
                }
            }
      }
      else
      {
          (void) fputs(buf, stderr);
          PARSE_ERROR("Syntax error in image description.");
          exit(1);
      }
    }

    if (EGifSpew(GifFileOut) == GIF_ERROR)
      HandleGifError(GifFileOut);
}

static void Gif2Icon(char *FileName,
                 int fdin, int fdout,
                 char NameTable[])
{
    int i, j, ExtCode, CodeSize, Len, ImageNum = 1;
    GifPixelType *Line, *cp;
    GifRecordType RecordType;
    GifByteType *CodeBlock, *Extension;
    GifFileType *GifFile;

    if (fdin == -1) {
      if ((GifFile = DGifOpenFileName(FileName)) == NULL) {
          PrintGifError();
          exit(1);
      }
    }
    else {
      /* Use stdin instead: */
      if ((GifFile = DGifOpenFileHandle(fdin)) == NULL) {
          PrintGifError();
          exit(1);
      }
    }

    printf("screen width %d\nscreen height %d\n",
         GifFile->SWidth, GifFile->SHeight);

    printf("screen colors %d\nscreen background %d\n\n",
         GifFile->SColorResolution,
         GifFile->SBackGroundColor);

    if (GifFile->SColorMap)
    {
      if (GifFile->SColorMap->ColorCount >= (int)strlen(NameTable))
      {
          (void) fprintf(stderr,
                     "%s: global color map has unprintable pixels\n",
                     FileName);
          exit(1);
      }

      printf("screen map\n");

      for (i = 0; i < GifFile->SColorMap->ColorCount; i++)
          printf("\trgb %03d %03d %03d is %c\n",
               GifFile->SColorMap ->Colors[i].Red,
               GifFile->SColorMap ->Colors[i].Green,
               GifFile->SColorMap ->Colors[i].Blue,
               NameTable[i]);
      printf("end\n\n");
    }

    do {
      if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
          PrintGifError();
          exit(1);
      }
      switch (RecordType) {
      case IMAGE_DESC_RECORD_TYPE:
          if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
            PrintGifError();
            exit(1);
          }
          printf("image # %d\nimage left %d\nimage top %d\n",
               ImageNum++,
               GifFile->Image.Left, GifFile->Image.Top);
          if (GifFile->Image.Interlace)
            printf("interlaced\n");

          if (GifFile->Image.ColorMap)
          {
            if (GifFile->Image.ColorMap->ColorCount >= (int)strlen(NameTable))
            {
                (void) fprintf(stderr,
                           "%s: global color map has unprintable pixels\n",
                           FileName);
                exit(1);
            }

            printf("image map\n");

            for (i = 0; i < GifFile->Image.ColorMap->ColorCount; i++)
                printf("\trgb %03d %03d %03d is %c\n",
                     GifFile->Image.ColorMap ->Colors[i].Red,
                     GifFile->Image.ColorMap ->Colors[i].Green,
                     GifFile->Image.ColorMap ->Colors[i].Blue,
                     NameTable[i]);
            printf("end\n\n");
          }

          printf("image bits %d by %d\n",
               GifFile->Image.Width, GifFile->Image.Height);

          Line = (GifPixelType *) malloc(GifFile->Image.Width *
                                 sizeof(GifPixelType));
          for (i = 0; i < GifFile->Image.Height; i++) {
            if (DGifGetLine(GifFile, Line, GifFile->Image.Width)
                == GIF_ERROR) {
                PrintGifError();
                exit(1);
            }
            for (cp = Line; cp < Line + GifFile->Image.Width; cp++)
                putchar(NameTable[*cp]);
            putchar('\n');
          }
          free((char *) Line);
          putchar('\n');

          break;
      case EXTENSION_RECORD_TYPE:
          if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) {
            PrintGifError();
            exit(1);
          }

          if (ExtCode == COMMENT_EXT_FUNC_CODE)
            printf("comment\n");
          else if (ExtCode == PLAINTEXT_EXT_FUNC_CODE)
            printf("plaintext\n");
          else if (isalpha(ExtCode))
            printf("extension %02x    # %c\n", ExtCode, ExtCode);
          else
            printf("extension %02x\n", ExtCode);

          while (Extension != NULL) {
            VisibleDumpBuffer(Extension + 1, Extension[0]);
            putchar('\n');

            if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
                PrintGifError();
                exit(1);
            }
          }
          printf("end\n\n");

          break;
      case TERMINATE_RECORD_TYPE:
          break;
      default:          /* Should be traps by DGifGetRecordType */
          break;
      }
    }
    while
      (RecordType != TERMINATE_RECORD_TYPE);

    /* Tell EMACS this is a picture... */
    printf("# The following sets edit modes for GNU EMACS\n");
    printf("# Local ");       /* ...break this up, so that EMACS doesn't */
    printf("Variables:\n");   /* get confused when visiting *this* file! */
    printf("# mode:picture\n");
    printf("# truncate-lines:t\n");
    printf("# End:\n");

    if (fdin == -1)
      (void) printf("# End of %s dump\n", FileName);

    if (DGifCloseFile(GifFile) == GIF_ERROR) {
      PrintGifError();
      exit(1);
    }
}

static int EscapeString(char *cp, char *tp)
/* process standard C-style escape sequences in a string */
{
    char *StartAddr = tp;

    while (*cp)
    {
      int   cval = 0;

      if (*cp == '\\' && strchr("0123456789xX", cp[1]))
      {
          char *dp, *hex = "00112233445566778899aAbBcCdDeEfF";
          int dcount = 0;

          if (*++cp == 'x' || *cp == 'X')
            for (++cp; (dp = strchr(hex, *cp)) && (dcount++ < 2); cp++)
                cval = (cval * 16) + (dp - hex) / 2;
          else if (*cp == '0')
            while (strchr("01234567",*cp) != (char*)NULL && (dcount++ < 3))
                cval = (cval * 8) + (*cp++ - '0');
          else
            while ((strchr("0123456789",*cp)!=(char*)NULL)&&(dcount++ < 3))
                cval = (cval * 10) + (*cp++ - '0');
      }
      else if (*cp == '\\')         /* C-style character escapes */
      {
          switch (*++cp)
          {
          case '\\': cval = '\\'; break;
          case 'n': cval = '\n'; break;
          case 't': cval = '\t'; break;
          case 'b': cval = '\b'; break;
          case 'r': cval = '\r'; break;
          default: cval = *cp;
          }
          cp++;
      }
      else if (*cp == '^')          /* expand control-character syntax */
      {
          cval = (*++cp & 0x1f);
          cp++;
      }
      else
          cval = *cp++;
      *tp++ = cval;
    }

    return(tp - StartAddr);
}

static void VisibleDumpBuffer(char *buf, int len)
/* Visibilize a given string */
{
    char    *cp;

    for (cp = buf; cp < buf + len; cp++)
    {
      if (isprint(*cp) || *cp == ' ')
          putchar(*cp);
      else if (*cp == '\n')
      {
          putchar('\\'); putchar('n');
      }
      else if (*cp == '\r')
      {
          putchar('\\'); putchar('r');
      }
      else if (*cp == '\b')
      {
          putchar('\\'); putchar('b');
      }
      else if (*cp < ' ')
      {
          putchar('\\'); putchar('^'); putchar('@' + *cp);
      }
      else
          printf("\\0x%02x", *cp);
    }
}

/******************************************************************************
* Handle last GIF error. Try to close the file and free all allocated memory. *
******************************************************************************/
static int HandleGifError(GifFileType *GifFile)
{
    int i = GifLastError();

    if (EGifCloseFile(GifFile) == GIF_ERROR) {
      GifLastError();
    }
    return i;
}

/******************************************************************************
* Close both input and output file (if open), and exit.                       *
******************************************************************************/
static void QuitGifError(GifFileType *GifFileIn, GifFileType *GifFileOut)
{
    PrintGifError();
    if (GifFileIn != NULL) DGifCloseFile(GifFileIn);
    if (GifFileOut != NULL) EGifCloseFile(GifFileOut);
    exit(1);
}

Generated by  Doxygen 1.6.0   Back to index