home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / Graphics / ToyViewer-2.6a / src / ppmread.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-28  |  9.3 KB  |  447 lines

  1. #include  <stdio.h>
  2. #include  <stdlib.h>
  3. #include  <libc.h>
  4. #include  "ppm.h"
  5. #include  "strfunc.h"
  6.  
  7. /* PPM Format
  8.     Px            : Header
  9.     Width Height
  10.     MAX            : pbm does not have this field
  11.     Bitmap        : in ASCII / Binary
  12. */
  13.  
  14. #define  PXOF        0xff
  15. #define  PAOF        0xfe
  16. #define  UnknownHD    0
  17. /* PX original Format
  18.     PX            : Header
  19.     Width Height Colors    : Colors := Number of colors in palette - 1
  20.     Count        : if Trans is there Count=1, otherwise Count=0.
  21.     Trans        : Transparent + 256
  22.     [Palette]        : Binary
  23.     [Bitmap]        : Binary
  24. */
  25. /* PA original Format
  26.     PA            : Header
  27.     Width Height MAX
  28.     Planes        : Planes = 1,2,3 or 4.  (planes 2 and 4 have ALPHA)
  29.     [Bitmap]        : Binary
  30. */
  31.  
  32. static int ppmkind = 0, ppmmax = 0;
  33. static int pxtrans = 0;
  34. static char ppmcomm[MAX_COMMENT];
  35.  
  36. static void ppm_skip(FILE *fp)
  37. {
  38.     int c;
  39.  
  40.     while ((c = getc(fp)) != EOF) {
  41.         if (c == '\n') {
  42.             c = getc(fp);
  43.             while (c == '#') {
  44.                 while ((c = getc(fp)) != '\n')
  45.                     if (c == EOF)
  46.                         return;
  47.                 c = getc(fp);
  48.             }
  49.         }
  50.         if (c > ' ') {
  51.             ungetc(c, fp);
  52.             return;
  53.         }
  54.     }
  55. }
  56.  
  57. static int ppm_head(FILE *fp)
  58. {
  59.     int c, i, kind = UnknownHD;
  60.  
  61.     if ((c = getc(fp)) != 'P')
  62.         return UnknownHD;
  63.     c = getc(fp);
  64.     if (c >= '0' && c <= '9')
  65.         kind = c - '0';
  66.     else if (c == 'X')
  67.         kind = PXOF;
  68.     else if (c == 'A')
  69.         kind = PAOF;
  70.     ppmcomm[0] = 0;
  71.     while ((c = getc(fp)) <= ' ') ;
  72.     if (c == '#') {
  73.         for (i = 0; (c = getc(fp)) != '\n'; i++)
  74.             if (i < MAX_COMMENT-1)
  75.                 ppmcomm[i] = c;
  76.             else {
  77.                 while (getc(fp) != '\n') ;
  78.                 break;
  79.             }
  80.         ppmcomm[i] = 0;
  81.         ungetc('\n', fp);
  82.         ppm_skip(fp);
  83.     }else
  84.         ungetc(c, fp);
  85.     return kind;
  86. }
  87.  
  88. static int ppm_getint(FILE *fp)
  89. {
  90.     int c;
  91.     int v = 0;
  92.  
  93.     c = getc(fp);
  94.     while (c < '0' || c > '9') {
  95.         if (c == EOF) return -1;
  96.         c = getc(fp);
  97.     }
  98.     while (c >= '0' && c <= '9') {
  99.         v = (v * 10) + c - '0';
  100.         c = getc(fp);
  101.     }
  102.     if (c != EOF && c < ' ')
  103.         ungetc(c, fp);
  104.     return v;
  105. }
  106.  
  107.  
  108. commonInfo *loadPpmHeader(FILE *fp, int *errcode)
  109. {
  110.     int w, err;
  111.     commonInfo *cinf;
  112.  
  113.     *errcode = err = 0;
  114.     ppmkind = ppm_head(fp);
  115.     if (ppmkind == UnknownHD) {
  116.         *errcode = Err_FORMAT;
  117.         return NULL;
  118.     }
  119.     if ((w = ppm_getint(fp)) >= MAXWidth) {
  120.         *errcode = Err_IMPLEMENT;
  121.         return NULL;
  122.     }
  123.     if ((cinf = (commonInfo *)malloc(sizeof(commonInfo))) == NULL) {
  124.         *errcode = Err_MEMORY;
  125.         return NULL;
  126.     }
  127.     cinf->width = w;
  128.     cinf->alpha = NO;
  129.     cinf->type = Type_ppm;
  130.     cinf->isplanar = YES;
  131.     cinf->palsteps = 0;
  132.     cinf->palette = NULL;
  133.     cinf->memo[0] = 0;
  134.     ppm_skip(fp);
  135.     cinf->height = ppm_getint(fp);
  136.     if (ppmkind == PBMa || ppmkind == PBMb) {
  137.         ppmmax = 2;
  138.         cinf->numcolors = 1;
  139.         cinf->cspace = NX_OneIsBlackColorSpace;
  140.         cinf->bits = 1;
  141.         cinf->xbytes = byte_length(1, cinf->width);
  142.         (void)getc(fp);    /* feed last CR */
  143.         return cinf;
  144.     }
  145.     ppm_skip(fp);
  146.     ppmmax = ppm_getint(fp) + 1;
  147.     if (ppmkind == PAOF) {
  148.         int pn;
  149.         ppm_skip(fp);
  150.         pn = ppm_getint(fp);
  151.         if (pn < 1 || pn > 4) { /* PAOF must have alpha */
  152.             *errcode = Err_FORMAT;
  153.             return NULL;
  154.         }
  155.         if (pn >= 3) {
  156.             cinf->numcolors = 3;
  157.             cinf->cspace = NX_RGBColorSpace;
  158.         }else {
  159.             cinf->numcolors = 1;
  160.             cinf->cspace = NX_OneIsWhiteColorSpace;
  161.         }
  162.         (void)getc(fp);    /* feed last CR */
  163.         cinf->alpha = (pn == 2 || pn == 4);
  164.     }else if (ppmkind == PXOF) {
  165.         int cnt;
  166.         pxtrans = -1;
  167.         ppm_skip(fp);
  168.         cnt = ppm_getint(fp);
  169.         if (cnt-- > 0) {
  170.             ppm_skip(fp);
  171.             pxtrans = ppm_getint(fp);
  172.         }
  173.         while (cnt-- > 0) { /* skip unknown parameters */
  174.             ppm_skip(fp);
  175.             (void) ppm_getint(fp);
  176.         }
  177.         (void)getc(fp);    /* feed last CR */
  178.         if (pxtrans >= 256) {
  179.             cinf->alpha = YES;
  180.             pxtrans -= 256;
  181.         }else
  182.             pxtrans = -1;
  183.         cinf->numcolors = 3;
  184.         cinf->cspace = NX_RGBColorSpace;
  185.         cinf->bits = 8;
  186.         cinf->xbytes = cinf->width;
  187.         return cinf;
  188.     }else {
  189.         (void)getc(fp);    /* feed last CR */
  190.         if (ppmkind == PPMa || ppmkind == PPMb) {
  191.             cinf->numcolors = 3;
  192.             cinf->cspace = NX_RGBColorSpace;
  193.         }else {
  194.             cinf->numcolors = 1;
  195.             cinf->cspace = NX_OneIsWhiteColorSpace;
  196.         }
  197.     }
  198.  
  199.     cinf->bits = (ppmmax > 16) ? 8
  200.             : ((ppmmax > 4) ? 4 : ((ppmmax > 2) ? 2 : 1));
  201.     cinf->xbytes = byte_length(cinf->bits, cinf->width);
  202.     return cinf;
  203. }
  204.  
  205.  
  206. static int isGrayPPM(unsigned char **planes, int length)
  207. {
  208.     int i;
  209.     unsigned char *rr, *gg, *bb;
  210.  
  211.     rr = planes[0];
  212.     gg = planes[1];
  213.     bb = planes[2];
  214.     for (i = 0; i < length; i++) {
  215.         if (rr[i] != gg[i] || gg[i] != bb[i]) return 0;
  216.     }
  217.     return 1;
  218. }
  219.  
  220. static int bitsOfPPM(unsigned char **planes, commonInfo *cinf)
  221. {
  222.     unsigned char *p, buf[256];
  223.     int i, pn, pnmx, w, num;
  224.  
  225.     w = cinf->width * cinf->height;
  226.     for (i = 0; i < 256; i++) buf[i] = 0;
  227.     num = 0;
  228.     pnmx = cinf->numcolors;
  229.     if (cinf->alpha) pnmx++;
  230.     for (pn = 0; pn < pnmx; pn++) {
  231.         p = planes[pn];
  232.         for (i = 0; i < w; i++)
  233.             if (buf[p[i]] == 0) {
  234.                 buf[p[i]] = 1;
  235.                 if (++num > 16) return 8;
  236.             }
  237.     }
  238.     return optimalBits(buf, num);
  239. }
  240.  
  241. static int getPXOF(FILE *fp, commonInfo *cinf,
  242.             unsigned char **planes, int *aflag)
  243. {
  244.     int    i, x, y;
  245.     unsigned char *p, *rr, *gg, *bb;
  246.  
  247.     cinf->palette = (paltype *)malloc(sizeof(paltype) * ppmmax);
  248.     if (cinf->palette == NULL)
  249.         return Err_MEMORY;
  250.     cinf->palsteps = ppmmax;
  251.     for (i = 0; i < ppmmax; i++) {
  252.         p = cinf->palette[i];
  253.         for (x = 0; x < 3; x++)
  254.             p[x] = getc(fp);
  255.     }
  256.     rr = planes[0];
  257.     gg = planes[1];
  258.     bb = planes[2];
  259.     if (! cinf->alpha) {
  260.         for (y = 0; y < cinf->height; y++) {
  261.             for (x = 0; x < cinf->width; x++) {
  262.                 p = cinf->palette[getc(fp)];
  263.                 *rr++ = p[RED];
  264.                 *gg++ = p[GREEN];
  265.                 *bb++ = p[BLUE];
  266.             }
  267.         }
  268.     }else {
  269.         unsigned char *aa = planes[3];
  270.         int cc;
  271.         for (y = 0; y < cinf->height; y++) {
  272.             for (x = 0; x < cinf->width; x++) {
  273.                 if ((cc = getc(fp)) == pxtrans) {
  274.                     *rr++ = *gg++ = *bb++ = 255;
  275.                     *aa++ = AlphaTransp;
  276.                     *aflag = YES;
  277.                 }else {
  278.                     p = cinf->palette[cc];
  279.                     *rr++ = p[RED];
  280.                     *gg++ = p[GREEN];
  281.                     *bb++ = p[BLUE];
  282.                     *aa++ = AlphaOpaque;
  283.                 }
  284.             }
  285.         }
  286.         if (pxtrans != ppmmax - 1) {
  287.             unsigned char *q;
  288.             p = cinf->palette[ppmmax-1];
  289.             q = cinf->palette[pxtrans];
  290.             for (i = 0; i < 3; i++)
  291.                 q[i] = p[i];
  292.             cinf->palsteps = pxtrans = ppmmax - 1;
  293.             p = cinf->palette[pxtrans];
  294.             for (i = 0; i < 3; i++)
  295.                 p[i] = 255;
  296.         }
  297.     }
  298.     return 0;
  299. }
  300.  
  301. static int PPMplanes(FILE *fp,
  302.     commonInfo *cinf, int pn, unsigned char **planes, int *hasalpha)
  303. {
  304.     int    i, r, x, y;
  305.     unsigned char    work[MAXPLANE][MAXWidth];
  306.     unsigned char    *pp;
  307.     int    width = cinf->width;
  308.     int    rdmax = ppmmax - 1;
  309.     int    aflag = NO;
  310.  
  311.     for (y = 0; y < cinf->height; y++) {
  312.         if (feof(fp))
  313.             return Err_SHORT;
  314.         if (isPPMascii(ppmkind)) {
  315.             for (x = 0; x < width; x++)
  316.                 for (i = 0; i < pn; i++) {
  317.                 ppm_skip(fp);
  318.                 work[i][x] = ((r = ppm_getint(fp)) >= rdmax)
  319.                     ? 255 : ((r << 8) / ppmmax);
  320.                 }
  321.         }else if (ppmkind == PBMb) {
  322.             int mask, cc;
  323.             for (x = 0; x < width; ) {
  324.                 cc = getc(fp);
  325.                 for (mask = 0x80; mask; mask >>= 1) {
  326.                     work[0][x] = (cc & mask) ? 0xff : 0;
  327.                     if (++x >= width) break;
  328.                 }
  329.             }
  330.         }else {
  331.             for (x = 0; x < width; x++) {
  332.                 for (i = 0; i < pn; i++)
  333.                 work[i][x] = ((r = getc(fp)) >= rdmax)
  334.                     ? 255 : ((r << 8) / ppmmax);
  335.             }
  336.         }
  337.         for (i = 0; i < pn; i++) {
  338.             pp = planes[i] + y * cinf->xbytes;
  339.             packImage(pp, work[i], width, cinf->bits);
  340.         }
  341.         if (cinf->alpha && aflag == NO) {
  342.             pp = work[pn - 1];
  343.             for (i = 0; i < width; i++) {
  344.                 if (*pp++ != AlphaOpaque) {
  345.                     aflag = YES;
  346.                     break;
  347.                 }
  348.             }
  349.         }
  350.     }
  351.     *hasalpha = aflag;
  352.     return 0;
  353. }
  354.  
  355. int ppmGetImage(FILE *fp,
  356.     commonInfo *cinf, unsigned char **planes, const char *fkind)
  357. {
  358.     int    i, y, pn, bits, err;
  359.     int    width, xbyte;
  360.     const char *kp;
  361.     int    aflag = NO;
  362.  
  363.     width = cinf->width;
  364.     pn = cinf->numcolors;
  365.     if (cinf->alpha) pn++;
  366.     err = allocImage(planes, width, cinf->height, cinf->bits, pn);
  367.     if (err) return err;
  368.     if (ppmkind == PXOF)
  369.         err = getPXOF(fp, cinf, planes, &aflag);
  370.     else
  371.         err = PPMplanes(fp, cinf, pn, planes, &aflag);
  372.     if (err) return err;
  373.  
  374.     /* ALPHA image ? */
  375.     if (cinf->alpha && aflag == NO) {
  376.         cinf->alpha = NO;
  377.         --pn;
  378.     }
  379.     /* Is this image Gray ? */
  380.     if (pn == 3 && isGrayPPM(planes, cinf->xbytes * cinf->height)) {
  381.         size_t newsize = planes[1] - planes[0];
  382.         planes[0] = (unsigned char *)realloc(planes[0], newsize);
  383.         planes[1] = planes[2] = NULL;
  384.         pn = cinf->numcolors = 1;
  385.         cinf->cspace = NX_OneIsWhiteColorSpace;
  386.     }
  387.     /* How many bits are needed ? */
  388.     if (cinf->bits == 8 && (bits = bitsOfPPM(planes, cinf)) < 8) {
  389.         unsigned char *src, *dst, *newmap[MAXPLANE];
  390.         err = allocImage(newmap, width, cinf->height, bits, pn);
  391.         if (err) return 0; /* Error */
  392.         xbyte = byte_length(bits, width);
  393.         for (i = 0; i < pn; i++) {
  394.             src = planes[i];
  395.             dst = newmap[i];
  396.             for (y = 0; y < cinf->height; y++) {
  397.                 packImage(dst, src, width, bits);
  398.                 src += width;
  399.                 dst += xbyte;
  400.             }
  401.         }
  402.         free((void *)planes[0]);
  403.         for (i = 0; i < pn; i++)
  404.             planes[i] = newmap[i];
  405.         cinf->xbytes = xbyte;
  406.         cinf->bits = bits;
  407.     }
  408.  
  409.     sprintf(cinf->memo, "%d x %d  ", cinf->width, cinf->height);
  410.     if (fkind) kp = fkind;
  411.     else if (ppmkind == PXOF) kp = "PXOF";
  412.     else if (ppmkind == PAOF) kp = "PAOF";
  413.     else kp = PPMname(ppmkind);
  414.     strcat(cinf->memo, kp);
  415.     if ((bits = cinf->bits) == 1)
  416.         strcat(cinf->memo, " 1bit");
  417.     else {
  418.         i = strlen(cinf->memo);
  419.         sprintf(cinf->memo + i, " %dbits%s", bits,
  420.                 (pn > 2 ? "" : " gray"));
  421.     }
  422.     if (pn == 2 || pn == 4)
  423.         strcat(cinf->memo, " Alpha");
  424.  
  425.     if (ppmcomm[0]) {
  426.         const char *p = ppmcomm;
  427.         while (*p == ' ') p++;
  428.         if (*p != 0) {
  429.             strcat(cinf->memo, "  ");
  430.             comm_cat(cinf->memo, p);
  431.         }
  432.     }
  433.  
  434.     return 0;
  435. }
  436.  
  437. #ifdef _TEST
  438. main()
  439. {
  440.     printf("kind=P%d\n", ppm_head(stdin));
  441.     while (!feof(stdin)) {
  442.         ppm_skip(stdin);
  443.         printf("%d\n", ppm_getint(stdin));
  444.     }
  445. }
  446. #endif
  447.