From 64971549fd63d131f136a16913deaec3bdbcf2f3 Mon Sep 17 00:00:00 2001 From: Andrew Hannam Date: Wed, 3 Apr 2013 13:51:43 +1000 Subject: New GDISP image handling with demo Images currently support Native and BMP (except RLE4,8 and 16 bit - due to bugs) Supports reading from Memory, BaseFileStream or real files (only on the Win32 simulator). Move gdisp_pictures demo to better refect its purpose. Bug fixes for BMP RLE4,8 & 16 bit to come very soon GIF support very soon. --- include/gdisp/gdisp.h | 4 + include/gdisp/image.h | 355 ++++++++++++++++++++++++++++++++++++++++++++++++ include/gdisp/options.h | 49 +++++++ 3 files changed, 408 insertions(+) create mode 100644 include/gdisp/image.h (limited to 'include/gdisp') diff --git a/include/gdisp/gdisp.h b/include/gdisp/gdisp.h index 9e408578..85f9b4ea 100644 --- a/include/gdisp/gdisp.h +++ b/include/gdisp/gdisp.h @@ -966,6 +966,10 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); } #endif +#if GDISP_NEED_IMAGE || defined(__DOXYGEN__) + #include "gdisp/image.h" +#endif + #endif /* GFX_USE_GDISP */ #endif /* _GDISP_H */ diff --git a/include/gdisp/image.h b/include/gdisp/image.h new file mode 100644 index 00000000..8e71437b --- /dev/null +++ b/include/gdisp/image.h @@ -0,0 +1,355 @@ +/* + 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 include/gdisp/image.h + * @brief GDISP image header file. + * + * @addtogroup GDISP + * @{ + */ + +#ifndef _GDISP_IMAGE_H +#define _GDISP_IMAGE_H +#if (GFX_USE_GDISP && GDISP_NEED_IMAGE) || defined(__DOXYGEN__) + +/** + * @brief The type of image + */ +typedef uint16_t gdispImageType; + #define GDISP_IMAGE_TYPE_UNKNOWN 0 + #define GDISP_IMAGE_TYPE_NATIVE 1 + #define GDISP_IMAGE_TYPE_GIF 2 + #define GDISP_IMAGE_TYPE_BMP 3 + #define GDISP_IMAGE_TYPE_JPG 4 + #define GDISP_IMAGE_TYPE_PNG 5 + +/** + * @brief An image error code + */ +typedef uint16_t gdispImageError; + #define GDISP_IMAGE_ERR_OK 0 + #define GDISP_IMAGE_ERR_UNRECOVERABLE 0x8000 + #define GDISP_IMAGE_ERR_BADFORMAT (GDISP_IMAGE_ERR_UNRECOVERABLE+1) + #define GDISP_IMAGE_ERR_BADDATA (GDISP_IMAGE_ERR_UNRECOVERABLE+2) + #define GDISP_IMAGE_ERR_UNSUPPORTED (GDISP_IMAGE_ERR_UNRECOVERABLE+3) + #define GDISP_IMAGE_ERR_UNSUPPORTED_OK 3 + #define GDISP_IMAGE_ERR_NOMEMORY (GDISP_IMAGE_ERR_UNRECOVERABLE+4) + +/** + * @brief Image flags + */ +typedef uint16_t gdispImageFlags; + #define GDISP_IMAGE_FLG_TRANSPARENT 0x0001 /* The image has transparency */ + #define GDISP_IMAGE_FLG_ANIMATED 0x0002 /* The image has animation */ + #define GDISP_IMAGE_FLG_MULTIPAGE 0x0004 /* The image has multiple pages */ + +struct gdispImageIO; + +/** + * @brief An image IO close function + * + * @param[in] pio Pointer to the io structure + * @param[in] desc The descriptor. A filename or an image structure pointer. + * + */ +typedef void (*gdispImageIOCloseFn)(struct gdispImageIO *pio); + +/** + * @brief An image IO read function + * @returns The number of bytes actually read or 0 on error + * + * @param[in] pio Pointer to the io structure + * @param[in] buf Where the results should be placed + * @param[in] len The number of bytes to read + * + */ +typedef size_t (*gdispImageIOReadFn)(struct gdispImageIO *pio, void *buf, size_t len); + +/** + * @brief An image IO seek function + * + * @param[in] pio Pointer to the io structure + * @param[in] pos Which byte to seek to relative to the start of the "file". + * + */ +typedef void (*gdispImageIOSeekFn)(struct gdispImageIO *pio, size_t pos); + +typedef struct gdispImageIOFunctions { + gdispImageIOReadFn read; /* @< The function to read input */ + gdispImageIOSeekFn seek; /* @< The function to seek input */ + gdispImageIOCloseFn close; /* @< The function to close input */ + } gdispImageIOFunctions; + +/** + * @brief The structure defining the IO routines for image handling + */ +typedef struct gdispImageIO { + const void * fd; /* @< The "file" descriptor */ + size_t pos; /* @< The current "file" position */ + const gdispImageIOFunctions *fns; /* @< The current "file" functions */ +} gdispImageIO; + +/** + * @brief The structure for an image + */ +typedef struct gdispImage { + gdispImageType type; /* @< The image type */ + gdispImageFlags flags; /* @< The image flags */ + coord_t width, height; /* @< The image dimensions */ + gdispImageIO io; /* @< The image IO functions */ + uint32_t membytes; /* @< How much RAM has been allocated */ + const struct gdispImageHandlers * fns; /* @< Don't mess with this! */ + struct gdispImagePrivate * priv; /* @< Don't mess with this! */ +} gdispImage; + +#ifdef __cplusplus +extern "C" { +#endif + + /** + * @brief Sets the io fields in the image structure to routines + * that support reading from an image stored in RAM or Flash. + * + * @return TRUE if the IO open function succeeds + * + * @param[in] img The image structure + * @param[in] memimage A pointer to the image in RAM or Flash + * + * @note Always returns TRUE for a Memory Reader + */ + bool_t gdispImageSetMemoryReader(gdispImage *img, const char *memimage); + + /** + * @brief Sets the io fields in the image structure to routines + * that support reading from an image stored on a BaseFileStream (eg SDCard). + * + * @return TRUE if the IO open function succeeds + * + * @param[in] img The image structure + * @param[in] BaseFileStreamPtr A pointer to the (open) BaseFileStream object. + * + */ + bool_t gdispImageSetBaseFileStreamReader(gdispImage *img, void *BaseFileStreamPtr); + + #if defined(WIN32) || defined(__DOXYGEN__) + /** + * @brief Sets the io fields in the image structure to routines + * that support reading from an image stored in Win32 simulators native + * file system. + * @pre Only available on the Win32 simulator + * + * @return TRUE if the IO open function succeeds + * + * @param[in] img The image structure + * @param[in] filename The filename to open + * + */ + bool_t gdispImageSetSimulFileReader(gdispImage *img, const char *filename); + #endif + + /** + * @brief Open an image ready for drawing + * @details Determine the image format and get ready to decode the first image frame + * @return GDISP_IMAGE_ERR_OK (0) on success or an error code. + * + * @param[in] img The image structure + * + * @pre The io fields should be filled in before calling gdispImageOpen() + * + * @note This determines which decoder to use and then initialises all other fields + * in the gdispImage structure. + * @note There are three types of return - everything OK, partial success and unrecoverable + * failures. For everything OK it returns GDISP_IMAGE_ERR_OK. A partial success can + * be distinguished from a unrecoverable failure by testing the GDISP_IMAGE_ERR_UNRECOVERABLE + * bit in the error code. + * A partial success return code means an image can still be drawn but perhaps with + * reduced functionality eg only the first page of a multi-page image. + * @note @p gdispImageClose() can be called even after a failure to open the image to ensure + * that the IO close routine gets called. + */ + gdispImageError gdispImageOpen(gdispImage *img); + + /** + * @brief Close an image and release any dynamicly allocated working storage. + * + * @param[in] img The image structure + * + * @pre gdispImageOpen() must have returned successfully. + * + * @note Also calls the IO close function (if it hasn't already been called). + */ + void gdispImageClose(gdispImage *img); + + /** + * @brief Cache the image + * @details Decodes and caches the current frame into RAM. + * @return GDISP_IMAGE_ERR_OK (0) on success or an error code. + * + * @param[in] img The image structure + * + * @pre gdispImageOpen() must have returned successfully. + * + * @note This can use a LOT of RAM! + * @note The decoder may choose to ignore the request for caching. If it does so it will + * return GDISP_IMAGE_ERR_UNSUPPORTED_OK. + * @note A fatal error here does not necessarily mean that drawing the image will fail. For + * example, a GDISP_IMAGE_ERR_NOMEMORY error simply means there isn't enough RAM to + * cache the image. + */ + gdispImageError gdispImageCache(gdispImage *img); + + /** + * @brief Draw the image + * @return GDISP_IMAGE_ERR_OK (0) on success or an error code. + * + * @param[in] img The image structure + * @param[in] x,y The screen location to draw the image + * @param[in] cx,cy The area on the screen to draw + * @param[in] sx,sy The image position to start drawing at + * + * @pre gdispImageOpen() must have returned successfully. + * + * @note If sx,sy + cx,cy is outside the image boundaries the area outside the image + * is simply not drawn. + * @note If @p gdispImageCache() has been called first for this frame, this routine will draw using a + * fast blit from the cached frame. If not, it reads the input and decodes it as it + * is drawing. This may be significantly slower than if the image has been cached (but + * uses a lot less RAM) + */ + gdispImageError gdispImageDraw(gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy); + + /** + * @brief Prepare for the next frame/page in the image file. + * @return A time in milliseconds to keep displaying the current frame before trying to draw + * the next frame. Watch out for the special values TIME_IMMEDIATE and TIME_INFINITE. + * + * @param[in] img The image structure + * + * @pre gdispImageOpen() must have returned successfully. + * + * @note It will return TIME_IMMEDIATE if the first frame/page hasn't been drawn or if the next frame + * should be drawn immediately. + * @note It will return TIME_INFINITE if another image frame doesn't exist or an error has occurred. + * @note Images that support multiple pages (eg TIFF files) will return TIME_IMMEDIATE between pages + * and then TIME_INFINITE when there are no more pages. + * @note An image that displays a looped animation will never return TIME_INFINITE unless it + * gets an error. + * @note Calling gdispImageDraw() after getting a TIME_INFINITE will go back to drawing the first + * frame/page. + */ + systime_t gdispImageNext(gdispImage *img); + + #if GDISP_NEED_IMAGE_NATIVE + /** + * @brief The image drawing routines for a NATIVE format image. + * + * @note Only use these functions if you absolutely know the format + * of the image you are decoding. Generally you should use the + * generic functions and it will auto-detect the format. + * @note A NATIVE format image is defined as an 8 byte header described below, immediately + * followed by the bitmap data. The bitmap data is stored in the native format for + * the display controller. If the pixel format specified in the header does not + * match the controller native format then the image is rejected. + * @note The 8 byte header: + * { 'N', 'I', width.hi, width.lo, height.hi, height.lo, format.hi, format.lo } + * The format word = GDISP_PIXELFORMAT + * @{ + */ + gdispImageError gdispImageOpen_NATIVE(gdispImage *img); + void gdispImageClose_NATIVE(gdispImage *img); + gdispImageError gdispImageCache_NATIVE(gdispImage *img); + gdispImageError gdispImageDraw_NATIVE(gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy); + systime_t gdispImageNext_NATIVE(gdispImage *img); + /* @} */ + #endif + + #if GDISP_NEED_IMAGE_GIF + /** + * @brief The image drawing routines for a GIF image. + * @note Only use these functions if you absolutely know the format + * of the image you are decoding. Generally you should use the + * generic functions and it will auto-detect the format. + * @{ + */ + gdispImageError gdispImageOpen_GIF(gdispImage *img); + void gdispImageClose_GIF(gdispImage *img); + gdispImageError gdispImageCache_GIF(gdispImage *img); + gdispImageError gdispImageDraw_GIF(gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy); + systime_t gdispImageNext_GIF(gdispImage *img); + /* @} */ + #endif + + #if GDISP_NEED_IMAGE_BMP + /** + * @brief The image drawing routines for a BMP image. + * @note Only use these functions if you absolutely know the format + * of the image you are decoding. Generally you should use the + * generic functions and it will auto-detect the format. + * @{ + */ + gdispImageError gdispImageOpen_BMP(gdispImage *img); + void gdispImageClose_BMP(gdispImage *img); + gdispImageError gdispImageCache_BMP(gdispImage *img); + gdispImageError gdispImageDraw_BMP(gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy); + systime_t gdispImageNext_BMP(gdispImage *img); + /* @} */ + #endif + + #if GDISP_NEED_IMAGE_JPG + /** + * @brief The image drawing routines for a JPG image. + * @note Only use these functions if you absolutely know the format + * of the image you are decoding. Generally you should use the + * generic functions and it will auto-detect the format. + * @{ + */ + gdispImageError gdispImageOpen_JPG(gdispImage *img); + void gdispImageClose_JPG(gdispImage *img); + gdispImageError gdispImageCache_JPG(gdispImage *img); + gdispImageError gdispImageDraw_JPG(gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy); + systime_t gdispImageNext_JPG(gdispImage *img); + /* @} */ + #endif + + #if GDISP_NEED_IMAGE_PNG + /** + * @brief The image drawing routines for a PNG image. + * @note Only use these functions if you absolutely know the format + * of the image you are decoding. Generally you should use the + * generic functions and it will auto-detect the format. + * @{ + */ + gdispImageError gdispImageOpen_PNG(gdispImage *img); + void gdispImageClose_PNG(gdispImage *img); + gdispImageError gdispImageCache_PNG(gdispImage *img); + gdispImageError gdispImageDraw_PNG(gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy); + systime_t gdispImageNext_PNG(gdispImage *img); + /* @} */ + #endif + +#ifdef __cplusplus +} +#endif + +#endif /* GFX_USE_GDISP && GDISP_NEED_IMAGE */ +#endif /* _GDISP_IMAGE_H */ +/** @} */ + diff --git a/include/gdisp/options.h b/include/gdisp/options.h index 78e48a0a..deacc036 100644 --- a/include/gdisp/options.h +++ b/include/gdisp/options.h @@ -130,6 +130,13 @@ #ifndef GDISP_NEED_QUERY #define GDISP_NEED_QUERY FALSE #endif + /** + * @brief Is the image interface required. + * @details Defaults to FALSE + */ + #ifndef GDISP_NEED_IMAGE + #define GDISP_NEED_IMAGE FALSE + #endif /** * @brief Is the messaging api interface required. * @details Defaults to FALSE @@ -137,6 +144,48 @@ #ifndef GDISP_NEED_MSGAPI #define GDISP_NEED_MSGAPI FALSE #endif +/** + * @} + * + * @name GDISP Image Options + * @pre GDISP_NEED_IMAGE must be TRUE + * @{ + */ + /** + * @brief Is native image decoding required. + * @details Defaults to FALSE + */ + #ifndef GDISP_NEED_IMAGE_NATIVE + #define GDISP_NEED_IMAGE_NATIVE FALSE + #endif + /** + * @brief Is GIF image decoding required. + * @details Defaults to FALSE + */ + #ifndef GDISP_NEED_IMAGE_GIF + #define GDISP_NEED_IMAGE_GIF FALSE + #endif + /** + * @brief Is BMP image decoding required. + * @details Defaults to FALSE + */ + #ifndef GDISP_NEED_IMAGE_BMP + #define GDISP_NEED_IMAGE_BMP FALSE + #endif + /** + * @brief Is JPG image decoding required. + * @details Defaults to FALSE + */ + #ifndef GDISP_NEED_IMAGE_JPG + #define GDISP_NEED_IMAGE_JPG FALSE + #endif + /** + * @brief Is PNG image decoding required. + * @details Defaults to FALSE + */ + #ifndef GDISP_NEED_IMAGE_PNG + #define GDISP_NEED_IMAGE_PNG FALSE + #endif /** * @} * -- cgit v1.2.3