/* ChibiOS/GFX - Copyright (C) 2012, 2013 Joel Bodenmann aka Tectu This file is part of ChibiOS/GFX. ChibiOS/GFX is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. ChibiOS/GFX 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /** * @file src/gdisp/image.c * @brief GDISP generic image code. */ #include "ch.h" #include "hal.h" #include "gfx.h" #if GFX_USE_GDISP && GDISP_NEED_IMAGE /* The structure defining the routines for image drawing */ typedef struct gdispImageHandlers { gdispImageError (*open)(gdispImage *img); /* The open function */ void (*close)(gdispImage *img); /* The close function */ gdispImageError (*cache)(gdispImage *img); /* The cache function */ gdispImageError (*draw)(gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy); /* The draw function */ systime_t (*next)(gdispImage *img); /* The next frame function */ } gdispImageHandlers; static gdispImageHandlers ImageHandlers[] = { #if GDISP_NEED_IMAGE_NATIVE { gdispImageOpen_NATIVE, gdispImageClose_NATIVE, gdispImageCache_NATIVE, gdispImageDraw_NATIVE, gdispImageNext_NATIVE, }, #endif #if GDISP_NEED_IMAGE_GIF { gdispImageOpen_GIF, gdispImageClose_GIF, gdispImageCache_GIF, gdispImageDraw_GIF, gdispImageNext_GIF, }, #endif #if GDISP_NEED_IMAGE_BMP { gdispImageOpen_BMP, gdispImageClose_BMP, gdispImageCache_BMP, gdispImageDraw_BMP, gdispImageNext_BMP, }, #endif #if GDISP_NEED_IMAGE_JPG { gdispImageOpen_JPG, gdispImageClose_JPG, gdispImageCache_JPG, gdispImageDraw_JPG, gdispImageNext_JPG, }, #endif #if GDISP_NEED_IMAGE_PNG { gdispImageOpen_PNG, gdispImageClose_PNG, gdispImageCache_PNG, gdispImageDraw_PNG, gdispImageNext_PNG, }, #endif }; static size_t ImageMemoryRead(struct gdispImageIO *pio, void *buf, size_t len) { if (pio->fd == (void *)-1) return 0; memcpy(buf, ((const char *)pio->fd)+pio->pos, len); pio->pos += len; return len; } static void ImageMemorySeek(struct gdispImageIO *pio, size_t pos) { if (pio->fd == (void *)-1) return; pio->pos = pos; } static void ImageMemoryClose(struct gdispImageIO *pio) { pio->fd = (void *)-1; pio->pos = 0; } static const gdispImageIOFunctions ImageMemoryFunctions = { ImageMemoryRead, ImageMemorySeek, ImageMemoryClose }; bool_t gdispImageSetMemoryReader(gdispImage *img, const void *memimage) { img->io.fns = &ImageMemoryFunctions; img->io.pos = 0; img->io.fd = memimage; return TRUE; } static size_t ImageBaseFileStreamRead(struct gdispImageIO *pio, void *buf, size_t len) { if (pio->fd == (void *)-1) return 0; len = chSequentialStreamRead(((BaseFileStream *)pio->fd), (uint8_t *)buf, len); pio->pos += len; return len; } static void ImageBaseFileStreamSeek(struct gdispImageIO *pio, size_t pos) { if (pio->fd == (void *)-1) return; if (pio->pos != pos) { chFileStreamSeek(((BaseFileStream *)pio->fd), pos); pio->pos = pos; } } static void ImageBaseFileStreamClose(struct gdispImageIO *pio) { if (pio->fd == (void *)-1) return; chFileStreamClose(((BaseFileStream *)pio->fd)); pio->fd = (void *)-1; pio->pos = 0; } static const gdispImageIOFunctions ImageBaseFileStreamFunctions = { ImageBaseFileStreamRead, ImageBaseFileStreamSeek, ImageBaseFileStreamClose }; bool_t gdispImageSetBaseFileStreamReader(gdispImage *img, void *BaseFileStreamPtr) { img->io.fns = &ImageBaseFileStreamFunctions; img->io.pos = 0; img->io.fd = BaseFileStreamPtr; return TRUE; } #if defined(WIN32) #include static size_t ImageSimulFileRead(struct gdispImageIO *pio, void *buf, size_t len) { if (pio->fd == (void *)-1) return 0; len = read((int)pio->fd, buf, len); if ((int)len < 0) len = 0; pio->pos += len; return len; } static void ImageSimulFileSeek(struct gdispImageIO *pio, size_t pos) { if (pio->fd == (void *)-1) return; if (pio->pos != pos) { lseek((int)pio->fd, pos, SEEK_SET); pio->pos = pos; } } static void ImageSimulFileClose(struct gdispImageIO *pio) { if (pio->fd == (void *)-1) return; close((int)pio->fd); pio->fd = (void *)-1; pio->pos = 0; } static const gdispImageIOFunctions ImageSimulFileFunctions = { ImageSimulFileRead, ImageSimulFileSeek, ImageSimulFileClose }; bool_t gdispImageSetSimulFileReader(gdispImage *img, const char *filename) { img->io.fns = &ImageSimulFileFunctions; img->io.pos = 0; img->io.fd = (void *)open(filename, O_RDONLY|O_BINARY); return img->io.fd != (void *)-1; } #endif gdispImageError gdispImageOpen(gdispImage *img) { gdispImageError err; img->bgcolor = White; for(img->fns = ImageHandlers; img->fns < ImageHandlers+sizeof(ImageHandlers)/sizeof(ImageHandlers[0]); img->fns++) { err = img->fns->open(img); if (err != GDISP_IMAGE_ERR_BADFORMAT) { if ((err & GDISP_IMAGE_ERR_UNRECOVERABLE)) img->fns = 0; return err; } img->io.fns->seek(&img->io, 0); } img->type = GDISP_IMAGE_TYPE_UNKNOWN; img->flags = 0; img->fns = 0; img->priv = 0; return GDISP_IMAGE_ERR_BADFORMAT; } void gdispImageClose(gdispImage *img) { if (img->fns) img->fns->close(img); else img->io.fns->close(&img->io); } void gdispImageSetBgColor(gdispImage *img, color_t bgcolor) { img->bgcolor = bgcolor; } gdispImageError gdispImageCache(gdispImage *img) { if (!img->fns) return GDISP_IMAGE_ERR_BADFORMAT; return img->fns->cache(img); } gdispImageError gdispImageDraw(gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy) { if (!img->fns) return GDISP_IMAGE_ERR_BADFORMAT; return img->fns->draw(img, x, y, cx, cy, sx, sy); } systime_t gdispImageNext(gdispImage *img) { if (!img->fns) return GDISP_IMAGE_ERR_BADFORMAT; return img->fns->next(img); } // Helper Routines void *gdispImageAlloc(gdispImage *img, size_t sz) { #if GDISP_NEED_IMAGE_ACCOUNTING void *ptr; ptr = chHeapAlloc(NULL, sz); if (ptr) { img->memused += sz; if (img->memused > img->maxmemused) img->maxmemused = img->memused; } return ptr; #else (void) img; return chHeapAlloc(NULL, sz); #endif } void gdispImageFree(gdispImage *img, void *ptr, size_t sz) { #if GDISP_NEED_IMAGE_ACCOUNTING chHeapFree(ptr); img->memused -= sz; #else (void) img; (void) sz; chHeapFree(ptr); #endif } #endif /* GFX_USE_GDISP && GDISP_NEED_IMAGE */ /** @} */