Beispiel #1
0
static int png_read_header(FILE*fi, struct png_header*header)
{
    char id[4];
    int len;
    int ok=0;
    unsigned char head[8] = {137,80,78,71,13,10,26,10};
    unsigned char head2[8];
    unsigned char*data;
    fread(head2,8,1,fi);
    if(strncmp((const char*)head,(const char*)head2,4))
        return 0; // not a png file

    while(png_read_chunk(&id, &len, &data, fi))
    {
        //printf("Chunk: %c%c%c%c (len:%d)\n", id[0],id[1],id[2],id[3], len);
        if(!strncmp(id, "IHDR", 4)) {
            char a,b,c,f,i;
            if(len < 8) exit(1);
            header->width = data[0]<<24|data[1]<<16|data[2]<<8|data[3];
            header->height = data[4]<<24|data[5]<<16|data[6]<<8|data[7];
            a = data[8];      // should be 8
            b = data[9];      // should be 3(indexed) or 2(rgb)

            c = data[10];     // compression mode (0)
            f = data[11];     // filter mode (0)
            i = data[12];     // interlace mode (0)

            if(b!=0 && b!=4 && b!=2 && b!=3 && b!=6) {
                fprintf(stderr, "Image mode %d not supported!\n", b);
                return 0;
            }
            if(a!=8 && (b==2 || b==6)) {
                printf("Bpp %d in mode %d not supported!\n", a);
                return 0;
            }
            if(c!=0) {
                printf("Compression mode %d not supported!\n", c);
                return 0;
            }
            if(f!=0) {
                printf("Filter mode %d not supported!\n", f);
                return 0;
            }
            if(i!=0) {
                printf("Interlace mode %d not supported!\n", i);
                return 0;
            }
            //printf("%dx%d bpp:%d mode:%d comp:%d filter:%d interlace:%d\n",header->width, header->height, a,b,c,f,i);
            header->bpp = a;
            header->mode = b;
            ok = 1;
        }

        free(data);
    }
    return ok;
}
Beispiel #2
0
static bool png_parse_ihdr_fio(FILE **fd,
      struct png_chunk *chunk, struct png_ihdr *ihdr)
{
   if (!png_read_chunk(fd, chunk))
      return false;

   if (chunk->size != 13)
      return false;

   ihdr->width       = dword_be(chunk->data + 0);
   ihdr->height      = dword_be(chunk->data + 4);
   ihdr->depth       = chunk->data[8];
   ihdr->color_type  = chunk->data[9];
   ihdr->compression = chunk->data[10];
   ihdr->filter      = chunk->data[11];
   ihdr->interlace   = chunk->data[12];

   if (ihdr->width == 0 || ihdr->height == 0)
      return false;

   return true;
}
Beispiel #3
0
static bool png_parse_ihdr(FILE *file, struct png_chunk *chunk, struct png_ihdr *ihdr)
{
   unsigned i;
   bool ret = true;
   if (!png_read_chunk(file, chunk))
      return false;

   if (chunk->size != 13)
      GOTO_END_ERROR();

   ihdr->width       = dword_be(chunk->data + 0);
   ihdr->height      = dword_be(chunk->data + 4);
   ihdr->depth       = chunk->data[8];
   ihdr->color_type  = chunk->data[9];
   ihdr->compression = chunk->data[10];
   ihdr->filter      = chunk->data[11];
   ihdr->interlace   = chunk->data[12];

   if (ihdr->width == 0 || ihdr->height == 0)
      GOTO_END_ERROR();

   if (ihdr->color_type == 2 || ihdr->color_type == 4 || ihdr->color_type == 6)
   {
      if (ihdr->depth != 8 && ihdr->depth != 16)
         GOTO_END_ERROR();
   }
   else if (ihdr->color_type == 0)
   {
      static const unsigned valid_bpp[] = { 1, 2, 4, 8, 16 };
      bool correct_bpp = false;
      for (i = 0; i < ARRAY_SIZE(valid_bpp); i++)
      {
         if (valid_bpp[i] == ihdr->depth)
         {
            correct_bpp = true;
            break;
         }
      }

      if (!correct_bpp)
         GOTO_END_ERROR();
   }
   else if (ihdr->color_type == 3)
   {
      static const unsigned valid_bpp[] = { 1, 2, 4, 8 };
      bool correct_bpp = false;
      for (i = 0; i < ARRAY_SIZE(valid_bpp); i++)
      {
         if (valid_bpp[i] == ihdr->depth)
         {
            correct_bpp = true;
            break;
         }
      }

      if (!correct_bpp)
         GOTO_END_ERROR();
   }
   else
      GOTO_END_ERROR();

#ifdef RPNG_TEST
   fprintf(stderr, "IHDR: (%u x %u), bpc = %u, palette = %s, color = %s, alpha = %s, adam7 = %s.\n",
         ihdr->width, ihdr->height,
         ihdr->depth, ihdr->color_type == 3 ? "yes" : "no",
         ihdr->color_type & 2 ? "yes" : "no",
         ihdr->color_type & 4 ? "yes" : "no",
         ihdr->interlace == 1 ? "yes" : "no");
#endif

   if (ihdr->compression != 0)
      GOTO_END_ERROR();

   //if (ihdr->interlace != 0) // No Adam7 supported.
   //   GOTO_END_ERROR();

end:
   png_free_chunk(chunk);
   return ret;
}
Beispiel #4
0
EXPORT int getPNG(const char*sname, int*destwidth, int*destheight, unsigned char**destdata)
{
    char tagid[4];
    int len;
    unsigned char*data;
    unsigned char*imagedata;
    unsigned char*zimagedata=0;
    unsigned long int imagedatalen;
    unsigned long int zimagedatalen=0;
    unsigned char*palette = 0;
    int palettelen = 0;
    unsigned char*alphapalette = 0;
    int alphapalettelen = 0;
    struct png_header header;
    int bypp;
    unsigned char*data2 = 0;
    unsigned char alphacolor[3];
    int hasalphacolor=0;

    FILE *fi;
    unsigned char *scanline;

    if ((fi = fopen(sname, "rb")) == NULL) {
        printf("Couldn't open %s\n", sname);
        return 0;
    }

    if(!png_read_header(fi, &header)) {
        fclose(fi);
        return 0;
    }

    if(header.mode == 3 || header.mode == 0) bypp = 1;
    else if(header.mode == 4) bypp = 2;
    else if(header.mode == 2) bypp = 3;
    else if(header.mode == 6) bypp = 4;
    else {
        printf("ERROR: mode:%d\n", header.mode);
        return 0;
    }

    imagedatalen = bypp * header.width * header.height + 65536;
    imagedata = (unsigned char*)malloc(imagedatalen);

    fseek(fi,8,SEEK_SET);
    while(!feof(fi))
    {
        if(!png_read_chunk(&tagid, &len, &data, fi))
            break;
        if(!strncmp(tagid, "IEND", 4)) {
            break;
        }
        if(!strncmp(tagid, "PLTE", 4)) {
            palette = data;
            palettelen = len/3;
            data = 0; //don't free data
            //printf("%d colors in palette\n", palettelen);
        }
        if(!strncmp(tagid, "tRNS", 4)) {
            if(header.mode == 3) {
                alphapalette = data;
                alphapalettelen = len;
                data = 0; //don't free data
                //printf("found %d alpha colors\n", alphapalettelen);
            } else if(header.mode == 0 || header.mode == 2) {
                int t;
                if(header.mode == 2) {
                    alphacolor[0] = data[1];
                    alphacolor[1] = data[3];
                    alphacolor[2] = data[5];
                } else {
                    alphacolor[0] = alphacolor[1] = alphacolor[2] = data[1];
                }
                hasalphacolor = 1;
            }
        }
        if(!strncmp(tagid, "IDAT", 4)) {
            if(!zimagedata) {
                zimagedatalen = len;
                zimagedata = (unsigned char*)malloc(len);
                memcpy(zimagedata,data,len);
            } else {
                zimagedata = (unsigned char*)realloc(zimagedata, zimagedatalen+len);
                memcpy(&zimagedata[zimagedatalen], data, len);
                zimagedatalen += len;
            }
        }
        if(!strncmp(tagid, "tEXt", 4)) {
            /*int t;
            printf("Image Text: ");
            for(t=0;t<len;t++) {
            if(data[t]>=32 && data[t]<128)
                printf("%c", data[t]);
            else
                printf("?");
            }
            printf("\n");*/
        }
        if(data) {
            free(data);
            data=0;
        }
    }

    if(!zimagedata || uncompress(imagedata, &imagedatalen, zimagedata, zimagedatalen) != Z_OK) {
        printf("Couldn't uncompress %s!\n", sname);
        if(zimagedata)
            free(zimagedata);
        return 0;
    }
    free(zimagedata);
    fclose(fi);

    *destwidth = header.width;
    *destheight = header.height;

    data2 = (unsigned char*)malloc(header.width*header.height*4);

    if(header.mode == 4)
    {
        int i,s=0;
        int x,y;
        int pos=0;
        unsigned char* old= (unsigned char*)malloc(header.width*2);
        memset(old, 0, header.width*2);
        *destdata = data2;
        for(y=0; y<header.height; y++) {
            int mode = imagedata[pos++]; //filter mode
            unsigned char*src;
            unsigned char*dest;
            int x;
            dest = &data2[(y*header.width)*4];

            if(header.bpp == 8) {
                /* one byte per pixel */
                src = &imagedata[pos];
                pos+=header.width*2;
            } else {
                /* not implemented yet */
                fprintf(stderr, "ERROR: mode=4 bpp:%d\n", header.bpp);
                free(data2);
                return 0;
            }

            applyfilter2(mode, src, old, dest, header.width);
            memcpy(old, dest, header.width*2);

            for(x=header.width-1; x>=0; x--) {
                unsigned char gray = dest[x*2+0];
                unsigned char alpha = dest[x*2+1];
                dest[x*4+0] = alpha;
                dest[x*4+1] = gray;
                dest[x*4+2] = gray;
                dest[x*4+3] = gray;
            }
        }
        free(old);
        free(imagedata);
    } else if(header.mode == 6 || header.mode == 2) {
        int i,s=0;
        int x,y;
        int pos=0;
        *destdata = data2;

        unsigned char* firstline = malloc(header.width*4);
        memset(firstline,0,header.width*4);
        for(y=0; y<header.height; y++) {
            int mode = imagedata[pos++]; //filter mode
            unsigned char*src;
            unsigned char*dest;
            unsigned char*old;
            dest = &data2[(y*header.width)*4];

            if(header.bpp == 8)
            {
                /* one byte per pixel */
                src = &imagedata[pos];
                pos+=header.width*(header.mode==6?4:3);
            } else {
                /* not implemented yet */
                fprintf(stderr, "ERROR: bpp:%d\n", header.bpp);
                free(data2);
                return 0;
            }

            if(!y) {
                old = firstline;
            } else {
                old = &data2[(y-1)*header.width*4];
            }
            if(header.mode == 6) {
                applyfilter4(mode, src, old, dest, header.width);
            } else { // header.mode = 2
                applyfilter3(mode, src, old, dest, header.width);
                /* replace alpha color */
                if(hasalphacolor) {
                    int x;
                    for(x=0; x<header.width; x++) {
                        if(dest[x*4+1] == alphacolor[0] &&
                                dest[x*4+2] == alphacolor[1] &&
                                dest[x*4+3] == alphacolor[2]) {
                            *(u32*)&dest[x*4] = 0;
                        }
                    }
                }
            }
        }
        free(firstline);
        free(imagedata);
    } else if(header.mode == 0 || header.mode == 3) {
        COL*rgba = 0;
        unsigned char*tmpline = (unsigned char*)malloc(header.width+1);
        unsigned char*destline = (unsigned char*)malloc(header.width+1);
        int i,x,y;
        int pos=0;

        *destdata = data2;

        if(header.mode == 0) { // grayscale palette
            int mult = (0x1ff>>header.bpp);
            palettelen = 1<<header.bpp;
            rgba = (COL*)malloc(palettelen*sizeof(COL));
            for(i=0; i<palettelen; i++) {
                rgba[i].a = 255;
                rgba[i].r = i*mult;
                rgba[i].g = i*mult;
                rgba[i].b = i*mult;
                if(hasalphacolor) {
                    if(rgba[i].r == alphacolor[0])
                        rgba[i].a = 0;
                }
            }
        } else {