📄 devimage.c
字号:
#define FASTJPEG 1 /* =1 for temp quick jpeg 8bpp display */
#ifdef __ECOS
// Why isn't this handled in the global config file?
#undef HAVE_MMAP
#else
#define HAVE_MMAP 1 /* =1 to use mmap if available */
#endif
#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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -