Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.     IMGLIB:  An example image loading library for use with SDL
  3.     Copyright (C) 1999  Sam Lantinga
  4.  
  5.     This library is free software; you can redistribute it and/or
  6.     modify it under the terms of the GNU Library General Public
  7.     License as published by the Free Software Foundation; either
  8.     version 2 of the License, or (at your option) any later version.
  9.  
  10.     This library is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13.     Library General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU Library General Public
  16.     License along with this library; if not, write to the Free
  17.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  
  19.     Sam Lantinga
  20.     5635-34 Springhouse Dr.
  21.     Pleasanton, CA 94588 (USA)
  22.     slouken@devolution.com
  23. */
  24.  
  25. /* This is a GIF image file loading framework */
  26.  
  27. #include <stdio.h>
  28. #include <string.h>
  29.  
  30. #include "SDL_image.h"
  31.  
  32. #ifdef LOAD_GIF
  33.  
  34. /* See if an image is contained in a data source */
  35. int IMG_isGIF(SDL_RWops *src)
  36. {
  37.         int is_GIF;
  38.         char magic[6];
  39.  
  40.         is_GIF = 0;
  41.         if ( SDL_RWread(src, magic, 6, 1) ) {
  42.                 if ( (strncmp(magic, "GIF", 3) == 0) &&
  43.                      ((memcmp(magic + 3, "87a", 3) == 0) ||
  44.                       (memcmp(magic + 3, "89a", 3) == 0)) ) {
  45.                         is_GIF = 1;
  46.                 }
  47.         }
  48.         return(is_GIF);
  49. }
  50.  
  51. /* Code from here to end of file has been adapted from XPaint:           */
  52. /* +-------------------------------------------------------------------+ */
  53. /* | Copyright 1990, 1991, 1993 David Koblas.                          | */
  54. /* | Copyright 1996 Torsten Martinsen.                                 | */
  55. /* |   Permission to use, copy, modify, and distribute this software   | */
  56. /* |   and its documentation for any purpose and without fee is hereby | */
  57. /* |   granted, provided that the above copyright notice appear in all | */
  58. /* |   copies and that both that copyright notice and this permission  | */
  59. /* |   notice appear in supporting documentation.  This software is    | */
  60. /* |   provided "as is" without express or implied warranty.           | */
  61. /* +-------------------------------------------------------------------+ */
  62.  
  63. /* Adapted for use in SDL by Sam Lantinga -- 7/20/98 */
  64. #define USED_BY_SDL
  65.  
  66. #include <stdio.h>
  67. #include <string.h>
  68.  
  69. #ifdef USED_BY_SDL
  70. /* Changes to work with SDL:
  71.  
  72.    Include SDL header file
  73.    Use SDL_Surface rather than xpaint Image structure
  74.    Define SDL versions of RWSetMsg(), ImageNewCmap() and ImageSetCmap()
  75. */
  76. #include "SDL.h"
  77.  
  78. #define Image                   SDL_Surface
  79. #define RWSetMsg                IMG_SetError
  80. #define ImageNewCmap(w, h, s)   SDL_AllocSurface(SDL_SWSURFACE,w,h,8,0,0,0,0)
  81. #define ImageSetCmap(s, i, R, G, B) do { \
  82.                                 s->format->palette->colors[i].r = R; \
  83.                                 s->format->palette->colors[i].g = G; \
  84.                                 s->format->palette->colors[i].b = B; \
  85.                         } while (0)
  86. /* * * * * */
  87.  
  88. #else
  89.  
  90. /* Original XPaint sources */
  91.  
  92. #include "image.h"
  93. #include "rwTable.h"
  94.  
  95. #define SDL_RWops       FILE
  96. #define SDL_RWclose     fclose
  97.  
  98. #endif /* USED_BY_SDL */
  99.  
  100.  
  101. #define MAXCOLORMAPSIZE         256
  102.  
  103. #define TRUE    1
  104. #define FALSE   0
  105.  
  106. #define CM_RED          0
  107. #define CM_GREEN        1
  108. #define CM_BLUE         2
  109.  
  110. #define MAX_LWZ_BITS            12
  111.  
  112. #define INTERLACE               0x40
  113. #define LOCALCOLORMAP   0x80
  114. #define BitSet(byte, bit)       (((byte) & (bit)) == (bit))
  115.  
  116. #define ReadOK(file,buffer,len) SDL_RWread(file, buffer, len, 1)
  117.  
  118. #define LM_to_uint(a,b)                 (((b)<<8)|(a))
  119.  
  120. static struct {
  121.     unsigned int Width;
  122.     unsigned int Height;
  123.     unsigned char ColorMap[3][MAXCOLORMAPSIZE];
  124.     unsigned int BitPixel;
  125.     unsigned int ColorResolution;
  126.     unsigned int Background;
  127.     unsigned int AspectRatio;
  128.     int GrayScale;
  129. } GifScreen;
  130.  
  131. static struct {
  132.     int transparent;
  133.     int delayTime;
  134.     int inputFlag;
  135.     int disposal;
  136. } Gif89;
  137.  
  138. static int ReadColorMap(SDL_RWops * src, int number,
  139.                         unsigned char buffer[3][MAXCOLORMAPSIZE], int *flag);
  140. static int DoExtension(SDL_RWops * src, int label);
  141. static int GetDataBlock(SDL_RWops * src, unsigned char *buf);
  142. static int GetCode(SDL_RWops * src, int code_size, int flag);
  143. static int LWZReadByte(SDL_RWops * src, int flag, int input_code_size);
  144. static Image *ReadImage(SDL_RWops * src, int len, int height, int,
  145.                         unsigned char cmap[3][MAXCOLORMAPSIZE],
  146.                         int gray, int interlace, int ignore);
  147.  
  148. Image *
  149. IMG_LoadGIF_RW(SDL_RWops *src)
  150. {
  151.     unsigned char buf[16];
  152.     unsigned char c;
  153.     unsigned char localColorMap[3][MAXCOLORMAPSIZE];
  154.     int grayScale;
  155.     int useGlobalColormap;
  156.     int bitPixel;
  157.     int imageCount = 0;
  158.     char version[4];
  159.     int imageNumber = 1;
  160.     Image *image = NULL;
  161.  
  162.     if ( src == NULL ) {
  163.         goto done;
  164.     }
  165.     if (!ReadOK(src, buf, 6)) {
  166.         RWSetMsg("error reading magic number");
  167.         goto done;
  168.     }
  169.     if (strncmp((char *) buf, "GIF", 3) != 0) {
  170.         RWSetMsg("not a GIF file");
  171.         goto done;
  172.     }
  173.     strncpy(version, (char *) buf + 3, 3);
  174.     version[3] = '\0';
  175.  
  176.     if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) {
  177.         RWSetMsg("bad version number, not '87a' or '89a'");
  178.         goto done;
  179.     }
  180.     Gif89.transparent = -1;
  181.     Gif89.delayTime = -1;
  182.     Gif89.inputFlag = -1;
  183.     Gif89.disposal = 0;
  184.  
  185.     if (!ReadOK(src, buf, 7)) {
  186.         RWSetMsg("failed to read screen descriptor");
  187.         goto done;
  188.     }
  189.     GifScreen.Width = LM_to_uint(buf[0], buf[1]);
  190.     GifScreen.Height = LM_to_uint(buf[2], buf[3]);
  191.     GifScreen.BitPixel = 2 << (buf[4] & 0x07);
  192.     GifScreen.ColorResolution = (((buf[4] & 0x70) >> 3) + 1);
  193.     GifScreen.Background = buf[5];
  194.     GifScreen.AspectRatio = buf[6];
  195.  
  196.     if (BitSet(buf[4], LOCALCOLORMAP)) {        /* Global Colormap */
  197.         if (ReadColorMap(src, GifScreen.BitPixel, GifScreen.ColorMap,
  198.                          &GifScreen.GrayScale)) {
  199.             RWSetMsg("error reading global colormap");
  200.             goto done;
  201.         }
  202.     }
  203.     do {
  204.         if (!ReadOK(src, &c, 1)) {
  205.             RWSetMsg("EOF / read error on image data");
  206.             goto done;
  207.         }
  208.         if (c == ';') {         /* GIF terminator */
  209.             if (imageCount < imageNumber) {
  210.                 RWSetMsg("only %d image%s found in file",
  211.                          imageCount, imageCount > 1 ? "s" : "");
  212.                 goto done;
  213.             }
  214.         }
  215.         if (c == '!') {         /* Extension */
  216.             if (!ReadOK(src, &c, 1)) {
  217.                 RWSetMsg("EOF / read error on extention function code");
  218.                 goto done;
  219.             }
  220.             DoExtension(src, c);
  221.             continue;
  222.         }
  223.         if (c != ',') {         /* Not a valid start character */
  224.             continue;
  225.         }
  226.         ++imageCount;
  227.  
  228.         if (!ReadOK(src, buf, 9)) {
  229.             RWSetMsg("couldn't read left/top/width/height");
  230.             goto done;
  231.         }
  232.         useGlobalColormap = !BitSet(buf[8], LOCALCOLORMAP);
  233.  
  234.         bitPixel = 1 << ((buf[8] & 0x07) + 1);
  235.  
  236.         if (!useGlobalColormap) {
  237.             if (ReadColorMap(src, bitPixel, localColorMap, &grayScale)) {
  238.                 RWSetMsg("error reading local colormap");
  239.                 goto done;
  240.             }
  241.             image = ReadImage(src, LM_to_uint(buf[4], buf[5]),
  242.                               LM_to_uint(buf[6], buf[7]),
  243.                               bitPixel, localColorMap, grayScale,
  244.                               BitSet(buf[8], INTERLACE),
  245.                               imageCount != imageNumber);
  246.         } else {
  247.             image = ReadImage(src, LM_to_uint(buf[4], buf[5]),
  248.                               LM_to_uint(buf[6], buf[7]),
  249.                               GifScreen.BitPixel, GifScreen.ColorMap,
  250.                               GifScreen.GrayScale, BitSet(buf[8], INTERLACE),
  251.                               imageCount != imageNumber);
  252.         }
  253.     } while (image == NULL);
  254.  
  255. #ifdef USED_BY_SDL
  256.     if ( Gif89.transparent > 0 ) {
  257.         SDL_SetColorKey(image, SDL_SRCCOLORKEY, Gif89.transparent);
  258.     }
  259. #endif
  260.  
  261. done:
  262.     return image;
  263. }
  264.  
  265. static int
  266. ReadColorMap(SDL_RWops *src, int number,
  267.              unsigned char buffer[3][MAXCOLORMAPSIZE], int *gray)
  268. {
  269.     int i;
  270.     unsigned char rgb[3];
  271.     int flag;
  272.  
  273.     flag = TRUE;
  274.  
  275.     for (i = 0; i < number; ++i) {
  276.         if (!ReadOK(src, rgb, sizeof(rgb))) {
  277.             RWSetMsg("bad colormap");
  278.             return 1;
  279.         }
  280.         buffer[CM_RED][i] = rgb[0];
  281.         buffer[CM_GREEN][i] = rgb[1];
  282.         buffer[CM_BLUE][i] = rgb[2];
  283.         flag &= (rgb[0] == rgb[1] && rgb[1] == rgb[2]);
  284.     }
  285.  
  286. #if 0
  287.     if (flag)
  288.         *gray = (number == 2) ? PBM_TYPE : PGM_TYPE;
  289.     else
  290.         *gray = PPM_TYPE;
  291. #else
  292.     *gray = 0;
  293. #endif
  294.  
  295.     return FALSE;
  296. }
  297.  
  298. static int
  299. DoExtension(SDL_RWops *src, int label)
  300. {
  301.     static unsigned char buf[256];
  302.     char *str;
  303.  
  304.     switch (label) {
  305.     case 0x01:                  /* Plain Text Extension */
  306.         str = "Plain Text Extension";
  307.         break;
  308.     case 0xff:                  /* Application Extension */
  309.         str = "Application Extension";
  310.         break;
  311.     case 0xfe:                  /* Comment Extension */
  312.         str = "Comment Extension";
  313.         while (GetDataBlock(src, (unsigned char *) buf) != 0);
  314.         return FALSE;
  315.     case 0xf9:                  /* Graphic Control Extension */
  316.         str = "Graphic Control Extension";
  317.         (void) GetDataBlock(src, (unsigned char *) buf);
  318.         Gif89.disposal = (buf[0] >> 2) & 0x7;
  319.         Gif89.inputFlag = (buf[0] >> 1) & 0x1;
  320.         Gif89.delayTime = LM_to_uint(buf[1], buf[2]);
  321.         if ((buf[0] & 0x1) != 0)
  322.             Gif89.transparent = buf[3];
  323.  
  324.         while (GetDataBlock(src, (unsigned char *) buf) != 0);
  325.         return FALSE;
  326.     default:
  327.         str = (char *)buf;
  328.         sprintf(str, "UNKNOWN (0x%02x)", label);
  329.         break;
  330.     }
  331.  
  332.     while (GetDataBlock(src, (unsigned char *) buf) != 0);
  333.  
  334.     return FALSE;
  335. }
  336.  
  337. static int ZeroDataBlock = FALSE;
  338.  
  339. static int
  340. GetDataBlock(SDL_RWops *src, unsigned char *buf)
  341. {
  342.     unsigned char count;
  343.  
  344.     if (!ReadOK(src, &count, 1)) {
  345.         /* pm_message("error in getting DataBlock size" ); */
  346.         return -1;
  347.     }
  348.     ZeroDataBlock = count == 0;
  349.  
  350.     if ((count != 0) && (!ReadOK(src, buf, count))) {
  351.         /* pm_message("error in reading DataBlock" ); */
  352.         return -1;
  353.     }
  354.     return count;
  355. }
  356.  
  357. static int
  358. GetCode(SDL_RWops *src, int code_size, int flag)
  359. {
  360.     static unsigned char buf[280];
  361.     static int curbit, lastbit, done, last_byte;
  362.     int i, j, ret;
  363.     unsigned char count;
  364.  
  365.     if (flag) {
  366.         curbit = 0;
  367.         lastbit = 0;
  368.         done = FALSE;
  369.         return 0;
  370.     }
  371.     if ((curbit + code_size) >= lastbit) {
  372.         if (done) {
  373.             if (curbit >= lastbit)
  374.                 RWSetMsg("ran off the end of my bits");
  375.             return -1;
  376.         }
  377.         buf[0] = buf[last_byte - 2];
  378.         buf[1] = buf[last_byte - 1];
  379.  
  380.         if ((count = GetDataBlock(src, &buf[2])) == 0)
  381.             done = TRUE;
  382.  
  383.         last_byte = 2 + count;
  384.         curbit = (curbit - lastbit) + 16;
  385.         lastbit = (2 + count) * 8;
  386.     }
  387.     ret = 0;
  388.     for (i = curbit, j = 0; j < code_size; ++i, ++j)
  389.         ret |= ((buf[i / 8] & (1 << (i % 8))) != 0) << j;
  390.  
  391.     curbit += code_size;
  392.  
  393.     return ret;
  394. }
  395.  
  396. static int
  397. LWZReadByte(SDL_RWops *src, int flag, int input_code_size)
  398. {
  399.     static int fresh = FALSE;
  400.     int code, incode;
  401.     static int code_size, set_code_size;
  402.     static int max_code, max_code_size;
  403.     static int firstcode, oldcode;
  404.     static int clear_code, end_code;
  405.     static int table[2][(1 << MAX_LWZ_BITS)];
  406.     static int stack[(1 << (MAX_LWZ_BITS)) * 2], *sp;
  407.     register int i;
  408.  
  409.     if (flag) {
  410.         set_code_size = input_code_size;
  411.         code_size = set_code_size + 1;
  412.         clear_code = 1 << set_code_size;
  413.         end_code = clear_code + 1;
  414.         max_code_size = 2 * clear_code;
  415.         max_code = clear_code + 2;
  416.  
  417.         GetCode(src, 0, TRUE);
  418.  
  419.         fresh = TRUE;
  420.  
  421.         for (i = 0; i < clear_code; ++i) {
  422.             table[0][i] = 0;
  423.             table[1][i] = i;
  424.         }
  425.         for (; i < (1 << MAX_LWZ_BITS); ++i)
  426.             table[0][i] = table[1][0] = 0;
  427.  
  428.         sp = stack;
  429.  
  430.         return 0;
  431.     } else if (fresh) {
  432.         fresh = FALSE;
  433.         do {
  434.             firstcode = oldcode = GetCode(src, code_size, FALSE);
  435.         } while (firstcode == clear_code);
  436.         return firstcode;
  437.     }
  438.     if (sp > stack)
  439.         return *--sp;
  440.  
  441.     while ((code = GetCode(src, code_size, FALSE)) >= 0) {
  442.         if (code == clear_code) {
  443.             for (i = 0; i < clear_code; ++i) {
  444.                 table[0][i] = 0;
  445.                 table[1][i] = i;
  446.             }
  447.             for (; i < (1 << MAX_LWZ_BITS); ++i)
  448.                 table[0][i] = table[1][i] = 0;
  449.             code_size = set_code_size + 1;
  450.             max_code_size = 2 * clear_code;
  451.             max_code = clear_code + 2;
  452.             sp = stack;
  453.             firstcode = oldcode = GetCode(src, code_size, FALSE);
  454.             return firstcode;
  455.         } else if (code == end_code) {
  456.             int count;
  457.             unsigned char buf[260];
  458.  
  459.             if (ZeroDataBlock)
  460.                 return -2;
  461.  
  462.             while ((count = GetDataBlock(src, buf)) > 0);
  463.  
  464.             if (count != 0) {
  465.                 /*
  466.                  * pm_message("missing EOD in data stream (common occurence)");
  467.                  */
  468.             }
  469.             return -2;
  470.         }
  471.         incode = code;
  472.  
  473.         if (code >= max_code) {
  474.             *sp++ = firstcode;
  475.             code = oldcode;
  476.         }
  477.         while (code >= clear_code) {
  478.             *sp++ = table[1][code];
  479.             if (code == table[0][code])
  480.                 RWSetMsg("circular table entry BIG ERROR");
  481.             code = table[0][code];
  482.         }
  483.  
  484.         *sp++ = firstcode = table[1][code];
  485.  
  486.         if ((code = max_code) < (1 << MAX_LWZ_BITS)) {
  487.             table[0][code] = oldcode;
  488.             table[1][code] = firstcode;
  489.             ++max_code;
  490.             if ((max_code >= max_code_size) &&
  491.                 (max_code_size < (1 << MAX_LWZ_BITS))) {
  492.                 max_code_size *= 2;
  493.                 ++code_size;
  494.             }
  495.         }
  496.         oldcode = incode;
  497.  
  498.         if (sp > stack)
  499.             return *--sp;
  500.     }
  501.     return code;
  502. }
  503.  
  504. static Image *
  505. ReadImage(SDL_RWops * src, int len, int height, int cmapSize,
  506.           unsigned char cmap[3][MAXCOLORMAPSIZE],
  507.           int gray, int interlace, int ignore)
  508. {
  509.     Image *image;
  510.     unsigned char c;
  511.     int i, v;
  512.     int xpos = 0, ypos = 0, pass = 0;
  513.  
  514.     /*
  515.     **  Initialize the compression routines
  516.      */
  517.     if (!ReadOK(src, &c, 1)) {
  518.         RWSetMsg("EOF / read error on image data");
  519.         return NULL;
  520.     }
  521.     if (LWZReadByte(src, TRUE, c) < 0) {
  522.         RWSetMsg("error reading image");
  523.         return NULL;
  524.     }
  525.     /*
  526.     **  If this is an "uninteresting picture" ignore it.
  527.      */
  528.     if (ignore) {
  529.         while (LWZReadByte(src, FALSE, c) >= 0);
  530.         return NULL;
  531.     }
  532.     image = ImageNewCmap(len, height, cmapSize);
  533.  
  534.     for (i = 0; i < cmapSize; i++)
  535.         ImageSetCmap(image, i, cmap[CM_RED][i],
  536.                      cmap[CM_GREEN][i], cmap[CM_BLUE][i]);
  537.  
  538.     while ((v = LWZReadByte(src, FALSE, c)) >= 0) {
  539. #ifdef USED_BY_SDL
  540.         ((Uint8 *)image->pixels)[xpos + ypos * image->pitch] = v;
  541. #else
  542.         image->data[xpos + ypos * len] = v;
  543. #endif
  544.         ++xpos;
  545.         if (xpos == len) {
  546.             xpos = 0;
  547.             if (interlace) {
  548.                 switch (pass) {
  549.                 case 0:
  550.                 case 1:
  551.                     ypos += 8;
  552.                     break;
  553.                 case 2:
  554.                     ypos += 4;
  555.                     break;
  556.                 case 3:
  557.                     ypos += 2;
  558.                     break;
  559.                 }
  560.  
  561.                 if (ypos >= height) {
  562.                     ++pass;
  563.                     switch (pass) {
  564.                     case 1:
  565.                         ypos = 4;
  566.                         break;
  567.                     case 2:
  568.                         ypos = 2;
  569.                         break;
  570.                     case 3:
  571.                         ypos = 1;
  572.                         break;
  573.                     default:
  574.                         goto fini;
  575.                     }
  576.                 }
  577.             } else {
  578.                 ++ypos;
  579.             }
  580.         }
  581.         if (ypos >= height)
  582.             break;
  583.     }
  584.  
  585.   fini:
  586.  
  587.     return image;
  588. }
  589.  
  590. #else
  591.  
  592. /* See if an image is contained in a data source */
  593. int IMG_isGIF(SDL_RWops *src)
  594. {
  595.         return(0);
  596. }
  597.  
  598. /* Load a GIF type image from an SDL datasource */
  599. SDL_Surface *IMG_LoadGIF_RW(SDL_RWops *src)
  600. {
  601.         return(NULL);
  602. }
  603.  
  604. #endif /* LOAD_GIF */
  605.