/* * in_pcx.cpp: loads PCX images * modified by pts@fazekas.hu at Fri Apr 12 22:16:08 CEST 2002 * -- Fri Apr 12 23:54:57 CEST 2002 * * xvpcx.c - load routine for PCX format pictures * * LoadPCX(fname, pinfo) - loads a PCX file */ /**** pts ****/ #include "config2.h" #include "image.hpp" #if USE_IN_PCX #include "error.hpp" #include "gensio.hpp" #include /* Imp: palette handling etc. according to PCX_VER, see decode.c */ #define dimen Image::Sampled::dimen_t #define pcxError(bname,conststr) Error::sev(Error::WARNING) << "PCX: " conststr << (Error*)0 #define WaitCursor() #define xvbzero(p,len) memset(p, '\0', len) #define FatalError(conststr) Error::sev(Error::EERROR) << "PCX: " conststr << (Error*)0 #define return_pcxError(bname, conststr) Error::sev(Error::EERROR) << "PCX: " conststr << (Error*)0 #define byte unsigned char #define PCX_SIZE_T slen_t #define malloc_byte(n) new byte[n] #define PCX_FREE(p) delete [] (p) /* the following list give indicies into saveColors[] array in xvdir.c */ #define F_FULLCOLOR 0 #define F_GREYSCALE 1 #define F_BWDITHER 2 /* values 'picType' can take */ #define PIC8 8 #define PIC24 24 #define xv_fopen(filename,read_mode) fopen(filename,"rb") #define BaseName(x) ((char*)0) #define PARM(parm) parm /* info structure filled in by the LoadXXX() image reading routines */ #ifndef USE_PCX_DEBUG_MESSAGES #define USE_PCX_DEBUG_MESSAGES 0 #endif typedef struct { byte *pic; /* image data */ dimen w, h; /* pic size */ #if 0 /**** pts ****/ byte r[256],g[256],b[256]; #else /* byte pal[3*256]; */ byte *pal; # define PAL_R(pinfo,idx) (pinfo)->pal[3*(idx)] # define PAL_G(pinfo,idx) (pinfo)->pal[3*(idx)+1] # define PAL_B(pinfo,idx) (pinfo)->pal[3*(idx)+2] #endif /* colormap, if PIC8 */ #if 0 /**** pts ****/ int colType; /* def. Color type to save in */ int type; /* PIC8 or PIC24 */ int normw, normh; /* 'normal size' of image file (normally eq. w,h, except when doing 'quick' load for icons */ int frmType; /* def. Format type to save in */ char fullInfo[128]; /* Format: field in info box */ char shrtInfo[128]; /* short format info */ char *comment; /* comment text */ int numpages; /* # of page files, if >1 */ char pagebname[64]; /* basename of page files */ #endif } PICINFO; /* #include "copyright.h" */ /* * the following code has been derived from code written by * Eckhard Rueggeberg (Eckhard.Rueggeberg@ts.go.dlr.de) */ /* #include "xv.h" */ /* offsets into PCX header */ #define PCX_ID 0 #define PCX_VER 1 #define PCX_ENC 2 #define PCX_BPP 3 #define PCX_XMINL 4 #define PCX_XMINH 5 #define PCX_YMINL 6 #define PCX_YMINH 7 #define PCX_XMAXL 8 #define PCX_XMAXH 9 #define PCX_YMAXL 10 #define PCX_YMAXH 11 /* hres (12,13) and vres (14,15) not used */ #define PCX_CMAP 16 /* start of 16*3 colormap data */ #define PCX_PLANES 65 #define PCX_BPRL 66 #define PCX_BPRH 67 #define PCX_MAPSTART 0x0c /* Start of appended colormap */ static int pcxLoadImage8 PARM((char *, FILE *, PICINFO *, byte *)); static int pcxLoadImage24 PARM((char *, FILE *, PICINFO *, byte *)); static void pcxLoadRaster PARM((FILE *, byte *, int, byte *, dimen, dimen)); #if 0 /**** pts ****/ static int pcxError PARM((char *, char *)); #endif static PCX_SIZE_T multiply_check(PCX_SIZE_T a, PCX_SIZE_T b) { const PCX_SIZE_T result = a * b; /* Check for overflow. Works only if everything is unsigned. */ if (result / a != b) FatalError("Image too large."); return result; } static PCX_SIZE_T multiply_check(PCX_SIZE_T a, PCX_SIZE_T b, PCX_SIZE_T c) { return multiply_check(multiply_check(a, b), c); } /*******************************************/ static Image::Sampled *LoadPCX #if 0 /**** pts ****/ ___((char *fname, PICINFO *pinfo), (fname, pinfo), (char *fname; PICINFO *pinfo;)) #else ___((FILE *fp, PICINFO *pinfo), (fname, pinfo), (char *fname; PICINFO *pinfo;)) #endif /*******************************************/ { Image::Sampled *ret=(Image::Sampled*)NULLP; byte hdr[128]; #if 0 /**** pts ****/ long filesize; char *bname; FILE *fp; char *errstr; byte *image; int gray; #endif int i, colors, fullcolor; pinfo->pic = (byte *) NULL; pinfo->pal = (byte *) NULL; #if 0 /**** pts ****/ pinfo->type = PIC8; pinfo->comment = (char *) NULL; bname = BaseName(fname); /* open the stream */ fp = xv_fopen(fname,"r"); if (!fp) return_pcxError(bname, "unable to open file"); #endif #if 0 /**** pts ****/ /* figure out the file size */ fseek(fp, 0L, 2); filesize = ftell(fp); fseek(fp, 0L, 0); #endif /* read the PCX header */ if (fread(hdr, (PCX_SIZE_T) 128, (PCX_SIZE_T) 1, fp) != 1 || ferror(fp) || feof(fp)) { /* fclose(fp); */ return_pcxError(bname, "EOF reached in PCX header.\n"); } if (hdr[PCX_ID] != 0x0a || hdr[PCX_VER] > 5) { /* fclose(fp); */ return_pcxError(bname,"unrecognized magic number"); } pinfo->w = (hdr[PCX_XMAXL] + ((dimen) hdr[PCX_XMAXH]<<8)) - (hdr[PCX_XMINL] + ((dimen) hdr[PCX_XMINH]<<8)); pinfo->h = (hdr[PCX_YMAXL] + ((dimen) hdr[PCX_YMAXH]<<8)) - (hdr[PCX_YMINL] + ((dimen) hdr[PCX_YMINH]<<8)); pinfo->w++; pinfo->h++; colors = 1 << (hdr[PCX_BPP] * hdr[PCX_PLANES]); fullcolor = (hdr[PCX_BPP] == 8 && hdr[PCX_PLANES] == 3); #if USE_PCX_DEBUG_MESSAGES fprintf(stderr,"PCX: %dx%d image, version=%d, encoding=%d\n", pinfo->w, pinfo->h, hdr[PCX_VER], hdr[PCX_ENC]); fprintf(stderr," BitsPerPixel=%d, planes=%d, BytePerRow=%d, colors=%d\n", hdr[PCX_BPP], hdr[PCX_PLANES], hdr[PCX_BPRL] + ((dimen) hdr[PCX_BPRH]<<8), colors); #endif if (colors>256 && !fullcolor) { /* fclose(fp); */ return_pcxError(bname,"No more than 256 colors allowed in PCX file."); } if (hdr[PCX_ENC] != 1) { /* fclose(fp); */ return_pcxError(bname,"Unsupported PCX encoding format."); } /* load the image, the image function fills in pinfo->pic */ if (!fullcolor) { Image::Indexed *img=new Image::Indexed(pinfo->w, pinfo->h, colors, 8); pinfo->pal=(byte*)img->getHeadp(); ASSERT_SIDE(pcxLoadImage8((char*)NULLP/*bname*/, fp, pinfo, hdr)); memcpy(img->getRowbeg(), pinfo->pic, multiply_check(pinfo->w, pinfo->h)); ret=img; } else { Image::RGB *img=new Image::RGB(pinfo->w, pinfo->h, 8); ASSERT_SIDE(pcxLoadImage24((char*)NULLP/*bname*/, fp, pinfo, hdr)); memcpy(img->getRowbeg(), pinfo->pic, multiply_check(pinfo->w, pinfo->h, 3)); ret=img; } PCX_FREE(pinfo->pic); pinfo->pic=(byte*)NULLP; if (ferror(fp) | feof(fp)) /* just a warning */ pcxError(bname, "PCX file appears to be truncated."); if (colors>16 && !fullcolor) { /* handle trailing colormap */ while (1) { i=MACRO_GETC(fp); if (i==PCX_MAPSTART || i==EOF) break; } #if 0 /**** pts ****/ for (i=0; ipal, 1, colors*3, fp) != colors * 3 + 0U || ferror(fp) || feof(fp)) { pcxError(bname,"Error reading PCX colormap. Using grayscale."); for (i=0; i<256; i++) PAL_R(pinfo,i) = PAL_G(pinfo,i) = PAL_B(pinfo,i) = i; } } else if (colors<=16) { /* internal colormap */ #if 0 /**** pts ****/ for (i=0; ipal, hdr+PCX_CMAP, colors*3); #endif } if (colors == 2) { /* b&w */ #if 0 /**** pts ****/ if (MONO(PAL_R(pinfo,0), PAL_G(pinfo,0), PAL_B(pinfo,0)) == MONO(PAL_R(pinfo,1), PAL_G(pinfo,1), PAL_B(pinfo,1))) { #else if (PAL_R(pinfo,0)==PAL_R(pinfo,1) && PAL_G(pinfo,0)==PAL_G(pinfo,1) && PAL_B(pinfo,0)==PAL_B(pinfo,1)) { #endif /* create cmap */ PAL_R(pinfo,0) = PAL_G(pinfo,0) = PAL_B(pinfo,0) = 255; PAL_R(pinfo,1) = PAL_G(pinfo,1) = PAL_B(pinfo,1) = 0; #if USE_PCX_DEBUG_MESSAGES fprintf(stderr,"PCX: no cmap: using 0=white,1=black\n"); #endif } } /* fclose(fp); */ /* finally, convert into XV internal format */ #if 0 /**** pts ****/ pinfo->type = fullcolor ? PIC24 : PIC8; pinfo->frmType = -1; /* no default format to save in */ #endif #if 0 /**** pts ****/ /* check for grayscaleitude */ gray = 0; if (!fullcolor) { for (i=0; i 2 || (colors==2 && !gray)) { /* grayscale or PseudoColor */ pinfo->colType = (gray) ? F_GREYSCALE : F_FULLCOLOR; #if 0 /**** pts ****/ sprintf(pinfo->fullInfo, "%s PCX, %d plane%s, %d bit%s per pixel. (%ld bytes)", (gray) ? "Greyscale" : "Color", hdr[PCX_PLANES], (hdr[PCX_PLANES]==1) ? "" : "s", hdr[PCX_BPP], (hdr[PCX_BPP]==1) ? "" : "s", filesize); #endif } else { pinfo->colType = F_BWDITHER; #if 0 /**** pts ****/ sprintf(pinfo->fullInfo, "B&W PCX. (%ld bytes)", filesize); #endif } #if 0 /**** pts ****/ sprintf(pinfo->shrtInfo, "%dx%d PCX.", pinfo->w, pinfo->h); pinfo->normw = pinfo->w; pinfo->normh = pinfo->h; #endif #endif return ret; } /*****************************/ static int pcxLoadImage8 ___((char *fname, FILE *fp, PICINFO *pinfo, byte *hdr), (fname, fp, pinfo, hdr), (char *fname; FILE *fp; PICINFO *pinfo; byte *hdr;)) { /* load an image with at most 8 bits per pixel */ (void)fname; /**** pts ****/ byte *image; image = (byte *) malloc_byte(multiply_check(pinfo->h, pinfo->w)); if (!image) FatalError("Can't alloc 'image' in pcxLoadImage8()"); xvbzero((char *) image, multiply_check(pinfo->h, pinfo->w)); switch (hdr[PCX_BPP]) { case 1: case 2: case 4: case 8: pcxLoadRaster(fp, image, hdr[PCX_BPP], hdr, pinfo->w, pinfo->h); break; default: PCX_FREE(image); return_pcxError(fname, "Unsupported # of bits per plane."); } pinfo->pic = image; return 1; } /*****************************/ static int pcxLoadImage24 ___((char *fname, FILE *fp, PICINFO *pinfo, byte *hdr), (fname, fp, pinfo, hdr), (char *fname; FILE *fp; PICINFO *pinfo; byte *hdr;)) { byte *pix, *pic24; int c; unsigned i, j, w, h, cnt, planes, bperlin, nbytes; #if 0 /***** pts ****/ int maxv; /* ImageMagick does not have one */ byte scale[256]; #endif (void)fname; /**** pts ****/ w = pinfo->w; h = pinfo->h; planes = (unsigned) hdr[PCX_PLANES]; bperlin = hdr[PCX_BPRL] + ((dimen) hdr[PCX_BPRH]<<8); /* allocate 24-bit image */ const PCX_SIZE_T alloced = multiply_check(w, h, planes); const PCX_SIZE_T w_planes = multiply_check(w, planes); pic24 = (byte *) malloc_byte(alloced); if (!pic24) FatalError("couldn't malloc 'pic24'"); /* This may still fail with a segfault for large values of alloced, even * if malloc_byte has succeeded. */ xvbzero((char *) pic24, alloced); fprintf(stderr, "AAA3\n"); #if 0 /**** pts ****/ maxv = 0; #endif pix = pinfo->pic = pic24; i = 0; /* planes, in this while loop */ j = 0; /* bytes per line, in this while loop */ nbytes = multiply_check(bperlin, h, planes); while (nbytes > 0 && (c = MACRO_GETC(fp)) != EOF) { if (c>=0xC0) { /* have a rep. count */ cnt = c & 0x3F; c = MACRO_GETC(fp); if (c == EOF) { MACRO_GETC(fp); break; } } else cnt = 1; if (cnt > nbytes) FatalError("Repeat count too large."); #if 0 /**** pts ****/ if (c > maxv) maxv = c; #endif while (cnt-- > 0) { if (j < w) { *pix = c; pix += planes; } j++; nbytes--; if (j == bperlin) { j = 0; if (++i < planes) { pix -= w_planes-1; /* next plane on this line */ } else { pix -= planes-1; /* start of next line, first plane */ i = 0; } } } } if (nbytes != 0) pcxError(0, "Image data truncated."); #if 0 /**** pts ****/ /* scale all RGB to range 0-255, if they aren't */ if (maxv<255) { for (i=0; i<=maxv; i++) scale[i] = (i * 255) / maxv; for (i=0, pix=pic24; i=0xC0) { /* have a rep. count */ cnt = b & 0x3F; b = MACRO_GETC(fp); if (b == EOF) { MACRO_GETC(fp); return; } } else cnt = 1; for (i=0; i>6)&3)*pmask; *image++|=((b>>4)&3)*pmask; *image++|=((b>>2)&3)*pmask; *image++|=((b )&3)*pmask; break; case 4: /**** pts ****/ *image++|=((b>>4)&15)*pmask; *image++|=((b )&15)*pmask; break; default: *image++=(byte)b; } bcnt++; if (bcnt == bperlin) { /* end of a line reached */ bcnt = 0; if (--pleft==0) { /* moved to next row */ pleft=hdr[PCX_PLANES]; pmask=1; image -= pad; oldimage = image; row++; if (row >= h) return; /* done */ } else { /* next plane, same row */ image = oldimage; pmask<<=depth; } } } } } #if 0 /**** pts ****/ /*******************************************/ static int pcxError(fname,st) char *fname, *st; { SetISTR(ISTR_WARNING,"%s: %s", fname, st); return 0; } #endif static Image::Sampled *in_pcx_reader(Image::Loader::UFD *ufd, SimBuffer::Flat const&) { PICINFO pinfo_; return LoadPCX(((Filter::UngetFILED*)ufd)->getFILE(/*seekable:*/false), &pinfo_); } static Image::Loader::reader_t in_pcx_checker(char buf[Image::Loader::MAGIC_LEN], char [Image::Loader::MAGIC_LEN], SimBuffer::Flat const&, Image::Loader::UFD*) { return buf[PCX_ID]==0x0a && (unsigned char)buf[PCX_VER]<=5 && buf[PCX_ENC]==1 && buf[PCX_BPP]<=8 ? in_pcx_reader : 0; } #else #define in_pcx_checker (Image::Loader::checker_t)NULLP #endif /* USE_IN_PCX */ Image::Loader in_pcx_loader = { "PCX", in_pcx_checker, 0 }; /* __END__ */