URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [trunk/] [mw/] [src/] [engine/] [devimage.c] - Rev 673
Go to most recent revision | Compare with Previous | Blame | View Log
#define FASTJPEG 1 /* =1 for temp quick jpeg 8bpp display */ #define HAVE_MMAP 1 /* =1 to use mmap if available */ #if defined(HAVE_FILEIO) /* temp for entire file*/ /* * Copyright (c) 2000, 2001 Greg Haerr <greg@censoft.com> * Portions Copyright (c) 2000 Martin Jolicoeur <martinj@visuaide.com> * Portions Copyright (c) 2000 Alex Holden <alex@linuxhacker.org> * Portions Copyright (c) Independant JPEG group (ijg) * * Image load/cache/resize/display routines * * GIF, BMP, JPEG, PPM, PGM, PBM, PNG, and XPM formats are supported. * JHC: Instead of working with a file, we work with a buffer * (either provided by the user or through mmap). This * improves speed, and provides a mechanism by which the * client can send image data directly to the engine */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <ctype.h> #include <sys/types.h> #include <sys/stat.h> #ifdef HAVE_MMAP #include <sys/mman.h> #endif #include "device.h" #include "swap.h" /* cached image list*/ typedef struct { MWLIST link; /* link list*/ int id; /* image id*/ PMWIMAGEHDR pimage; /* image data*/ PSD psd; /* FIXME shouldn't need this*/ } IMAGEITEM, *PIMAGEITEM; static MWLISTHEAD imagehead; /* global image list*/ static int nextimageid = 1; typedef struct { /* structure for reading images from buffer */ void *start; /* The pointer to the beginning of the buffer */ int offset; /* The current offset within the buffer */ int size; /* The total size of the buffer */ } buffer_t; static void ComputePitch(int bpp, int width, int *pitch, int *bytesperpixel); #if defined(HAVE_BMP_SUPPORT) static int LoadBMP(buffer_t *src, PMWIMAGEHDR pimage); #endif #if defined(HAVE_JPEG_SUPPORT) static int LoadJPEG(buffer_t *src, PMWIMAGEHDR pimage, PSD psd, MWBOOL fast_grayscale); #endif #if defined(HAVE_PNG_SUPPORT) static int LoadPNG(buffer_t *src, PMWIMAGEHDR pimage); #endif #if defined(HAVE_GIF_SUPPORT) static int LoadGIF(buffer_t *src, PMWIMAGEHDR pimage); #endif #if defined(HAVE_PNM_SUPPORT) static int LoadPNM(buffer_t *src, PMWIMAGEHDR pimage); #endif #if defined(HAVE_XPM_SUPPORT) static int LoadXPM(buffer_t *src, PMWIMAGEHDR pimage, PSD psd) ; #endif /* * Buffered input functions to replace stdio functions */ static void binit(void *in, int size, buffer_t *dest) { dest->start = in; dest->offset = 0; dest->size = size; } static int bseek(buffer_t *buffer, int offset, int whence) { int new; switch(whence) { case SEEK_SET: if (offset >= buffer->size || offset < 0) return(-1); buffer->offset = offset; return(0); case SEEK_CUR: new = buffer->offset + offset; if (new >= buffer->size || new < 0) return(-1); buffer->offset = new; return(0); case SEEK_END: if (offset >= buffer->size || offset > 0) return(-1); buffer->offset = (buffer->size - 1) - offset; return(0); default: return(-1); } } static int bread(buffer_t *buffer, void *dest, int size) { int copysize = size; if (buffer->offset == buffer->size) return(0); if (buffer->offset + size > buffer->size) copysize = (buffer->size - buffer->offset); memcpy((void *)dest, (void *)(buffer->start + buffer->offset),copysize); buffer->offset += copysize; return(copysize); } static int bgetc(buffer_t *buffer) { int ch; if (buffer->offset == buffer->size) return(EOF); ch = *((unsigned char *) (buffer->start + buffer->offset)); buffer->offset++; return(ch); } static char * bgets(buffer_t *buffer, char *dest, int size) { int i,o; int copysize = size - 1; if (buffer->offset == buffer->size) return(0); if (buffer->offset + copysize > buffer->size) copysize = buffer->size - buffer->offset; for(o=0, i=buffer->offset; i < buffer->offset + copysize; i++, o++) { dest[o] = *((char *) (buffer->start + i)); if (dest[o] == '\n') break; } buffer->offset = i + 1; dest[o + 1] = 0; return(dest); } static int beof(buffer_t *buffer) { return (buffer->offset == buffer->size); } /* * Image decoding and display * NOTE: This routine and APIs will change in subsequent releases. * * Decodes and loads a graphics file, then resizes to width/height, * then displays image at x, y * If width/height == -1, don't resize, use image size. * Clipping is not currently supported, just stretch/shrink to fit. * */ static int GdDecodeImage(PSD psd, buffer_t *src, int flags); int GdLoadImageFromBuffer(PSD psd, void *buffer, int size, int flags) { buffer_t src; binit(buffer, size, &src); return(GdDecodeImage(psd, &src, flags)); } void GdDrawImageFromBuffer(PSD psd, MWCOORD x, MWCOORD y, MWCOORD width, MWCOORD height, void *buffer, int size, int flags) { int id; buffer_t src; binit(buffer, size, &src); id = GdDecodeImage(psd, &src, flags); if (id) { GdDrawImageToFit(psd, x, y, width, height, id); GdFreeImage(id); } } void GdDrawImageFromFile(PSD psd, MWCOORD x, MWCOORD y, MWCOORD width, MWCOORD height, char *path, int flags) { int id; id = GdLoadImageFromFile(psd, path, flags); if (id) { GdDrawImageToFit(psd, x, y, width, height, id); GdFreeImage(id); } } int GdLoadImageFromFile(PSD psd, char *path, int flags) { int fd, id; struct stat s; void *buffer = 0; buffer_t src; fd = open(path, O_RDONLY); if (fd <= 0) { EPRINTF("GdLoadImageFromFile: can't open image: %s\n", path); return(0); } fstat(fd, &s); #ifdef HAVE_MMAP buffer = mmap(0, s.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (!buffer) { EPRINTF("GdLoadImageFromFile: Couldn't map image %s\n", path); close(fd); return(0); } #else buffer = malloc(s.st_size); if (!buffer) { EPRINTF("GdLoadImageFromFile: Couldn't load image %s\n", path); close(fd); return(0); } if (read(fd, buffer, s.st_size) != s.st_size) { EPRINTF("GdLoadImageFromFile: Couldn't load image %s\n", path); close(fd); return(0); } #endif binit(buffer, s.st_size, &src); id = GdDecodeImage(psd, &src, flags); #ifdef HAVE_MMAP munmap(buffer, s.st_size); #else free(buffer); #endif close(fd); return(id); } static int GdDecodeImage(PSD psd, buffer_t * src, int flags) { int loadOK = 0; PMWIMAGEHDR pimage; PIMAGEITEM pItem; /* allocate image struct*/ pimage = (PMWIMAGEHDR)malloc(sizeof(MWIMAGEHDR)); if(!pimage) { return 0; } pimage->imagebits = NULL; pimage->palette = NULL; pimage->transcolor = -1L; #if defined(HAVE_BMP_SUPPORT) if (loadOK == 0) loadOK = LoadBMP(src, pimage); #endif #if defined(HAVE_GIF_SUPPORT) if (loadOK == 0) loadOK = LoadGIF(src, pimage); #endif #if defined(HAVE_JPEG_SUPPORT) if (loadOK == 0) loadOK = LoadJPEG(src, pimage, psd, flags); #endif #if defined(HAVE_PNG_SUPPORT) if (loadOK == 0) loadOK = LoadPNG(src, pimage); #endif #if defined(HAVE_PNM_SUPPORT) if(loadOK == 0) loadOK = LoadPNM(src, pimage); #endif #if defined(HAVE_XPM_SUPPORT) if (loadOK == 0) loadOK = LoadXPM(src, pimage, psd); #endif if (loadOK == 0) { EPRINTF("GdLoadImageFromFile: unknown image type:\n"); // EPRINTF("GdLoadImageFromFile: unknown image type: \n", path); goto err; /* image loading error*/ } if (loadOK != 1) goto err; /* image loading error*/ /* allocate id*/ pItem = GdItemNew(IMAGEITEM); if (!pItem) goto err; pItem->id = nextimageid++; pItem->pimage = pimage; pItem->psd = psd; GdListAdd(&imagehead, &pItem->link); return pItem->id; err: free(pimage); return 0; /* image loading error*/ } static PIMAGEITEM findimage(int id) { PMWLIST p; PIMAGEITEM pimagelist; for (p=imagehead.head; p; p=p->next) { pimagelist = GdItemAddr(p, IMAGEITEM, link); if (pimagelist->id == id) return pimagelist; } return NULL; } void GdDrawImageToFit(PSD psd, MWCOORD x, MWCOORD y, MWCOORD width, MWCOORD height, int id) { PIMAGEITEM pItem; PMWIMAGEHDR pimage; pItem = findimage(id); if (!pItem) return; pimage = pItem->pimage; /* * Display image, possibly stretch/shrink to resize */ if (height < 0) height = pimage->height; if (width < 0) width = pimage->width; if (height != pimage->height || width != pimage->width) { MWCLIPRECT rcDst; MWIMAGEHDR image2; /* create similar image, different width/height*/ image2.width = width; image2.height = height; image2.planes = pimage->planes; image2.bpp = pimage->bpp; ComputePitch(pimage->bpp, width, &image2.pitch, &image2.bytesperpixel); image2.compression = pimage->compression; image2.palsize = pimage->palsize; image2.palette = pimage->palette; /* already allocated*/ image2.transcolor = pimage->transcolor; if( (image2.imagebits = malloc(image2.pitch*height)) == NULL) { EPRINTF("GdDrawImageToFit: no memory\n"); return; } rcDst.x = 0; rcDst.y = 0; rcDst.width = width; rcDst.height = height; /* Stretch full soruce to destination rectangle*/ GdStretchImage(pimage, NULL, &image2, &rcDst); GdDrawImage(psd, x, y, &image2); free(image2.imagebits); } else GdDrawImage(psd, x, y, pimage); } void GdFreeImage(int id) { PIMAGEITEM pItem; PMWIMAGEHDR pimage; pItem = findimage(id); if (pItem) { GdListRemove(&imagehead, &pItem->link); pimage = pItem->pimage; /* delete image bits*/ if(pimage->imagebits) free(pimage->imagebits); if(pimage->palette) free(pimage->palette); free(pimage); GdItemFree(pItem); } } MWBOOL GdGetImageInfo(int id, PMWIMAGEINFO pii) { PMWIMAGEHDR pimage; PIMAGEITEM pItem; int i; pItem = findimage(id); if (!pItem) { memset(pii, 0, sizeof(*pii)); return FALSE; } pimage = pItem->pimage; pii->id = id; pii->width = pimage->width; pii->height = pimage->height; pii->planes = pimage->planes; pii->bpp = pimage->bpp; pii->pitch = pimage->pitch; pii->bytesperpixel = pimage->bytesperpixel; pii->compression = pimage->compression; pii->palsize = pimage->palsize; if (pimage->palsize) { if (pimage->palette) { for (i=0; i<pimage->palsize; ++i) pii->palette[i] = pimage->palette[i]; } else { /* FIXME handle jpeg's without palette*/ GdGetPalette(pItem->psd, 0, pimage->palsize, pii->palette); } } return TRUE; } #define PIX2BYTES(n) (((n)+7)/8) /* * compute image line size and bytes per pixel * from bits per pixel and width */ static void ComputePitch(int bpp, int width, int *pitch, int *bytesperpixel) { int linesize; int bytespp = 1; if(bpp == 1) linesize = PIX2BYTES(width); else if(bpp <= 4) linesize = PIX2BYTES(width<<2); else if(bpp <= 8) linesize = width; else if(bpp <= 16) { linesize = width * 2; bytespp = 2; } else if(bpp <= 24) { linesize = width * 3; bytespp = 3; } else { linesize = width * 4; bytespp = 4; } /* rows are DWORD right aligned*/ *pitch = (linesize + 3) & ~3; *bytesperpixel = bytespp; } /* * StretchImage - Resize an image * * Major portions from SDL Simple DirectMedia Layer by Sam Lantinga * Copyright (C) 1997, 1998, 1999, 2000 Sam Lantinga <slouken@devolution.com> * This a stretch blit implementation based on ideas given to me by * Tomasz Cejner - thanks! :) */ /* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #define DEFINE_COPY_ROW(name, type) \ static void name(type *src, int src_w, type *dst, int dst_w) \ { \ int i; \ int pos, inc; \ type pixel = 0; \ \ pos = 0x10000; \ inc = (src_w << 16) / dst_w; \ for ( i=dst_w; i>0; --i ) { \ while ( pos >= 0x10000L ) { \ pixel = *src++; \ pos -= 0x10000L; \ } \ *dst++ = pixel; \ pos += inc; \ } \ } DEFINE_COPY_ROW(copy_row1, unsigned char) DEFINE_COPY_ROW(copy_row2, unsigned short) DEFINE_COPY_ROW(copy_row4, unsigned long) static void copy_row3(unsigned char *src, int src_w, unsigned char *dst, int dst_w) { int i; int pos, inc; unsigned char r = 0; unsigned char g = 0; unsigned char b = 0; pos = 0x10000; inc = (src_w << 16) / dst_w; for ( i=dst_w; i>0; --i ) { while ( pos >= 0x10000L ) { b = *src++; g = *src++; r = *src++; pos -= 0x10000L; } *dst++ = b; *dst++ = g; *dst++ = r; pos += inc; } } /* Perform a stretch blit between two image structs of the same format.*/ void GdStretchImage(PMWIMAGEHDR src, MWCLIPRECT *srcrect, PMWIMAGEHDR dst, MWCLIPRECT *dstrect) { int pos, inc; int bytesperpixel; int dst_maxrow; int src_row, dst_row; MWUCHAR *srcp = 0; MWUCHAR *dstp; MWCLIPRECT full_src; MWCLIPRECT full_dst; if ( src->bytesperpixel != dst->bytesperpixel ) { EPRINTF("GdStretchImage: bytesperpixel mismatch\n"); return; } /* Verify the blit rectangles */ if ( srcrect ) { if ( (srcrect->x < 0) || (srcrect->y < 0) || ((srcrect->x+srcrect->width) > src->width) || ((srcrect->y+srcrect->height) > src->height) ) { EPRINTF("GdStretchImage: invalid source rect\n"); return; } } else { full_src.x = 0; full_src.y = 0; full_src.width = src->width; full_src.height = src->height; srcrect = &full_src; } if ( dstrect ) { /* if stretching to nothing, return*/ if (!dstrect->width || !dstrect->height) return; if ( (dstrect->x < 0) || (dstrect->y < 0) || ((dstrect->x+dstrect->width) > dst->width) || ((dstrect->y+dstrect->height) > dst->height) ) { EPRINTF("GdStretchImage: invalid dest rect\n"); return; } } else { full_dst.x = 0; full_dst.y = 0; full_dst.width = dst->width; full_dst.height = dst->height; dstrect = &full_dst; } /* Set up the data... */ pos = 0x10000; inc = (srcrect->height << 16) / dstrect->height; src_row = srcrect->y; dst_row = dstrect->y; bytesperpixel = dst->bytesperpixel; /* Perform the stretch blit */ for ( dst_maxrow = dst_row+dstrect->height; dst_row<dst_maxrow; ++dst_row ) { dstp = (MWUCHAR *)dst->imagebits + (dst_row*dst->pitch) + (dstrect->x*bytesperpixel); while ( pos >= 0x10000L ) { srcp = (MWUCHAR *)src->imagebits + (src_row*src->pitch) + (srcrect->x*bytesperpixel); ++src_row; pos -= 0x10000L; } switch (bytesperpixel) { case 1: copy_row1(srcp, srcrect->width, dstp, dstrect->width); break; case 2: copy_row2((unsigned short *)srcp, srcrect->width, (unsigned short *)dstp, dstrect->width); break; case 3: copy_row3(srcp, srcrect->width, dstp, dstrect->width); break; case 4: copy_row4((unsigned long *)srcp, srcrect->width, (unsigned long *)dstp, dstrect->width); break; } pos += inc; } } #if defined(HAVE_FILEIO) && defined(HAVE_JPEG_SUPPORT) #include "jpeglib.h" /* * JPEG decompression routine * * JPEG support must be enabled (see README.txt in contrib/jpeg) * * SOME FINE POINTS: (from libjpeg) * In the below code, we ignored the return value of jpeg_read_scanlines, * which is the number of scanlines actually read. We could get away with * this because we asked for only one line at a time and we weren't using * a suspending data source. See libjpeg.doc for more info. * * We cheated a bit by calling alloc_sarray() after jpeg_start_decompress(); * we should have done it beforehand to ensure that the space would be * counted against the JPEG max_memory setting. In some systems the above * code would risk an out-of-memory error. However, in general we don't * know the output image dimensions before jpeg_start_decompress(), unless we * call jpeg_calc_output_dimensions(). See libjpeg.doc for more about this. * * Scanlines are returned in the same order as they appear in the JPEG file, * which is standardly top-to-bottom. If you must emit data bottom-to-top, * you can use one of the virtual arrays provided by the JPEG memory manager * to invert the data. See wrbmp.c for an example. * * As with compression, some operating modes may require temporary files. * On some systems you may need to set up a signal handler to ensure that * temporary files are deleted if the program is interrupted. See libjpeg.doc. */ static int LoadJPEG(buffer_t *src, PMWIMAGEHDR pimage, PSD psd, MWBOOL fast_grayscale) { int i; int ret = 2; /* image load error*/ unsigned char magic[4]; #if FASTJPEG extern MWPALENTRY mwstdpal8[256]; #else MWPALENTRY palette[256]; #endif struct jpeg_source_mgr smgr; struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; static void init_source(j_compress_ptr dinfo) { smgr.next_input_byte = src->start; smgr.bytes_in_buffer = src->size; } static void fill_input_buffer(j_compress_ptr dinfo) { return; } static void skip_input_data(j_compress_ptr dinfo, int num_bytes) { if (num_bytes >= src->size) return; smgr.next_input_byte += num_bytes; smgr.bytes_in_buffer -= num_bytes; } static int resync_to_restart(j_compress_ptr dinfo, int desired ) { return(jpeg_resync_to_restart(dinfo, desired)); } static void term_source(j_compress_ptr dinfo) { return; } /* first determine if JPEG file since decoder will error if not*/ bseek(src, 0, SEEK_SET); if (!bread(src, magic, 2)) return(0); if (magic[0] != 0xFF || magic[1] != 0xD8) return(0); /* not JPEG image*/ bread(src, magic, 4); bread(src, magic, 4); if (strncmp(magic, "JFIF", 4) != 0) return(0); /* not JPEG image*/ bread(src, 0, SEEK_SET); pimage->imagebits = NULL; pimage->palette = NULL; /* Step 1: allocate and initialize JPEG decompression object */ /* We set up the normal JPEG error routines. */ cinfo.err = jpeg_std_error (&jerr); /* Now we can initialize the JPEG decompression object. */ jpeg_create_decompress (&cinfo); /* Step 2: Setup the source manager */ smgr.init_source = init_source; smgr.fill_input_buffer = fill_input_buffer; smgr.skip_input_data = skip_input_data; smgr.resync_to_restart = resync_to_restart; smgr.term_source = term_source; cinfo.src = &smgr; /* Step 2: specify data source (eg, a file) */ /* jpeg_stdio_src (&cinfo, fp); */ /* Step 3: read file parameters with jpeg_read_header() */ jpeg_read_header (&cinfo, TRUE); /* Step 4: set parameters for decompression */ cinfo.out_color_space = fast_grayscale? JCS_GRAYSCALE: JCS_RGB; cinfo.quantize_colors = FALSE; #if FASTJPEG goto fastjpeg; #endif if (!fast_grayscale) { if (psd->pixtype == MWPF_PALETTE) { fastjpeg: cinfo.quantize_colors = TRUE; #if FASTJPEG cinfo.actual_number_of_colors = 256; #else /* Get system palette */ cinfo.actual_number_of_colors = GdGetPalette(psd, 0, psd->ncolors, palette); #endif /* Allocate jpeg colormap space */ cinfo.colormap = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, (JDIMENSION)cinfo.actual_number_of_colors, (JDIMENSION)3); /* Set colormap from system palette */ for(i = 0; i < cinfo.actual_number_of_colors; ++i) { #if FASTJPEG cinfo.colormap[0][i] = mwstdpal8[i].r; cinfo.colormap[1][i] = mwstdpal8[i].g; cinfo.colormap[2][i] = mwstdpal8[i].b; #else cinfo.colormap[0][i] = palette[i].r; cinfo.colormap[1][i] = palette[i].g; cinfo.colormap[2][i] = palette[i].b; #endif } } } else { /* Grayscale output asked */ cinfo.quantize_colors = TRUE; cinfo.out_color_space = JCS_GRAYSCALE; cinfo.desired_number_of_colors = psd->ncolors; } jpeg_calc_output_dimensions(&cinfo); pimage->width = cinfo.output_width; pimage->height = cinfo.output_height; pimage->planes = 1; #if FASTJPEG pimage->bpp = 8; #else pimage->bpp = (fast_grayscale || psd->pixtype == MWPF_PALETTE)? 8: cinfo.output_components*8; #endif ComputePitch(pimage->bpp, pimage->width, &pimage->pitch, &pimage->bytesperpixel); pimage->compression = MWIMAGE_RGB; /* RGB not BGR order*/ pimage->palsize = (pimage->bpp == 8)? 256: 0; pimage->imagebits = malloc(pimage->pitch * pimage->height); if(!pimage->imagebits) goto err; pimage->palette = NULL; #if FASTJPEG if(pimage->bpp == 8) { pimage->palette = malloc(256*sizeof(MWPALENTRY)); if(!pimage->palette) goto err; for (i=0; i<256; ++i) pimage->palette[i] = mwstdpal8[i]; } #endif /* Step 5: Start decompressor */ jpeg_start_decompress (&cinfo); /* Step 6: while (scan lines remain to be read) */ while(cinfo.output_scanline < cinfo.output_height) { JSAMPROW rowptr[1]; rowptr[0] = (JSAMPROW)(pimage->imagebits + cinfo.output_scanline * pimage->pitch); jpeg_read_scanlines (&cinfo, rowptr, 1); } ret = 1; err: /* Step 7: Finish decompression */ jpeg_finish_decompress (&cinfo); /* Step 8: Release JPEG decompression object */ jpeg_destroy_decompress (&cinfo); /* May want to check to see whether any corrupt-data * warnings occurred (test whether jerr.pub.num_warnings is nonzero). */ return ret; } #endif /* defined(HAVE_FILEIO) && defined(HAVE_JPEG_SUPPORT)*/ #if defined(HAVE_FILEIO) && defined(HAVE_PNG_SUPPORT) #include "png.h" /* png_jmpbuf() macro is not defined prior to libpng-1.0.6*/ #ifndef png_jmpbuf #define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) #endif /* * Load a PNG file. * Currently for simplicity we get the PNG library to convert the file to * 24 bit RGB format with no alpha channel information even if we could * potentially store the image more efficiently by taking note of the image * type and depth and acting accordingly. Similarly, > 8 bits per channel, * gamma correction, etc. are not supported. */ static int LoadPNG(buffer_t * src, PMWIMAGEHDR pimage) { unsigned char hdr[8], **rows; png_structp state; png_infop pnginfo; png_uint_32 width, height; int bit_depth, colourtype, i; bseek(src, 0L, 0); if(bread(src, hdr, 8) != 8) return 0; if(png_sig_cmp(hdr, 0, 8)) return 0; if(!(state = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) goto nomem; if(!(pnginfo = png_create_info_struct(state))) { png_destroy_read_struct(&state, NULL, NULL); goto nomem; } if(setjmp(png_jmpbuf(state))) { png_destroy_read_struct(&state, &pnginfo, NULL); return 2; } png_init_io(state, fp); png_set_sig_bytes(state, 8); png_read_info(state, pnginfo); png_get_IHDR(state, pnginfo, &width, &height, &bit_depth, &colourtype, NULL, NULL, NULL); pimage->width = width; pimage->height = height; pimage->bpp = 24; pimage->planes = 1; ComputePitch(pimage->bpp, pimage->width, &pimage->pitch, &pimage->bytesperpixel); pimage->compression = MWIMAGE_RGB; if(!(pimage->imagebits = malloc(pimage->pitch * pimage->height))) { png_destroy_read_struct(&state, &pnginfo, NULL); goto nomem; } if(!(rows = malloc(pimage->height * sizeof(unsigned char *)))) { png_destroy_read_struct(&state, &pnginfo, NULL); goto nomem; } for(i = 0; i < pimage->height; i++) rows[i] = pimage->imagebits + (i * pimage->pitch); png_set_expand(state); if(bit_depth == 16) png_set_strip_16(state); if(colourtype & PNG_COLOR_MASK_ALPHA) png_set_strip_alpha(state); if(colourtype == PNG_COLOR_TYPE_GRAY || colourtype == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(state); png_read_image(state, rows); png_read_end(state, NULL); free(rows); png_destroy_read_struct(&state, &pnginfo, NULL); return 1; nomem: EPRINTF("LoadPNG: Out of memory\n"); return 2; } #endif /* defined(HAVE_FILEIO) && defined(HAVE_PNG_SUPPORT)*/ #if defined(HAVE_FILEIO) && defined(HAVE_BMP_SUPPORT) /* BMP stuff*/ #define BI_RGB 0L #define BI_RLE8 1L #define BI_RLE4 2L #define BI_BITFIELDS 3L typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned long DWORD; typedef long LONG; typedef struct { /* BITMAPFILEHEADER*/ BYTE bfType[2]; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; } BMPFILEHEAD; #define FILEHEADSIZE 14 /* windows style*/ typedef struct { /* BITMAPINFOHEADER*/ DWORD BiSize; DWORD BiWidth; DWORD BiHeight; WORD BiPlanes; WORD BiBitCount; DWORD BiCompression; DWORD BiSizeImage; DWORD BiXpelsPerMeter; DWORD BiYpelsPerMeter; DWORD BiClrUsed; DWORD BiClrImportant; } BMPINFOHEAD; #define INFOHEADSIZE 40 /* os/2 style*/ typedef struct { /* BITMAPCOREHEADER*/ DWORD bcSize; WORD bcWidth; WORD bcHeight; WORD bcPlanes; WORD bcBitCount; } BMPCOREHEAD; #define COREHEADSIZE 12 static int DecodeRLE8(MWUCHAR *buf, buffer_t *src); static int DecodeRLE4(MWUCHAR *buf, buffer_t *src); static void put4(int b); /* * BMP decoding routine */ /* Changed by JHC to allow a buffer instead of a filename */ static int LoadBMP(buffer_t *src, PMWIMAGEHDR pimage) { int h, i, compression; int headsize; MWUCHAR *imagebits; BMPFILEHEAD bmpf; BMPINFOHEAD bmpi; BMPCOREHEAD bmpc; MWUCHAR headbuffer[INFOHEADSIZE]; bseek(src, 0, SEEK_SET); pimage->imagebits = NULL; pimage->palette = NULL; /* read BMP file header*/ if (bread(src, &headbuffer, FILEHEADSIZE) != FILEHEADSIZE) return(0); bmpf.bfType[0] = headbuffer[0]; bmpf.bfType[1] = headbuffer[1]; /* Is it really a bmp file ? */ if (*(WORD*)&bmpf.bfType[0] != wswap(0x4D42)) /* 'BM' */ return 0; /* not bmp image*/ /*bmpf.bfSize = dwswap(dwread(&headbuffer[2]));*/ bmpf.bfOffBits = dwswap(dwread(&headbuffer[10])); /* Read remaining header size */ if (bread(src,&headsize,sizeof(DWORD)) != sizeof(DWORD)) return 0; /* not bmp image*/ headsize = dwswap(headsize); /* might be windows or os/2 header */ if(headsize == COREHEADSIZE) { /* read os/2 header */ if(bread(src, &headbuffer, COREHEADSIZE-sizeof(DWORD)) != COREHEADSIZE-sizeof(DWORD)) return 0; /* not bmp image*/ /* Get data */ bmpc.bcWidth = wswap(*(WORD*)&headbuffer[0]); bmpc.bcHeight = wswap(*(WORD*)&headbuffer[2]); bmpc.bcPlanes = wswap(*(WORD*)&headbuffer[4]); bmpc.bcBitCount = wswap(*(WORD*)&headbuffer[6]); pimage->width = (int)bmpc.bcWidth; pimage->height = (int)bmpc.bcHeight; pimage->bpp = bmpc.bcBitCount; if (pimage->bpp <= 8) pimage->palsize = 1 << pimage->bpp; else pimage->palsize = 0; compression = BI_RGB; } else { /* read windows header */ if(bread(src, &headbuffer, INFOHEADSIZE-sizeof(DWORD)) != INFOHEADSIZE-sizeof(DWORD)) return 0; /* not bmp image*/ /* Get data */ bmpi.BiWidth = dwswap(*(DWORD*)&headbuffer[0]); bmpi.BiHeight = dwswap(*(DWORD*)&headbuffer[4]); bmpi.BiPlanes = wswap(*(WORD*)&headbuffer[8]); bmpi.BiBitCount = wswap(*(WORD*)&headbuffer[10]); bmpi.BiCompression = dwswap(*(DWORD*)&headbuffer[12]); bmpi.BiSizeImage = dwswap(*(DWORD*)&headbuffer[16]); bmpi.BiXpelsPerMeter = dwswap(*(DWORD*)&headbuffer[20]); bmpi.BiYpelsPerMeter = dwswap(*(DWORD*)&headbuffer[24]); bmpi.BiClrUsed = dwswap(*(DWORD*)&headbuffer[28]); bmpi.BiClrImportant = dwswap(*(DWORD*)&headbuffer[32]); pimage->width = (int)bmpi.BiWidth; pimage->height = (int)bmpi.BiHeight; pimage->bpp = bmpi.BiBitCount; pimage->palsize = (int)bmpi.BiClrUsed; if (pimage->palsize > 256) pimage->palsize = 0; else if(pimage->palsize == 0 && pimage->bpp <= 8) pimage->palsize = 1 << pimage->bpp; compression = bmpi.BiCompression; } pimage->compression = MWIMAGE_BGR; /* right side up, BGR order*/ pimage->planes = 1; /* currently only 1, 4, 8 and 24 bpp bitmaps*/ if(pimage->bpp > 8 && pimage->bpp != 24) { EPRINTF("LoadBMP: image bpp not 1, 4, 8 or 24\n"); return 2; /* image loading error*/ } /* compute byte line size and bytes per pixel*/ ComputePitch(pimage->bpp, pimage->width, &pimage->pitch, &pimage->bytesperpixel); /* Allocate image */ if( (pimage->imagebits = malloc(pimage->pitch*pimage->height)) == NULL) goto err; if( (pimage->palette = malloc(256*sizeof(MWPALENTRY))) == NULL) goto err; /* get colormap*/ if(pimage->bpp <= 8) { for(i=0; i<pimage->palsize; i++) { pimage->palette[i].b = bgetc(src); pimage->palette[i].g = bgetc(src); pimage->palette[i].r = bgetc(src); if(headsize != COREHEADSIZE) bgetc(src); } } /* decode image data*/ bseek(src, bmpf.bfOffBits, SEEK_SET); h = pimage->height; /* For every row ... */ while (--h >= 0) { /* turn image rightside up*/ imagebits = pimage->imagebits + h*pimage->pitch; /* Get row data from file */ if(compression == BI_RLE8) { if(!DecodeRLE8(imagebits, src)) break; } else if(compression == BI_RLE4) { if(!DecodeRLE4(imagebits, src)) break; } else { if(bread(src, imagebits, pimage->pitch) != pimage->pitch) goto err; } } return 1; /* bmp image ok*/ err: EPRINTF("LoadBMP: image loading error\n"); if(pimage->imagebits) free(pimage->imagebits); if(pimage->palette) free(pimage->palette); return 2; /* bmp image error*/ } /* * Decode one line of RLE8, return 0 when done with all bitmap data */ static int DecodeRLE8(MWUCHAR *buf, buffer_t *src) { int c, n; MWUCHAR * p = buf; for( ;;) { switch( n = bgetc(src)) { case EOF: return( 0); case 0: /* 0 = escape*/ switch( n = bgetc(src)) { case 0: /* 0 0 = end of current scan line*/ return( 1); case 1: /* 0 1 = end of data*/ return( 1); case 2: /* 0 2 xx yy delta mode NOT SUPPORTED*/ (void)bgetc(src); (void)bgetc(src); continue; default: /* 0 3..255 xx nn uncompressed data*/ for( c=0; c<n; c++) *p++ = bgetc(src); if( n & 1) (void)bgetc(src); continue; } default: c = bgetc(src); while( n--) *p++ = c; continue; } } } /* * Decode one line of RLE4, return 0 when done with all bitmap data */ static MWUCHAR *p; static int once; static void put4(int b) { static int last; last = (last << 4) | b; if( ++once == 2) { *p++ = last; once = 0; } } static int DecodeRLE4(MWUCHAR *buf, buffer_t *src) { int c, n, c1, c2; p = buf; once = 0; c1 = 0; for( ;;) { switch( n = bgetc(src)) { case EOF: return( 0); case 0: /* 0 = escape*/ switch( n = bgetc(src)) { case 0: /* 0 0 = end of current scan line*/ if( once) put4( 0); return( 1); case 1: /* 0 1 = end of data*/ if( once) put4( 0); return( 1); case 2: /* 0 2 xx yy delta mode NOT SUPPORTED*/ (void)bgetc(src); (void)bgetc(src); continue; default: /* 0 3..255 xx nn uncompressed data*/ c2 = (n+3) & ~3; for( c=0; c<c2; c++) { if( (c & 1) == 0) c1 = bgetc(src); if( c < n) put4( (c1 >> 4) & 0x0f); c1 <<= 4; } continue; } default: c = bgetc(src); c1 = (c >> 4) & 0x0f; c2 = c & 0x0f; for( c=0; c<n; c++) put4( (c&1)? c2: c1); continue; } } } #endif /* defined(HAVE_FILEIO) && defined(HAVE_BMP_SUPPORT)*/ #if 0 void print_image(PMWIMAGEHDR image) { int i; DPRINTF("Image:\n\n"); DPRINTF("height: %d\n", image->height); DPRINTF("width: %d\n", image->width); DPRINTF("planes: %d\n", image->planes); DPRINTF("bpp: %d\n", image->bpp); DPRINTF("compression: %d\n", image->compression); DPRINTF("palsize: %d\n", image->palsize); for (i=0;i<image->palsize;i++) DPRINTF("palette: %d, %d, %d\n", image->palette[i].r, image->palette[i].g, image->palette[i].b); for(i=0;i<(image->width*image->height);i++) DPRINTF("imagebits: %d\n", image->imagebits[i]); } #endif #if defined(HAVE_FILEIO) && defined(HAVE_GIF_SUPPORT) /* Code for GIF decoding has been adapted from XPaint: */ /* +-------------------------------------------------------------------+ */ /* | Copyright 1990, 1991, 1993 David Koblas. | */ /* | Copyright 1996 Torsten Martinsen. | */ /* | Permission to use, copy, modify, and distribute this software | */ /* | and its documentation for any purpose and without fee is hereby | */ /* | granted, provided that the above copyright notice appear in all | */ /* | copies and that both that copyright notice and this permission | */ /* | notice appear in supporting documentation. This software is | */ /* | provided "as is" without express or implied warranty. | */ /* +-------------------------------------------------------------------+ */ /* Portions Copyright (C) 1999 Sam Lantinga*/ /* Adapted for use in SDL by Sam Lantinga -- 7/20/98 */ /* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* GIF stuff*/ /* * GIF decoding routine */ #define MAXCOLORMAPSIZE 256 #define MAX_LWZ_BITS 12 #define INTERLACE 0x40 #define LOCALCOLORMAP 0x80 #define CM_RED 0 #define CM_GREEN 1 #define CM_BLUE 2 #define BitSet(byte, bit) (((byte) & (bit)) == (bit)) #define ReadOK(src,buffer,len) bread(src, buffer, len) #define LM_to_uint(a,b) (((b)<<8)|(a)) struct { unsigned int Width; unsigned int Height; unsigned char ColorMap[3][MAXCOLORMAPSIZE]; unsigned int BitPixel; unsigned int ColorResolution; unsigned int Background; unsigned int AspectRatio; int GrayScale; } GifScreen; static struct { int transparent; int delayTime; int inputFlag; int disposal; } Gif89; static int ReadColorMap(buffer_t *src, int number, unsigned char buffer[3][MAXCOLORMAPSIZE], int *flag); static int DoExtension(buffer_t *src, int label); static int GetDataBlock(buffer_t *src, unsigned char *buf); static int GetCode(buffer_t *src, int code_size, int flag); static int LWZReadByte(buffer_t *src, int flag, int input_code_size); static int ReadImage(buffer_t *src, PMWIMAGEHDR pimage, int len, int height, int, unsigned char cmap[3][MAXCOLORMAPSIZE], int gray, int interlace, int ignore); static int LoadGIF(buffer_t *src, PMWIMAGEHDR pimage) { unsigned char buf[16]; unsigned char c; unsigned char localColorMap[3][MAXCOLORMAPSIZE]; int grayScale; int useGlobalColormap; int bitPixel; int imageCount = 0; char version[4]; int imageNumber = 1; int ok = 0; bseek(src, 0, SEEK_SET); pimage->imagebits = NULL; pimage->palette = NULL; if (!ReadOK(src, buf, 6)) return 0; /* not gif image*/ if (strncmp((char *) buf, "GIF", 3) != 0) return 0; strncpy(version, (char *) buf + 3, 3); version[3] = '\0'; if (strcmp(version, "87a") != 0 && strcmp(version, "89a") != 0) { EPRINTF("LoadGIF: GIF version number not 87a or 89a\n"); return 2; /* image loading error*/ } Gif89.transparent = -1; Gif89.delayTime = -1; Gif89.inputFlag = -1; Gif89.disposal = 0; if (!ReadOK(src, buf, 7)) { EPRINTF("LoadGIF: bad screen descriptor\n"); return 2; /* image loading error*/ } GifScreen.Width = LM_to_uint(buf[0], buf[1]); GifScreen.Height = LM_to_uint(buf[2], buf[3]); GifScreen.BitPixel = 2 << (buf[4] & 0x07); GifScreen.ColorResolution = (((buf[4] & 0x70) >> 3) + 1); GifScreen.Background = buf[5]; GifScreen.AspectRatio = buf[6]; if (BitSet(buf[4], LOCALCOLORMAP)) { /* Global Colormap */ if (ReadColorMap(src, GifScreen.BitPixel, GifScreen.ColorMap, &GifScreen.GrayScale)) { EPRINTF("LoadGIF: bad global colormap\n"); return 2; /* image loading error*/ } } do { if (!ReadOK(src, &c, 1)) { EPRINTF("LoadGIF: EOF on image data\n"); goto done; } if (c == ';') { /* GIF terminator */ if (imageCount < imageNumber) { EPRINTF("LoadGIF: no image %d of %d\n", imageNumber,imageCount); goto done; } } if (c == '!') { /* Extension */ if (!ReadOK(src, &c, 1)) { EPRINTF("LoadGIF: EOF on extension function code\n"); goto done; } DoExtension(src, c); continue; } if (c != ',') { /* Not a valid start character */ continue; } ++imageCount; if (!ReadOK(src, buf, 9)) { EPRINTF("LoadGIF: bad image size\n"); goto done; } useGlobalColormap = !BitSet(buf[8], LOCALCOLORMAP); bitPixel = 1 << ((buf[8] & 0x07) + 1); if (!useGlobalColormap) { if (ReadColorMap(src, bitPixel, localColorMap, &grayScale)) { EPRINTF("LoadGIF: bad local colormap\n"); goto done; } ok = ReadImage(src, pimage, LM_to_uint(buf[4], buf[5]), LM_to_uint(buf[6], buf[7]), bitPixel, localColorMap, grayScale, BitSet(buf[8], INTERLACE), imageCount != imageNumber); } else { ok = ReadImage(src, pimage, LM_to_uint(buf[4], buf[5]), LM_to_uint(buf[6], buf[7]), GifScreen.BitPixel, GifScreen.ColorMap, GifScreen.GrayScale, BitSet(buf[8], INTERLACE), imageCount != imageNumber); } } while (ok == 0); /* set transparent color, if any*/ pimage->transcolor = Gif89.transparent; if (ok) return 1; /* image load ok*/ done: if (pimage->imagebits) free(pimage->imagebits); if (pimage->palette) free(pimage->palette); return 2; /* image load error*/ } static int ReadColorMap(buffer_t *src, int number, unsigned char buffer[3][MAXCOLORMAPSIZE], int *gray) { int i; unsigned char rgb[3]; int flag; flag = TRUE; for (i = 0; i < number; ++i) { if (!ReadOK(src, rgb, sizeof(rgb))) return 1; buffer[CM_RED][i] = rgb[0]; buffer[CM_GREEN][i] = rgb[1]; buffer[CM_BLUE][i] = rgb[2]; flag &= (rgb[0] == rgb[1] && rgb[1] == rgb[2]); } #if 0 if (flag) *gray = (number == 2) ? PBM_TYPE : PGM_TYPE; else *gray = PPM_TYPE; #else *gray = 0; #endif return FALSE; } static int DoExtension(buffer_t *src, int label) { static unsigned char buf[256]; switch (label) { case 0x01: /* Plain Text Extension */ break; case 0xff: /* Application Extension */ break; case 0xfe: /* Comment Extension */ while (GetDataBlock(src, (unsigned char *) buf) != 0); return FALSE; case 0xf9: /* Graphic Control Extension */ GetDataBlock(src, (unsigned char *) buf); Gif89.disposal = (buf[0] >> 2) & 0x7; Gif89.inputFlag = (buf[0] >> 1) & 0x1; Gif89.delayTime = LM_to_uint(buf[1], buf[2]); if ((buf[0] & 0x1) != 0) Gif89.transparent = buf[3]; while (GetDataBlock(src, (unsigned char *) buf) != 0); return FALSE; default: break; } while (GetDataBlock(src, (unsigned char *) buf) != 0); return FALSE; } static int ZeroDataBlock = FALSE; static int GetDataBlock(buffer_t *src, unsigned char *buf) { unsigned char count; if (!ReadOK(src, &count, 1)) return -1; ZeroDataBlock = count == 0; if ((count != 0) && (!ReadOK(src, buf, count))) return -1; return count; } static int GetCode(buffer_t *src, int code_size, int flag) { static unsigned char buf[280]; static int curbit, lastbit, done, last_byte; int i, j, ret; unsigned char count; if (flag) { curbit = 0; lastbit = 0; done = FALSE; return 0; } if ((curbit + code_size) >= lastbit) { if (done) { if (curbit >= lastbit) EPRINTF("LoadGIF: bad decode\n"); return -1; } buf[0] = buf[last_byte - 2]; buf[1] = buf[last_byte - 1]; if ((count = GetDataBlock(src, &buf[2])) == 0) done = TRUE; last_byte = 2 + count; curbit = (curbit - lastbit) + 16; lastbit = (2 + count) * 8; } ret = 0; for (i = curbit, j = 0; j < code_size; ++i, ++j) ret |= ((buf[i / 8] & (1 << (i % 8))) != 0) << j; curbit += code_size; return ret; } static int LWZReadByte(buffer_t *src, int flag, int input_code_size) { int code, incode; register int i; static int fresh = FALSE; static int code_size, set_code_size; static int max_code, max_code_size; static int firstcode, oldcode; static int clear_code, end_code; static int table[2][(1 << MAX_LWZ_BITS)]; static int stack[(1 << (MAX_LWZ_BITS)) * 2], *sp; if (flag) { set_code_size = input_code_size; code_size = set_code_size + 1; clear_code = 1 << set_code_size; end_code = clear_code + 1; max_code_size = 2 * clear_code; max_code = clear_code + 2; GetCode(src, 0, TRUE); fresh = TRUE; for (i = 0; i < clear_code; ++i) { table[0][i] = 0; table[1][i] = i; } for (; i < (1 << MAX_LWZ_BITS); ++i) table[0][i] = table[1][0] = 0; sp = stack; return 0; } else if (fresh) { fresh = FALSE; do { firstcode = oldcode = GetCode(src, code_size, FALSE); } while (firstcode == clear_code); return firstcode; } if (sp > stack) return *--sp; while ((code = GetCode(src, code_size, FALSE)) >= 0) { if (code == clear_code) { for (i = 0; i < clear_code; ++i) { table[0][i] = 0; table[1][i] = i; } for (; i < (1 << MAX_LWZ_BITS); ++i) table[0][i] = table[1][i] = 0; code_size = set_code_size + 1; max_code_size = 2 * clear_code; max_code = clear_code + 2; sp = stack; firstcode = oldcode = GetCode(src, code_size, FALSE); return firstcode; } else if (code == end_code) { int count; unsigned char buf[260]; if (ZeroDataBlock) return -2; while ((count = GetDataBlock(src, buf)) > 0); if (count != 0) { /* * EPRINTF("missing EOD in data stream (common occurence)"); */ } return -2; } incode = code; if (code >= max_code) { *sp++ = firstcode; code = oldcode; } while (code >= clear_code) { *sp++ = table[1][code]; if (code == table[0][code]) EPRINTF("LoadGIF: circular table entry\n"); code = table[0][code]; } *sp++ = firstcode = table[1][code]; if ((code = max_code) < (1 << MAX_LWZ_BITS)) { table[0][code] = oldcode; table[1][code] = firstcode; ++max_code; if ((max_code >= max_code_size) && (max_code_size < (1 << MAX_LWZ_BITS))) { max_code_size *= 2; ++code_size; } } oldcode = incode; if (sp > stack) return *--sp; } return code; } static int ReadImage(buffer_t* src, PMWIMAGEHDR pimage, int len, int height, int cmapSize, unsigned char cmap[3][MAXCOLORMAPSIZE], int gray, int interlace, int ignore) { unsigned char c; int i, v; int xpos = 0, ypos = 0, pass = 0; /* * Initialize the compression routines */ if (!ReadOK(src, &c, 1)) { EPRINTF("LoadGIF: EOF on image data\n"); return 0; } if (LWZReadByte(src, TRUE, c) < 0) { EPRINTF("LoadGIF: error reading image\n"); return 0; } /* * If this is an "uninteresting picture" ignore it. */ if (ignore) { while (LWZReadByte(src, FALSE, c) >= 0); return 0; } /*image = ImageNewCmap(len, height, cmapSize);*/ pimage->width = len; pimage->height = height; pimage->planes = 1; pimage->bpp = 8; ComputePitch(8, len, &pimage->pitch, &pimage->bytesperpixel); pimage->compression = 0; pimage->palsize = cmapSize; pimage->palette = malloc(256*sizeof(MWPALENTRY)); pimage->imagebits = malloc(height*pimage->pitch); if(!pimage->imagebits || !pimage->palette) return 0; for (i = 0; i < cmapSize; i++) { /*ImageSetCmap(image, i, cmap[CM_RED][i], cmap[CM_GREEN][i], cmap[CM_BLUE][i]);*/ pimage->palette[i].r = cmap[CM_RED][i]; pimage->palette[i].g = cmap[CM_GREEN][i]; pimage->palette[i].b = cmap[CM_BLUE][i]; } while ((v = LWZReadByte(src, FALSE, c)) >= 0) { pimage->imagebits[ypos * pimage->pitch + xpos] = v; ++xpos; if (xpos == len) { xpos = 0; if (interlace) { switch (pass) { case 0: case 1: ypos += 8; break; case 2: ypos += 4; break; case 3: ypos += 2; break; } if (ypos >= height) { ++pass; switch (pass) { case 1: ypos = 4; break; case 2: ypos = 2; break; case 3: ypos = 1; break; default: goto fini; } } } else { ++ypos; } } if (ypos >= height) break; } fini: return 1; } #endif /* defined(HAVE_FILEIO) && defined(HAVE_GIF_SUPPORT)*/ #if defined(HAVE_FILEIO) && defined(HAVE_PNM_SUPPORT) enum { PNM_TYPE_NOTPNM, PNM_TYPE_PBM, PNM_TYPE_PGM, PNM_TYPE_PPM }; static int LoadPNM(buffer_t *src, PMWIMAGEHDR pimage) { char buf[256], *p; int type = PNM_TYPE_NOTPNM, binary = 0, gothdrs = 0, scale = 0; int ch, x = 0, y = 0, i, n, mask, col1, col2, col3; bseek(src, 0L, 0); if(!bgets(src,buf, 4)) return 0; if(!strcmp("P1\n", buf)) type = PNM_TYPE_PBM; else if(!strcmp("P2\n", buf)) type = PNM_TYPE_PGM; else if(!strcmp("P3\n", buf)) type = PNM_TYPE_PPM; else if(!strcmp("P4\n", buf)) { type = PNM_TYPE_PBM; binary = 1; } else if(!strcmp("P5\n", buf)) { type = PNM_TYPE_PGM; binary = 1; } else if(!strcmp("P6\n", buf)) { type = PNM_TYPE_PPM; binary = 1; } if(type == PNM_TYPE_NOTPNM) return 0; n = 0; while((p = bgets(src, buf, 256))) { if(*buf == '#') continue; if(type == PNM_TYPE_PBM) { if(sscanf(buf, "%i %i", &pimage->width, &pimage->height) == 2) { pimage->bpp = 1; gothdrs = 1; if(!(pimage->palette = malloc( sizeof(MWPALENTRY) * 2))) { EPRINTF("Out of memory\n"); return 2; } pimage->palsize = 2; pimage->palette[0].r = 0xff; pimage->palette[0].g = 0xff; pimage->palette[0].b = 0xff; pimage->palette[1].r = 0; pimage->palette[1].g = 0; pimage->palette[1].b = 0; } break; } if((type == PNM_TYPE_PGM) || (type == PNM_TYPE_PPM)) { if(!n++) { if(sscanf(buf, "%i %i", &pimage->width, &pimage->height) != 2) break; } else { if(sscanf(buf, "%i", &i) != 1) break; pimage->bpp = 24; if(i > 255) { EPRINTF("LoadPNM: PPM files must be " "24bpp\n"); return 2; } for(scale = 7, n = 2; scale; scale--, n *= 2) if(i < n) break; gothdrs = 1; break; } } } if(!gothdrs) { EPRINTF("LoadPNM: bad image headers\n"); if(pimage->palette) free(pimage->palette); return 2; } pimage->planes = 1; ComputePitch(pimage->bpp, pimage->width, &pimage->pitch, &pimage->bytesperpixel); pimage->compression = MWIMAGE_RGB; if(!(pimage->imagebits = malloc(pimage->pitch * pimage->height))) { EPRINTF("LoadPNM: couldn't allocate memory for image\n"); if(pimage->palette) free(pimage->palette); return 2; } p = pimage->imagebits; if(type == PNM_TYPE_PBM) { if(binary) { x = 0; y = 0; while((ch = bgetc(src)) != EOF) { for(i = 0; i < 8; i++) { mask = 0x80 >> i; if(ch & mask) *p |= mask; else *p &= ~mask; if(++x == pimage->width) { if(++y == pimage->height) return 1; p = pimage->imagebits - 1 + (y * pimage->pitch); x = 0; break; } } p++; } } else { n = 0; while((ch = bgetc(src)) != EOF) { if(isspace(ch)) continue; mask = 0x80 >> n; if(ch == '1') *p |= mask; else if(ch == '0') *p &= ~mask; else goto baddata; if(++n == 8) { n = 0; p++; } if(++x == pimage->width) { if(++y == pimage->height) return 1; p = pimage->imagebits + (y * pimage->pitch); n = 0; x = 0; } } } } else { while(1) { if(type == PNM_TYPE_PGM) { if(binary) { if((ch = bgetc(src)) == EOF) goto baddata; } else { // if(fscanf(fp, "%i", &ch) != 1) goto baddata; } *p++ = ch << scale; *p++ = ch << scale; *p++ = ch << scale; } else { if(binary) { if(((col1 = bgetc(src)) == EOF) || ((col2 = bgetc(src)) == EOF) || ((col3 = bgetc(src)) == EOF)) goto baddata; } else { // if(fscanf(fp, "%i %i %i", &col1, &col2, // &col3) != 3) goto baddata; } *p++ = col1 << scale; *p++ = col2 << scale; *p++ = col3 << scale; } if(++x == pimage->width) { if(++y == pimage->height) return 1; p = pimage->imagebits + (y * pimage->pitch); x = 0; } } } baddata: EPRINTF("LoadPNM: bad image data\n"); free(pimage->imagebits); if(pimage->palette) free(pimage->palette); return 2; } #endif /* defined(HAVE_FILEIO) && defined(HAVE_PNM_SUPPORT) */ #if defined(HAVE_FILEIO) && defined(HAVE_XPM_SUPPORT) struct xpm_cmap { char mapstr[3]; long palette_entry; long color; struct xpm_cmap *next; }; static long XPM_parse_color(char *color) { /* This will parse the string into a color value of some sort */ if (color[0] != '#') { if (!strcmp(color, "None")) return(-1); /* Transparent */ else return(0); /* If its an X color, then we bail */ } else { /* This is ugly! */ char *sptr = color + 1; char rstr[5], gstr[5], bstr[5]; long r,g,b; switch(strlen(sptr)) { case 6: return(strtol(sptr, NULL, 16)); case 9: /* RRRGGGBBB */ strncpy(rstr, sptr, 3); strncpy(gstr, sptr + 3, 3); strncpy(bstr, sptr + 6, 3); rstr[3] = 0; gstr[3] = 0; bstr[3] = 0; r = strtol(rstr, NULL, 16) >> 4; g = strtol(gstr, NULL, 16) >> 4; b = strtol(bstr, NULL, 16) >> 4; return( (long) ( r << 16 | g << 8 | b)); case 12: strncpy(rstr, sptr, 4); strncpy(gstr, sptr + 4, 4); strncpy(bstr, sptr + 8, 4); rstr[4] = 0; gstr[4] = 0; bstr[4] = 0; r = strtol(rstr, NULL, 16) >> 8; g = strtol(gstr, NULL, 16) >> 8; b = strtol(bstr, NULL, 16) >> 8; return( (long) ( (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF))); } } return(0); } /* A series of status indicators that let us know whats going on */ /* It could be an enum if you want */ #define LOAD_HEADER 1 #define LOAD_COLORS 2 #define LOAD_PALETTE 3 #define LOAD_PIXELS 4 #define LOAD_DONE 5 /* The magic that "should" indicate an XPM (does it really?) */ #define XPM_MAGIC "/* XPM */" #define XPM_TRANSCOLOR 0x01000000 static int LoadXPM(buffer_t *src, PMWIMAGEHDR pimage, PSD psd) { struct xpm_cmap *colorheap = 0; /* A "heap" of color structs */ struct xpm_cmap *colormap[256]; /* A quick hash of 256 spots for colors */ unsigned char *imageptr = 0; MWSCREENINFO sinfo; char xline[300]; char dline[300]; char *c; int a; int col, row, colors, cpp; int in_color = 0; int read_xline = 0; int status = LOAD_HEADER; /* Very first thing, get the screen info */ GdGetScreenInfo(psd, &sinfo); for(a = 0; a < 256; a++) colormap[a] = 0; pimage->imagebits = NULL; pimage->palette = NULL; /* Start over at the beginning with the file */ bseek(src, 0, SEEK_SET); bgets(src, xline, 300); /* Chop the EOL */ xline[strlen(xline) - 1] = 0; /* Check the magic */ if (strncmp(xline, XPM_MAGIC, sizeof(XPM_MAGIC))) return(0); while(!beof(src)) { /* Get the next line from the file */ bgets(src,xline, 300); xline[strlen(xline) - 1] = 0; /* Check it out */ if (xline[0] == '/' && xline[1] == '*') /* Comment */ continue; if (xline[0] != '\"') continue; /* remove the quotes from the line */ for(c = xline + 1, a = 0; *c != '\"' && *c != 0; c++, a++) dline[a] = *c; dline[a] = 0; /* Is it the header? */ if (status == LOAD_HEADER) { sscanf(dline, "%i %i %i %i", &col, &row, &colors, &cpp); pimage->width = col; pimage->height = row; pimage->planes = 1; if (sinfo.bpp <= 8) { pimage->bpp = sinfo.bpp; pimage->compression = 0; pimage->transcolor = -1; } else { pimage->bpp = 32; pimage->transcolor = XPM_TRANSCOLOR; pimage->compression = MWIMAGE_BGR; } pimage->palsize = colors; ComputePitch(pimage->bpp, col, &pimage->pitch, &pimage->bytesperpixel); pimage->imagebits = malloc(pimage->pitch * pimage->height); imageptr = (unsigned char *) pimage->imagebits; /* Allocate enough room for all the colors */ colorheap = (struct xpm_cmap *) malloc(colors * sizeof(struct xpm_cmap)); /* Allocate the palette space (if required) */ if (sinfo.bpp <= 8) pimage->palette = malloc(256*sizeof(MWPALENTRY)); if (!colorheap) { EPRINTF("Couldn't allocate any memory for the colors\n"); return(0); } status = LOAD_COLORS; in_color = 0; continue; } /* Are we in load colors? */ if (status == LOAD_COLORS) { struct xpm_cmap *n; char tstr[5]; char cstr[256]; unsigned char m; c = dline; /* Go at at least 1 charater, and then count until we have two spaces in a row */ strncpy(tstr, c, cpp); c += cpp; for(; *c == '\t' || *c == ' '; c++); /* Skip over whitespace */ /* FIXME: We assume that a 'c' follows. What if it doesn't? */ c +=2; tstr[cpp] = 0; /* Now we put it into the array for easy lookup */ /* We base it off the first charater, even though */ /* there may be up to 4 */ m = tstr[0]; if (colormap[m]) { n = colormap[m]; while(n->next) n = n->next; n->next = &colorheap[in_color]; n = n->next; } else { colormap[m] = &colorheap[in_color]; n = colormap[m]; } n->next = 0; /* Record the string */ strncpy(n->mapstr, tstr, cpp); n->mapstr[cpp] = 0; /* Now record the palette entry */ n->palette_entry = (long) in_color; /* This is the color */ sscanf(c, "%65535s", cstr); /* Turn it into a real value */ n->color = XPM_parse_color(cstr); /* If we are in palette mode, then we need to */ /* load the palette (duh..) */ if (sinfo.bpp <= 8) { if (n->color == -1) { pimage->transcolor = in_color; n->color = -1; } pimage->palette[in_color].r = (n->color >> 16) & 0xFF; pimage->palette[in_color].g = (n->color >> 8) & 0xFF; pimage->palette[in_color].b = n->color & 0xFF; } else { if (n->color == -1) n->color = XPM_TRANSCOLOR; } if (++in_color == colors) { read_xline = 0; status = LOAD_PIXELS; } continue; } if (status == LOAD_PIXELS) { int bytecount = 0; int bitcount = 0; long dwordcolor = 0; int i; char pxlstr[3]; c = dline; while(*c) { unsigned char z = 0; if (cpp == 1) { z = *c; if (!colormap[z]) { EPRINTF("No color entry for (%c)\n", z); return(0); } if (sinfo.bpp <= 8) dwordcolor = (long) colormap[z]->palette_entry; else dwordcolor = colormap[z]->color; c++; } else { struct xpm_cmap *n; /* We grab the largest possible, and then compare */ strncpy(pxlstr, c, cpp); z = pxlstr[0]; if (!colormap[z]) { EPRINTF("No color entry for (%s)\n", pxlstr); return(0); } n = colormap[z]; while(n) { if (!strncmp(n->mapstr, pxlstr, cpp)) break; n = n->next; } if (!n) { EPRINTF("No color found for (%s)\n", pxlstr); return(0); } if (sinfo.bpp <= 8) dwordcolor = (long) n->palette_entry; else dwordcolor = n->color; c += cpp; } /* * This ugly thing is needed to ensure that we * work well in all modes. */ switch(sinfo.bpp) { case 2: if (bitcount == 0) imageptr[0] = 0; imageptr[0] |= (dwordcolor & 0x3) << (4 - bitcount); bitcount++; if (bitcount == 4) { imageptr++; bytecount += pimage->bytesperpixel; bitcount = 0; } break; case 4: if (bitcount == 0) imageptr[0] = 0; imageptr[0] |= (dwordcolor & 0xF) << (2 - bitcount); bitcount++; if (bitcount == 2) { imageptr++; bytecount += pimage->bytesperpixel; bitcount = 0; } break; case 8: case 16: case 24: case 32: for(i = 0; i < pimage->bytesperpixel; i++) imageptr[i] = (dwordcolor >> (8 * i)) & 0xFF; imageptr += pimage->bytesperpixel; bytecount += pimage->bytesperpixel; break; #ifdef NOTUSED case 8: imageptr[0] = (unsigned char) (dwordcolor & 0xFF); imageptr += pimage->bytesperpixel; bytecount += pimage->bytesperpixel; break; case 16: case 24: case 32: imageptr[0] = (unsigned char) (dwordcolor >> 24) & 0xFF; imageptr[1] = (unsigned char) (dwordcolor >> 16) & 0xFF; imageptr[2] = (unsigned char) (dwordcolor >> 8) & 0xFF; imageptr[3] = (unsigned char) (dwordcolor & 0xFF); imageptr += pimage->bytesperpixel; bytecount += pimage->bytesperpixel; break; #endif } } /* Pad to the end of the line */ if (bytecount < pimage->pitch) for(i = 0; i < (pimage->pitch - bytecount); i++) *imageptr++ = 0x00; read_xline++; if (read_xline == row) status = LOAD_DONE; continue; } } free(colorheap); if (status != LOAD_DONE) return(-1); return(1); } #endif /* defined(HAVE_FILEIO) && defined(HAVE_XPM_SUPPORT)*/ #endif /* defined(HAVE_FILEIO)*/
Go to most recent revision | Compare with Previous | Blame | View Log