📄 devimage.c
字号:
#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 voidbinit(void *in, int size, buffer_t *dest){ dest->start = in; dest->offset = 0; dest->size = size;} static intbseek(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 intbread(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 intbgetc(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 intbeof(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);intGdLoadImageFromBuffer(PSD psd, void *buffer, int size, int flags){ buffer_t src; binit(buffer, size, &src); return(GdDecodeImage(psd, &src, flags));}voidGdDrawImageFromBuffer(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); }}voidGdDrawImageFromFile(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); }}intGdLoadImageFromFile(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 || fstat(fd, &s) < 0) { EPRINTF("GdLoadImageFromFile: can't open image: %s\n", path); return(0); } #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 intGdDecodeImage(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"); 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 PIMAGEITEMfindimage(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;}voidGdDrawImageToFit(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);}voidGdFreeImage(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); }}MWBOOLGdGetImageInfo(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 voidComputePitch(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.*/voidGdStretchImage(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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -