home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / netpbma.zip / pnm / giftopnm.c < prev    next >
C/C++ Source or Header  |  1993-12-14  |  19KB  |  593 lines

  1. /* +-------------------------------------------------------------------+ */
  2. /* | Copyright 1990, 1991, 1993, David Koblas.  (koblas@netcom.com)    | */
  3. /* |   Permission to use, copy, modify, and distribute this software   | */
  4. /* |   and its documentation for any purpose and without fee is hereby | */
  5. /* |   granted, provided that the above copyright notice appear in all | */
  6. /* |   copies and that both that copyright notice and this permission  | */
  7. /* |   notice appear in supporting documentation.  This software is    | */
  8. /* |   provided "as is" without express or implied warranty.           | */
  9. /* +-------------------------------------------------------------------+ */
  10.  
  11.  
  12. #include       "pnm.h"
  13.  
  14. #define        MAXCOLORMAPSIZE         256
  15.  
  16. #define        TRUE    1
  17. #define        FALSE   0
  18.  
  19. #define CM_RED         0
  20. #define CM_GREEN       1
  21. #define CM_BLUE                2
  22.  
  23. #define        MAX_LWZ_BITS            12
  24.  
  25. #define INTERLACE              0x40
  26. #define LOCALCOLORMAP  0x80
  27. #define BitSet(byte, bit)      (((byte) & (bit)) == (bit))
  28.  
  29. #define        ReadOK(file,buffer,len) (fread(buffer, len, 1, file) != 0)
  30.  
  31. #define LM_to_uint(a,b)                        (((b)<<8)|(a))
  32.  
  33. static struct {
  34.        unsigned int    Width;
  35.        unsigned int    Height;
  36.        unsigned char   ColorMap[3][MAXCOLORMAPSIZE];
  37.        unsigned int    BitPixel;
  38.        unsigned int    ColorResolution;
  39.        unsigned int    Background;
  40.        unsigned int    AspectRatio;
  41.        /*
  42.        **
  43.        */
  44.        int             GrayScale;
  45. } GifScreen;
  46.  
  47. static struct {
  48.        int     transparent;
  49.        int     delayTime;
  50.        int     inputFlag;
  51.        int     disposal;
  52. } Gif89 = { -1, -1, -1, 0 };
  53.  
  54. pixel  *Image = NULL;
  55. int    verbose;
  56. int    showComment;
  57.  
  58. static char    usage[] = "[-verbose] [-comments] [-image N] [GIFfile]";
  59.  
  60. static void ReadGIF ARGS(( FILE        *fd, int imageNumber ));
  61. static int ReadColorMap ARGS(( FILE *fd, int number, unsigned char buffer[3][MAXCOLORMAPSIZE], int *flag ));
  62. static int DoExtension ARGS(( FILE *fd, int label ));
  63. static int GetDataBlock ARGS(( FILE *fd, unsigned char  *buf ));
  64. static int GetCode ARGS(( FILE *fd, int code_size, int flag ));
  65. static int LWZReadByte ARGS(( FILE *fd, int flag, int input_code_size ));
  66. static void ReadImage ARGS(( FILE *fd, int len, int height, unsigned char cmap[3][MAXCOLORMAPSIZE], int gray, int interlace, int ignore ));
  67.  
  68. int
  69. main(argc,argv)
  70. int    argc;
  71. char   **argv;
  72. {
  73.        int             argn;
  74.        FILE            *in;
  75.        int             imageNumber;
  76.  
  77.        pnm_init(&argc, argv);
  78.  
  79.        argn = 1;
  80.        imageNumber = 1;
  81.        verbose = FALSE;
  82.        showComment = FALSE;
  83.  
  84.        while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') {
  85.                if (pm_keymatch(argv[argn], "-verbose", 2)) {
  86.                        verbose = TRUE;
  87.                        showComment = TRUE;
  88.                } else if (pm_keymatch(argv[argn], "-comments", 2)) {
  89.                        showComment = TRUE;
  90.                } else if (pm_keymatch(argv[argn], "-image", 2)) {
  91.                        ++argn;
  92.                        if (argn == argc || sscanf(argv[argn], "%d", &imageNumber) != 1)
  93.                                pm_usage(usage);
  94.                } else {
  95.                        pm_usage(usage);
  96.                }
  97.                ++argn;
  98.        }
  99.        if (argn != argc) {
  100.                in = pm_openr(argv[argn]);
  101.                ++argn;
  102.        } else {
  103.                in = stdin;
  104.        }
  105.  
  106.        if (argn != argc)
  107.                pm_usage(usage);
  108.  
  109.        ReadGIF(in, imageNumber);
  110.        pm_close(in);
  111.        pm_close(stdout);
  112.        exit(0);
  113. }
  114.  
  115. static void
  116. ReadGIF(fd, imageNumber)
  117. FILE   *fd;
  118. int    imageNumber;
  119. {
  120.        unsigned char   buf[16];
  121.        unsigned char   c;
  122.        unsigned char   localColorMap[3][MAXCOLORMAPSIZE];
  123.        int             grayScale;
  124.        int             useGlobalColormap;
  125.        int             bitPixel;
  126.        int             imageCount = 0;
  127.        char            version[4];
  128.  
  129.        if (! ReadOK(fd,buf,6))
  130.                pm_error("error reading magic number" );
  131.  
  132.        if (strncmp((char *)buf,"GIF",3) != 0)
  133.                pm_error("not a GIF file" );
  134.  
  135.        strncpy(version, (char *)buf + 3, 3);
  136.        version[3] = '\0';
  137.  
  138.        if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0))
  139.                pm_error("bad version number, not '87a' or '89a'" );
  140.  
  141.        if (! ReadOK(fd,buf,7))
  142.                pm_error("failed to read screen descriptor" );
  143.  
  144.        GifScreen.Width           = LM_to_uint(buf[0],buf[1]);
  145.        GifScreen.Height          = LM_to_uint(buf[2],buf[3]);
  146.        GifScreen.BitPixel        = 2<<(buf[4]&0x07);
  147.        GifScreen.ColorResolution = (((buf[4]&0x70)>>3)+1);
  148.        GifScreen.Background      = buf[5];
  149.        GifScreen.AspectRatio     = buf[6];
  150.  
  151.        if (BitSet(buf[4], LOCALCOLORMAP)) {    /* Global Colormap */
  152.                if (ReadColorMap(fd,GifScreen.BitPixel,GifScreen.ColorMap,
  153.                                        &GifScreen.GrayScale))
  154.                        pm_error("error reading global colormap" );
  155.        }
  156.  
  157.        if (GifScreen.AspectRatio != 0 && GifScreen.AspectRatio != 49) {
  158.                float   r;
  159.                r = ( (float) GifScreen.AspectRatio + 15.0 ) / 64.0;
  160.                pm_message("warning - non-square pixels; to fix do a 'pnmscale -%cscale %g'",
  161.                    r < 1.0 ? 'x' : 'y',
  162.                    r < 1.0 ? 1.0 / r : r );
  163.        }
  164.  
  165.        for (;;) {
  166.                if (! ReadOK(fd,&c,1))
  167.                        pm_error("EOF / read error on image data" );
  168.  
  169.                if (c == ';') {         /* GIF terminator */
  170.                        if (imageCount < imageNumber)
  171.                                pm_error("only %d image%s found in file",
  172.                                         imageCount, imageCount>1?"s":"" );
  173.                        return;
  174.                }
  175.  
  176.                if (c == '!') {         /* Extension */
  177.                        if (! ReadOK(fd,&c,1))
  178.                                pm_error("OF / read error on extention function code");
  179.                        DoExtension(fd, c);
  180.                        continue;
  181.                }
  182.  
  183.                if (c != ',') {         /* Not a valid start character */
  184.                        pm_message("bogus character 0x%02x, ignoring", (int) c );
  185.                        continue;
  186.                }
  187.  
  188.                ++imageCount;
  189.  
  190.                if (! ReadOK(fd,buf,9))
  191.                        pm_error("couldn't read left/top/width/height");
  192.  
  193.                useGlobalColormap = ! BitSet(buf[8], LOCALCOLORMAP);
  194.  
  195.                bitPixel = 1<<((buf[8]&0x07)+1);
  196.  
  197.                if (! useGlobalColormap) {
  198.                        if (ReadColorMap(fd, bitPixel, localColorMap, &grayScale))
  199.                                pm_error("error reading local colormap" );
  200.                        ReadImage(fd, LM_to_uint(buf[4],buf[5]),
  201.                                  LM_to_uint(buf[6],buf[7]), 
  202.                                  localColorMap, grayScale,
  203.                                  BitSet(buf[8], INTERLACE), imageCount != imageNumber);
  204.                } else {
  205.                        ReadImage(fd, LM_to_uint(buf[4],buf[5]),
  206.                                  LM_to_uint(buf[6],buf[7]), 
  207.                                  GifScreen.ColorMap, GifScreen.GrayScale,
  208.                                  BitSet(buf[8], INTERLACE), imageCount != imageNumber);
  209.                }
  210.  
  211.        }
  212. }
  213.  
  214. static int
  215. ReadColorMap(fd,number,buffer,pbm_format)
  216. FILE           *fd;
  217. int            number;
  218. unsigned char  buffer[3][MAXCOLORMAPSIZE];
  219. int            *pbm_format;
  220. {
  221.        int             i;
  222.        unsigned char   rgb[3];
  223.        int             flag;
  224.  
  225.        flag = TRUE;
  226.  
  227.        for (i = 0; i < number; ++i) {
  228.                if (! ReadOK(fd, rgb, sizeof(rgb)))
  229.                        pm_error("bad colormap" );
  230.  
  231.                buffer[CM_RED][i] = rgb[0] ;
  232.                buffer[CM_GREEN][i] = rgb[1] ;
  233.                buffer[CM_BLUE][i] = rgb[2] ;
  234.  
  235.                flag &= (rgb[0] == rgb[1] && rgb[1] == rgb[2]);
  236.        }
  237.  
  238.        if (flag)
  239.                *pbm_format = (number == 2) ? PBM_TYPE : PGM_TYPE;
  240.        else
  241.                *pbm_format = PPM_TYPE;
  242.  
  243.        return FALSE;
  244. }
  245.  
  246. static int
  247. DoExtension(fd, label)
  248. FILE   *fd;
  249. int    label;
  250. {
  251.        static char     buf[256];
  252.        char            *str;
  253.  
  254.        switch (label) {
  255.        case 0x01:              /* Plain Text Extension */
  256.                str = "Plain Text Extension";
  257. #ifdef notdef
  258.                if (GetDataBlock(fd, (unsigned char*) buf) == 0)
  259.                        ;
  260.  
  261.                lpos   = LM_to_uint(buf[0], buf[1]);
  262.                tpos   = LM_to_uint(buf[2], buf[3]);
  263.                width  = LM_to_uint(buf[4], buf[5]);
  264.                height = LM_to_uint(buf[6], buf[7]);
  265.                cellw  = buf[8];
  266.                cellh  = buf[9];
  267.                foreground = buf[10];
  268.                background = buf[11];
  269.  
  270.                while (GetDataBlock(fd, (unsigned char*) buf) != 0) {
  271.                        PPM_ASSIGN(image[ypos][xpos],
  272.                                        cmap[CM_RED][v],
  273.                                        cmap[CM_GREEN][v],
  274.                                        cmap[CM_BLUE][v]);
  275.                        ++index;
  276.                }
  277.  
  278.                return FALSE;
  279. #else
  280.                break;
  281. #endif
  282.        case 0xff:              /* Application Extension */
  283.                str = "Application Extension";
  284.                break;
  285.        case 0xfe:              /* Comment Extension */
  286.                str = "Comment Extension";
  287.                while (GetDataBlock(fd, (unsigned char*) buf) != 0) {
  288.                        if (showComment)
  289.                                pm_message("gif comment: %s", buf );
  290.                }
  291.                return FALSE;
  292.        case 0xf9:              /* Graphic Control Extension */
  293.                str = "Graphic Control Extension";
  294.                (void) GetDataBlock(fd, (unsigned char*) buf);
  295.                Gif89.disposal    = (buf[0] >> 2) & 0x7;
  296.                Gif89.inputFlag   = (buf[0] >> 1) & 0x1;
  297.                Gif89.delayTime   = LM_to_uint(buf[1],buf[2]);
  298.                if ((buf[0] & 0x1) != 0)
  299.                        Gif89.transparent = buf[3];
  300.  
  301.                while (GetDataBlock(fd, (unsigned char*) buf) != 0)
  302.                        ;
  303.                return FALSE;
  304.        default:
  305.                str = buf;
  306.                sprintf(buf, "UNKNOWN (0x%02x)", label);
  307.                break;
  308.        }
  309.  
  310.        pm_message("got a '%s' extension", str );
  311.  
  312.        while (GetDataBlock(fd, (unsigned char*) buf) != 0)
  313.                ;
  314.  
  315.        return FALSE;
  316. }
  317.  
  318. int    ZeroDataBlock = FALSE;
  319.  
  320. static int
  321. GetDataBlock(fd, buf)
  322. FILE           *fd;
  323. unsigned char  *buf;
  324. {
  325.        unsigned char   count;
  326.  
  327.        if (! ReadOK(fd,&count,1)) {
  328.                pm_message("error in getting DataBlock size" );
  329.                return -1;
  330.        }
  331.  
  332.        ZeroDataBlock = count == 0;
  333.  
  334.        if ((count != 0) && (! ReadOK(fd, buf, count))) {
  335.                pm_message("error in reading DataBlock" );
  336.                return -1;
  337.        }
  338.  
  339.        return count;
  340. }
  341.  
  342. static int
  343. GetCode(fd, code_size, flag)
  344. FILE   *fd;
  345. int    code_size;
  346. int    flag;
  347. {
  348.        static unsigned char    buf[280];
  349.        static int              curbit, lastbit, done, last_byte;
  350.        int                     i, j, ret;
  351.        unsigned char           count;
  352.  
  353.        if (flag) {
  354.                curbit = 0;
  355.                lastbit = 0;
  356.                done = FALSE;
  357.                return 0;
  358.        }
  359.  
  360.        if ( (curbit+code_size) >= lastbit) {
  361.                if (done) {
  362.                        if (curbit >= lastbit)
  363.                                pm_error("ran off the end of my bits" );
  364.                        return -1;
  365.                }
  366.                buf[0] = buf[last_byte-2];
  367.                buf[1] = buf[last_byte-1];
  368.  
  369.                if ((count = GetDataBlock(fd, &buf[2])) == 0)
  370.                        done = TRUE;
  371.  
  372.                last_byte = 2 + count;
  373.                curbit = (curbit - lastbit) + 16;
  374.                lastbit = (2+count)*8 ;
  375.        }
  376.  
  377.        ret = 0;
  378.        for (i = curbit, j = 0; j < code_size; ++i, ++j)
  379.                ret |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j;
  380.  
  381.        curbit += code_size;
  382.  
  383.        return ret;
  384. }
  385.  
  386. static int
  387. LWZReadByte(fd, flag, input_code_size)
  388. FILE   *fd;
  389. int    flag;
  390. int    input_code_size;
  391. {
  392.        static int      fresh = FALSE;
  393.        int             code, incode;
  394.        static int      code_size, set_code_size;
  395.        static int      max_code, max_code_size;
  396.        static int      firstcode, oldcode;
  397.        static int      clear_code, end_code;
  398.        static int      table[2][(1<< MAX_LWZ_BITS)];
  399.        static int      stack[(1<<(MAX_LWZ_BITS))*2], *sp;
  400.        register int    i;
  401.  
  402.        if (flag) {
  403.                set_code_size = input_code_size;
  404.                code_size = set_code_size+1;
  405.                clear_code = 1 << set_code_size ;
  406.                end_code = clear_code + 1;
  407.                max_code_size = 2*clear_code;
  408.                max_code = clear_code+2;
  409.  
  410.                GetCode(fd, 0, TRUE);
  411.                
  412.                fresh = TRUE;
  413.  
  414.                for (i = 0; i < clear_code; ++i) {
  415.                        table[0][i] = 0;
  416.                        table[1][i] = i;
  417.                }
  418.                for (; i < (1<<MAX_LWZ_BITS); ++i)
  419.                        table[0][i] = table[1][0] = 0;
  420.  
  421.                sp = stack;
  422.  
  423.                return 0;
  424.        } else if (fresh) {
  425.                fresh = FALSE;
  426.                do {
  427.                        firstcode = oldcode =
  428.                                GetCode(fd, code_size, FALSE);
  429.                } while (firstcode == clear_code);
  430.                return firstcode;
  431.        }
  432.  
  433.        if (sp > stack)
  434.                return *--sp;
  435.  
  436.        while ((code = GetCode(fd, code_size, FALSE)) >= 0) {
  437.                if (code == clear_code) {
  438.                        for (i = 0; i < clear_code; ++i) {
  439.                                table[0][i] = 0;
  440.                                table[1][i] = i;
  441.                        }
  442.                        for (; i < (1<<MAX_LWZ_BITS); ++i)
  443.                                table[0][i] = table[1][i] = 0;
  444.                        code_size = set_code_size+1;
  445.                        max_code_size = 2*clear_code;
  446.                        max_code = clear_code+2;
  447.                        sp = stack;
  448.                        firstcode = oldcode =
  449.                                        GetCode(fd, code_size, FALSE);
  450.                        return firstcode;
  451.                } else if (code == end_code) {
  452.                        int             count;
  453.                        unsigned char   buf[260];
  454.  
  455.                        if (ZeroDataBlock)
  456.                                return -2;
  457.  
  458.                        while ((count = GetDataBlock(fd, buf)) > 0)
  459.                                ;
  460.  
  461.                        if (count != 0)
  462.                                pm_message("missing EOD in data stream (common occurence)");
  463.                        return -2;
  464.                }
  465.  
  466.                incode = code;
  467.  
  468.                if (code >= max_code) {
  469.                        *sp++ = firstcode;
  470.                        code = oldcode;
  471.                }
  472.  
  473.                while (code >= clear_code) {
  474.                        *sp++ = table[1][code];
  475.                        if (code == table[0][code])
  476.                                pm_error("circular table entry BIG ERROR");
  477.                        code = table[0][code];
  478.                }
  479.  
  480.                *sp++ = firstcode = table[1][code];
  481.  
  482.                if ((code = max_code) <(1<<MAX_LWZ_BITS)) {
  483.                        table[0][code] = oldcode;
  484.                        table[1][code] = firstcode;
  485.                        ++max_code;
  486.                        if ((max_code >= max_code_size) &&
  487.                                (max_code_size < (1<<MAX_LWZ_BITS))) {
  488.                                max_code_size *= 2;
  489.                                ++code_size;
  490.                        }
  491.                }
  492.  
  493.                oldcode = incode;
  494.  
  495.                if (sp > stack)
  496.                        return *--sp;
  497.        }
  498.        return code;
  499. }
  500.  
  501. static void
  502. ReadImage(fd, len, height, cmap, pbm_format, interlace, ignore)
  503. FILE   *fd;
  504. int    len, height;
  505. unsigned char  cmap[3][MAXCOLORMAPSIZE];
  506. int    pbm_format, interlace, ignore;
  507. {
  508.        unsigned char   c;      
  509.        int             v;
  510.        int             xpos = 0, ypos = 0, pass = 0;
  511.        pixel           **image;
  512.  
  513.        /*
  514.        **  Initialize the Compression routines
  515.        */
  516.        if (! ReadOK(fd,&c,1))
  517.                pm_error("EOF / read error on image data" );
  518.  
  519.        if (LWZReadByte(fd, TRUE, c) < 0)
  520.                pm_error("error reading image" );
  521.  
  522.        /*
  523.        **  If this is an "uninteresting picture" ignore it.
  524.        */
  525.        if (ignore) {
  526.                if (verbose)
  527.                        pm_message("skipping image..." );
  528.  
  529.                while (LWZReadByte(fd, FALSE, c) >= 0)
  530.                        ;
  531.                return;
  532.        }
  533.  
  534.        if ((image = pnm_allocarray(len, height)) == NULL)
  535.                pm_error("couldn't alloc space for image" );
  536.  
  537.        if (verbose)
  538.                pm_message("reading %d by %d%s GIF image",
  539.                        len, height, interlace ? " interlaced" : "" );
  540.  
  541.        while ((v = LWZReadByte(fd,FALSE,c)) >= 0 ) {
  542.                PPM_ASSIGN(image[ypos][xpos], cmap[CM_RED][v],
  543.                                        cmap[CM_GREEN][v], cmap[CM_BLUE][v]);
  544.  
  545.                ++xpos;
  546.                if (xpos == len) {
  547.                        xpos = 0;
  548.                        if (interlace) {
  549.                                switch (pass) {
  550.                                case 0:
  551.                                case 1:
  552.                                        ypos += 8; break;
  553.                                case 2:
  554.                                        ypos += 4; break;
  555.                                case 3:
  556.                                        ypos += 2; break;
  557.                                }
  558.  
  559.                                if (ypos >= height) {
  560.                                        ++pass;
  561.                                        switch (pass) {
  562.                                        case 1:
  563.                                                ypos = 4; break;
  564.                                        case 2:
  565.                                                ypos = 2; break;
  566.                                        case 3:
  567.                                                ypos = 1; break;
  568.                                        default:
  569.                                                goto fini;
  570.                                        }
  571.                                }
  572.                        } else {
  573.                                ++ypos;
  574.                        }
  575.                }
  576.                if (ypos >= height)
  577.                        break;
  578.        }
  579.  
  580. fini:
  581.        if (LWZReadByte(fd,FALSE,c)>=0)
  582.                pm_message("too much input data, ignoring extra...");
  583.  
  584.        if (verbose)
  585.                pm_message("writing a %s file",
  586.                                pbm_format == PBM_TYPE ? "PBM" :
  587.                                pbm_format == PGM_TYPE ? "PGM" :
  588.                                pbm_format == PPM_TYPE ? "PPM" :
  589.                                "UNKNOWN!");
  590.  
  591.        pnm_writepnm(stdout, image, len, height, (pixval) 255, pbm_format, 0 );
  592. }
  593.