/***************************************************************************** * Reads one image in. * ****************************************************************************** * (C) Gershon Elber, Technion, Israel Institute of Technology * ****************************************************************************** * Written by: Gershon Elber Ver 1.0, Dec. 1998 * *****************************************************************************/ #include #include "irit_sm.h" #include "misc_loc.h" #ifdef HAVE_URT_RLE #define NO_DECLARE_MALLOC /* For rle.h */ #define USE_PROTOTYPES #define USE_STDLIB_H #include #include #endif /* HAVE_URT_RLE */ #ifdef HAVE_GIF_LIB #include "gif_lib.h" #endif /* HAVE_GIF_LIB */ #ifdef HAVE_PNG_LIB #include "png.h" #ifndef png_jmpbuf # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) #endif #endif /* HAVE_PNG_LIB */ #ifdef __WINNT__ #include #include #endif /* __WINNT__ */ typedef struct LoadedImagesStruct { struct LoadedImagesStruct *Pnext; char *FileName; int MaxX, MaxY; ByteType *Data; } LoadedImagesStruct; STATIC_DATA LoadedImagesStruct *GlblLoadedImagesList = NULL; static ByteType *PPMReadImage(char *File, int *MaxX, int *MaxY); static ByteType *RLEReadImage(char *File, int *MaxX, int *MaxY); static ByteType *GIFReadImage(char *ImageFileName, int *MaxX, int *MaxY); static ByteType *PNGReadImage(char *ImageFileName, int *MaxX, int *MaxY); /***************************************************************************** * DESCRIPTION: M * Reads one image in from a file named ImageFileName. The image is M * returned as a vector of RGBRGB... of size (MaxX+1) * (MaxY+1) * 3. M * * * PARAMETERS: M * ImageFileName: Name of image to read. M * MaxX: Maximum X of read image is saved here. M * MaxY: Maximum Y of read image is saved here. M * * * RETURN VALUE: M * IrtImgPixelStruct *: A vector of RGBRGB... of size M * (MaxX+1) * (MaxY+1) * 3 or NULL if failed. M * * * SEE ALSO: M * IrtImgReadImage2 M * * * KEYWORDS: M * IrtImgReadImage M *****************************************************************************/ IrtImgPixelStruct *IrtImgReadImage(char *ImageFileName, int *MaxX, int *MaxY) { char *Type; if (ImageFileName == NULL) { IRIT_FATAL_ERROR("Empty image file name to write to."); return NULL; } if ((Type = strrchr(ImageFileName, '.')) == NULL) Type = ""; if (stricmp(Type, ".Z") == 0) { Type--; while (Type != ImageFileName && *Type != '.') Type--; } if (stricmp(Type, ".ppm") == 0) { return (IrtImgPixelStruct *) PPMReadImage(ImageFileName, MaxX, MaxY); } else if (stricmp(Type, ".rle") == 0 || stricmp(Type, ".rle.Z") == 0) { return (IrtImgPixelStruct *) RLEReadImage(ImageFileName, MaxX, MaxY); } else if (stricmp(Type, ".gif") == 0) { return (IrtImgPixelStruct *) GIFReadImage(ImageFileName, MaxX, MaxY); } else if (stricmp(Type, ".png") == 0) { return (IrtImgPixelStruct *) PNGReadImage(ImageFileName, MaxX, MaxY); } else { fprintf(stderr, IRIT_EXP_STR("Texture file \"%s\" must be image of type 'rle', 'ppm', 'gif' or 'png'\n"), ImageFileName); return NULL; } } /***************************************************************************** * DESCRIPTION: M * Same as IrtImgReadImage2 but if a name of an image repeats itself, the M * image is read only once. M * * * PARAMETERS: M * ImageFileName: Name of image to read. M * MaxX: Maximum X of read image is saved here. M * MaxY: Maximum Y of read image is saved here. M * * * RETURN VALUE: M * IrtImgPixelStruct *: A vector of RGBRGB... of size M * (MaxX+1) * (MaxY+1) * 3 or NULL if failed. M * * * SEE ALSO: M * IrtImgReadImage, IrtImgReadClrCache M * * * KEYWORDS: M * IrtImgReadImage2 M *****************************************************************************/ IrtImgPixelStruct *IrtImgReadImage2(char *ImageFileName, int *MaxX, int *MaxY) { LoadedImagesStruct *LoadedImage; IrtImgPixelStruct *Data; /* Search if we already loaded this image. */ for (LoadedImage = GlblLoadedImagesList; LoadedImage != NULL; LoadedImage = LoadedImage -> Pnext) { if (strcmp(ImageFileName, LoadedImage -> FileName) == 0) { *MaxX = LoadedImage -> MaxX; *MaxY = LoadedImage -> MaxY; return (IrtImgPixelStruct *) LoadedImage -> Data; } } if (Data = IrtImgReadImage(ImageFileName, MaxX, MaxY)) { /* Add it to global list of loaded images. */ LoadedImage = (LoadedImagesStruct *) IritMalloc(sizeof(LoadedImagesStruct)); LoadedImage -> FileName = IritStrdup(ImageFileName); LoadedImage -> MaxX = *MaxX; LoadedImage -> MaxY = *MaxY; LoadedImage -> Data = (ByteType *) Data; LoadedImage -> Pnext = GlblLoadedImagesList; GlblLoadedImagesList = LoadedImage; } return Data; } /***************************************************************************** * DESCRIPTION: M * Clears the cache of read images. M * * * PARAMETERS: M * None M * * * RETURN VALUE: M * void M * * * SEE ALSO: M * IrtImgReadImage2 M * * * KEYWORDS: M * IrtImgReadClrCache M *****************************************************************************/ void IrtImgReadClrCache(void) { while (GlblLoadedImagesList != NULL) { LoadedImagesStruct *LoadedImage = GlblLoadedImagesList; GlblLoadedImagesList = GlblLoadedImagesList -> Pnext; IritFree(LoadedImage -> FileName); IritFree(LoadedImage -> Data); IritFree(LoadedImage); } } /***************************************************************************** * DESCRIPTION: * * Loads image file in PPM format. * * * * PARAMETERS: * * ImageFileName: Name of PPM image to read. * * MaxX: Maximum X of read image is saved here. * * MaxY: Maximum Y of read image is saved here. * * * * RETURN VALUE: * * ByteType *: Pointer to dynamicaly created image, NULL if non. * *****************************************************************************/ static ByteType *PPMReadImage(char *ImageFileName, int *MaxX, int *MaxY) { int x, y, Width, Height; char Line[LINE_LEN_LONG], Line2[LINE_LEN_LONG]; ByteType *Data; FILE *PPMLoad; #ifdef __WINNT__ if ((PPMLoad = fopen(ImageFileName, "rb")) == NULL) { #else if ((PPMLoad = fopen(ImageFileName, "r")) == NULL) { #endif /* __WINNT__ */ fprintf(stderr, IRIT_EXP_STR("Failed to read PPM file \"%s\"\n"), ImageFileName); return NULL; } fgets(Line2, LINE_LEN_LONG - 1, PPMLoad); if (strncmp(Line2, "P3", 2) != 0 && strncmp(Line2, "P6", 2) != 0) { fprintf(stderr, IRIT_EXP_STR("P3 or P6 expected, found \"%s\"\n"), Line2); return NULL; } fgets(Line, LINE_LEN_LONG - 1, PPMLoad); while (Line[0] == '#') fgets(Line, LINE_LEN_LONG - 1, PPMLoad); sscanf(Line, "%d %d", &Width, &Height); if (Width < 0 || Width > 100000 || Height < 0 || Height > 100000) { fprintf(stderr, IRIT_EXP_STR("Unrealistic image size %d by %d\n"), Width, Height); return NULL; } /* Get the "255" line. */ fgets(Line, LINE_LEN_LONG - 1, PPMLoad); *MaxX = Width - 1; *MaxY = Height - 1; /* Allocate the image. */ Data = IritMalloc(3 * Width * Height); if (strncmp(Line2, "P6", 2) == 0) { int LineSize = Width * 3; fread(Data, 3 * Width * Height, 1, PPMLoad); /* Swap the lines so YMin is YMax. */ for (y = 0; y <= (Height >> 1); y++) { ByteType *p1 = &Data[(*MaxY - y) * LineSize], *p2 = &Data[y * LineSize]; for (x = LineSize; x > 0; x--, p1++, p2++) { SWAP(ByteType, *p1, *p2); } } } else if (strncmp(Line2, "P3", 2) == 0) { int LineSize = Width * 3; for (y = 0; y < Height; y++) { ByteType *p = &Data[(*MaxY - y) * LineSize]; for (x = 0; x < Width; x++) { int r, g, b; fscanf(PPMLoad, "%d %d %d", &r, &g, &b); *p++ = (ByteType) r; *p++ = (ByteType) g; *p++ = (ByteType) b; } } } fclose(PPMLoad); return Data; } /***************************************************************************** * DESCRIPTION: * * Loads image file in RLE format. * * * * PARAMETERS: * * ImageFileName: Name of RLE image to read. * * MaxX: Maximum X of read image is saved here. * * MaxY: Maximum Y of read image is saved here. * * * * RETURN VALUE: * * ByteType *: Pointer to dynamicaly created image, NULL if non. * *****************************************************************************/ static ByteType *RLEReadImage(char *ImageFileName, int *MaxX, int *MaxY) { #ifdef HAVE_URT_RLE rle_hdr Header; rle_pixel **Rows; int Error, x, y; ByteType *Data, *p; Header = *rle_hdr_init(NULL); Header.rle_file = rle_open_f_noexit("RleLoadImage", ImageFileName, "r"); if (!Header.rle_file) { fprintf(stderr, IRIT_EXP_STR("Failed to read RLE file \"%s\"\n"), ImageFileName); return NULL; } if (Error = rle_get_setup(&Header)) { rle_get_error(Error, "RleLoadImage", ImageFileName); return NULL; } rle_row_alloc(&Header, &Rows); *MaxX = Header.xmax - Header.xmin; *MaxY = Header.ymax - Header.ymin; Data = p = IritMalloc(3 * (*MaxX + 1) * (*MaxY + 1)); for (y = 0; y <= *MaxY; y++) { rle_getrow(&Header, Rows); for (x = 0; x <= *MaxX; x++) { *p++ = Rows[RLE_RED][x]; *p++ = Rows[RLE_GREEN][x]; *p++ = Rows[RLE_BLUE][x]; } } rle_close_f(Header.rle_file); return Data; #else fprintf(stderr, IRIT_EXP_STR("Utah raster tool kit is not supported\n")); return NULL; /* Silent the compiler's warning. */ #endif /* HAVE_URT_RLE */ } /***************************************************************************** * DESCRIPTION: * * Loads image file in GIF format. * * * * PARAMETERS: * * ImageFileName: Name of GIF image to read. * * MaxX: Maximum X of read image is saved here. * * MaxY: Maximum Y of read image is saved here. * * * * RETURN VALUE: * * ByteType *: Pointer to dynamicaly created image, NULL if non. * *****************************************************************************/ static ByteType *GIFReadImage(char *ImageFileName, int *MaxX, int *MaxY) { #ifdef HAVE_GIF_LIB GifFileType *GifFileIn; ByteType *Data, *p, *Line; GifRecordType RecordType; if ((GifFileIn = DGifOpenFileName(ImageFileName)) == NULL) return NULL; /* Scan the content of the GIF file and load the image(s) in: */ do { int i, j, l, ExtCode; GifByteType *Extension; ColorMapObject *ColorMap; GifColorType *ColorMapEntry; if (DGifGetRecordType(GifFileIn, &RecordType) == GIF_ERROR) return NULL; switch (RecordType) { case IMAGE_DESC_RECORD_TYPE: if (DGifGetImageDesc(GifFileIn) == GIF_ERROR) return NULL; ColorMap = (GifFileIn -> Image.ColorMap ? GifFileIn -> Image.ColorMap : GifFileIn -> SColorMap); *MaxX = GifFileIn -> Image.Width - 1; *MaxY = GifFileIn -> Image.Height - 1; /* Allocate the image (padding it as well). */ Data = IritMalloc(3 * (GifFileIn -> Image.Width + 3) * (GifFileIn -> Image.Height + 3)); Line = IritMalloc(GifFileIn -> Image.Width + 3); /* Read the image itself: */ if (GifFileIn->Image.Interlace) { /* Interlaced images - offsets and jumps. */ static int InterlacedOffset[] = { 0, 4, 2, 1 }, InterlacedJumps[] = { 8, 8, 4, 2 }; /* Need to perform 4 passes on the images: */ for (i = 0; i < 4; i++) { for (l = InterlacedOffset[i]; l < GifFileIn -> Image.Height; l += InterlacedJumps[i]) { if (DGifGetLine(GifFileIn, Line, GifFileIn -> Image.Width) == GIF_ERROR) { IritFree(Data); return NULL; } p = &Data[(GifFileIn -> Image.Height - l - 1) * GifFileIn -> Image.Width * 3]; for (j = 0; j < GifFileIn -> Image.Width; j++) { ColorMapEntry = &ColorMap -> Colors[Line[j]]; *p++ = ColorMapEntry -> Red; *p++ = ColorMapEntry -> Green; *p++ = ColorMapEntry -> Blue; } } } } else { for (i = 0; i < GifFileIn -> Image.Height; i++) { if (DGifGetLine(GifFileIn, Line, GifFileIn -> Image.Width) == GIF_ERROR) { IritFree(Data); return NULL; } p = &Data[(GifFileIn -> Image.Height - i - 1) * GifFileIn -> Image.Width * 3]; for (j = 0; j < GifFileIn -> Image.Width; j++) { ColorMapEntry = &ColorMap -> Colors[Line[j]]; *p++ = ColorMapEntry -> Red; *p++ = ColorMapEntry -> Green; *p++ = ColorMapEntry -> Blue; } } } IritFree(Line); break; case EXTENSION_RECORD_TYPE: /* Skip any extension blocks in file: */ DGifGetExtension(GifFileIn, &ExtCode, &Extension); while (Extension != NULL) DGifGetExtensionNext(GifFileIn, &Extension); break; case TERMINATE_RECORD_TYPE: break; default: /* Should be traps by DGifGetRecordType. */ break; } } while (RecordType != TERMINATE_RECORD_TYPE); DGifCloseFile(GifFileIn); return Data; #else fprintf(stderr, IRIT_EXP_STR("GifLib tool kit is not supported\n")); return NULL; /* Silent the compiler's warning. */ #endif /* HAVE_GIF_LIB */ } /***************************************************************************** * DESCRIPTION: * * Loads image file in PNG format. Based on the example from libpng. * * * * PARAMETERS: * * ImageFileName: Name of PNG image to read. * * MaxX: Maximum X of read image is saved here. * * MaxY: Maximum Y of read image is saved here. * * * * RETURN VALUE: * * ByteType *: Pointer to dynamicaly created image, NULL if non. * *****************************************************************************/ static ByteType *PNGReadImage(char *ImageFileName, int *MaxX, int *MaxY) { #ifdef HAVE_PNG_LIB int y, RowSize; ByteType *Data; png_structp PngPtr; png_infop InfoPtr; unsigned int SigRead = 0; FILE *fp; if ((fp = fopen(ImageFileName, "rb")) == NULL) return NULL; PngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, png_voidp_NULL, png_error_ptr_NULL, png_error_ptr_NULL); if (PngPtr == NULL) { fclose(fp); return NULL; } /* Allocate/initialize the memory for image information. REQUIRED. */ InfoPtr = png_create_info_struct(PngPtr); if (InfoPtr == NULL) { fclose(fp); png_destroy_read_struct(&PngPtr, png_infopp_NULL, png_infopp_NULL); return NULL; } if (setjmp(png_jmpbuf(PngPtr))) { /* Free all of the memory associated with the PngPtr and InfoPtr */ png_destroy_read_struct(&PngPtr, &InfoPtr, png_infopp_NULL); fclose(fp); /* If we get here, we had a problem reading the file */ return NULL; } png_init_io(PngPtr, fp); /* If we have already read some of the signature */ png_set_sig_bytes(PngPtr, SigRead); png_read_png(PngPtr, InfoPtr, PNG_TRANSFORM_STRIP_ALPHA | PNG_TRANSFORM_EXPAND, png_voidp_NULL); *MaxX = InfoPtr -> width - 1; *MaxY = InfoPtr -> height - 1; RowSize = InfoPtr -> rowbytes; Data = IritMalloc(RowSize * (*MaxY + 1)); for (y = 0; y <= *MaxY; y++) { GEN_COPY(&Data[RowSize * y], InfoPtr -> row_pointers[*MaxY - y], RowSize); } /* clean up after the read, and free any memory allocated - REQUIRED */ png_destroy_read_struct(&PngPtr, &InfoPtr, png_infopp_NULL); /* close the file */ fclose(fp); /* that's it */ return Data; #else fprintf(stderr, IRIT_EXP_STR("LibPng tool kit is not supported\n")); return NULL; /* Silent the compiler's warning. */ #endif /* HAVE_PNG_LIB */ } /***************************************************************************** * DESCRIPTION: M * Parses the string of the "ptexture" attribute M * * * PARAMETERS: M * PTexture: The string of the "ptexture" attribute. M * FName: The texture file name will be placed here. M * Scale: The scaling vector in XYZ or just XY if Z = IRIT_INFNTY. M * Flip: If Image flipping was requested. M * * * RETURN VALUE: M * int: TRUE if parsed succesfully, FALSE otherwise. M * * * KEYWORDS: M * IrtImgParsePTextureString M *****************************************************************************/ int IrtImgParsePTextureString(char *PTexture, char *FName, RealType *Scale, int *Flip) { char *p; Scale[0] = Scale[1] = 1.0; Scale[2] = IRIT_INFNTY; *Flip = FALSE; if (PTexture == NULL) return FALSE; strncpy(FName, PTexture, LINE_LEN_LONG - 1); if ((p = strchr(FName, ',')) != NULL) { char *q; float Sx, Sy, Sz; *p++ = 0; /* Mark the end of the regular string. */ if ((q = strchr(p, 'F')) != NULL) *Flip = TRUE; if (sscanf(p, "%f, %f, %f", &Sx, &Sy, &Sz) == 3 || ((q = strchr(p, 'S')) != NULL && sscanf(q, "S %f %f %f", &Sx, &Sy, &Sz) == 3)) { Scale[0] = Sx; Scale[1] = Sy; Scale[2] = Sz; } else if (sscanf(p, "%f, %f", &Sx, &Sy) == 2 || ((q = strchr(p, 'S')) != NULL && sscanf(q, "S %f %f", &Sx, &Sy) == 2)) { Scale[0] = Sx; Scale[1] = Sy; } } return TRUE; }