Merge pull request #51 from inmarket/master
GDISP Image support with Demo
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
56
demos/modules/gdisp/gdisp_images/gfxconf.h
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/**
|
||||||
|
* This file has a different license to the rest of the GFX system.
|
||||||
|
* You can copy, modify and distribute this file as you see fit.
|
||||||
|
* You do not need to publish your source modifications to this file.
|
||||||
|
* The only thing you are not permitted to do is to relicense it
|
||||||
|
* under a different license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _GFXCONF_H
|
||||||
|
#define _GFXCONF_H
|
||||||
|
|
||||||
|
/* GFX sub-systems to turn on */
|
||||||
|
#define GFX_USE_GDISP TRUE
|
||||||
|
#define GFX_USE_GWIN FALSE
|
||||||
|
#define GFX_USE_GEVENT FALSE
|
||||||
|
#define GFX_USE_GTIMER FALSE
|
||||||
|
#define GFX_USE_GINPUT FALSE
|
||||||
|
|
||||||
|
/* Features for the GDISP sub-system. */
|
||||||
|
#define GDISP_NEED_VALIDATION TRUE
|
||||||
|
#define GDISP_NEED_CLIP TRUE
|
||||||
|
#define GDISP_NEED_TEXT FALSE
|
||||||
|
#define GDISP_NEED_CIRCLE FALSE
|
||||||
|
#define GDISP_NEED_ELLIPSE FALSE
|
||||||
|
#define GDISP_NEED_ARC FALSE
|
||||||
|
#define GDISP_NEED_CONVEX_POLYGON FALSE
|
||||||
|
#define GDISP_NEED_SCROLL FALSE
|
||||||
|
#define GDISP_NEED_PIXELREAD FALSE
|
||||||
|
#define GDISP_NEED_CONTROL FALSE
|
||||||
|
#define GDISP_NEED_IMAGE TRUE
|
||||||
|
#define GDISP_NEED_MULTITHREAD FALSE
|
||||||
|
#define GDISP_NEED_ASYNC FALSE
|
||||||
|
#define GDISP_NEED_MSGAPI FALSE
|
||||||
|
|
||||||
|
/* Builtin Fonts */
|
||||||
|
#define GDISP_INCLUDE_FONT_SMALL FALSE
|
||||||
|
#define GDISP_INCLUDE_FONT_LARGER FALSE
|
||||||
|
#define GDISP_INCLUDE_FONT_UI1 FALSE
|
||||||
|
#define GDISP_INCLUDE_FONT_UI2 FALSE
|
||||||
|
#define GDISP_INCLUDE_FONT_LARGENUMBERS FALSE
|
||||||
|
|
||||||
|
/* GDISP image decoders */
|
||||||
|
#define GDISP_NEED_IMAGE_NATIVE FALSE
|
||||||
|
#define GDISP_NEED_IMAGE_GIF FALSE
|
||||||
|
#define GDISP_NEED_IMAGE_BMP TRUE
|
||||||
|
#define GDISP_NEED_IMAGE_JPG FALSE
|
||||||
|
#define GDISP_NEED_IMAGE_PNG FALSE
|
||||||
|
|
||||||
|
/* Features for the GWIN sub-system. */
|
||||||
|
#define GWIN_NEED_BUTTON FALSE
|
||||||
|
#define GWIN_NEED_CONSOLE FALSE
|
||||||
|
|
||||||
|
/* Features for the GINPUT sub-system. */
|
||||||
|
#define GINPUT_NEED_MOUSE FALSE
|
||||||
|
|
||||||
|
#endif /* _GFXCONF_H */
|
52
demos/modules/gdisp/gdisp_images/main.c
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/GFX - Copyright (C) 2012, 2013
|
||||||
|
Joel Bodenmann aka Tectu <joel@unormal.org>
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ch.h"
|
||||||
|
#include "hal.h"
|
||||||
|
#include "gfx.h"
|
||||||
|
|
||||||
|
static gdispImage myImage;
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
coord_t swidth, sheight;
|
||||||
|
|
||||||
|
halInit(); // Initialise the Hardware
|
||||||
|
chSysInit(); // Initialize the OS
|
||||||
|
gdispInit(); // Initialize the display
|
||||||
|
|
||||||
|
gdispClear(Black);
|
||||||
|
|
||||||
|
// Get the display dimensions
|
||||||
|
swidth = gdispGetWidth();
|
||||||
|
sheight = gdispGetHeight();
|
||||||
|
|
||||||
|
// Set up IO for our image
|
||||||
|
gdispImageSetSimulFileReader(&myImage, "test-pal8.bmp");
|
||||||
|
|
||||||
|
gdispImageOpen(&myImage);
|
||||||
|
gdispImageDraw(&myImage, 0, 0, swidth, sheight, 0, 0);
|
||||||
|
gdispImageClose(&myImage);
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
chThdSleepMilliseconds(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
BIN
demos/modules/gdisp/gdisp_images/results_650x493.png
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
demos/modules/gdisp/gdisp_images/test-pal8.bmp
Normal file
After Width: | Height: | Size: 9 KiB |
|
@ -38,16 +38,36 @@
|
||||||
#define GDISP_NEED_PIXELREAD FALSE
|
#define GDISP_NEED_PIXELREAD FALSE
|
||||||
#define GDISP_NEED_CONTROL FALSE
|
#define GDISP_NEED_CONTROL FALSE
|
||||||
#define GDISP_NEED_QUERY FALSE
|
#define GDISP_NEED_QUERY FALSE
|
||||||
|
#define GDISP_NEED_IMAGE FALSE
|
||||||
#define GDISP_NEED_MULTITHREAD FALSE
|
#define GDISP_NEED_MULTITHREAD FALSE
|
||||||
#define GDISP_NEED_ASYNC FALSE
|
#define GDISP_NEED_ASYNC FALSE
|
||||||
#define GDISP_NEED_MSGAPI FALSE
|
#define GDISP_NEED_MSGAPI FALSE
|
||||||
|
|
||||||
/* GDISP - builtin fonts */
|
/* GDISP - builtin fonts */
|
||||||
#define GDISP_INCLUDE_FONT_SMALL TRUE
|
#define GDISP_INCLUDE_FONT_SMALL FALSE
|
||||||
#define GDISP_INCLUDE_FONT_LARGER TRUE
|
#define GDISP_INCLUDE_FONT_LARGER FALSE
|
||||||
#define GDISP_INCLUDE_FONT_UI1 TRUE
|
#define GDISP_INCLUDE_FONT_UI1 FALSE
|
||||||
#define GDISP_INCLUDE_FONT_UI2 TRUE
|
#define GDISP_INCLUDE_FONT_UI2 TRUE
|
||||||
#define GDISP_INCLUDE_FONT_LARGENUMBERS TRUE
|
#define GDISP_INCLUDE_FONT_LARGENUMBERS FALSE
|
||||||
|
|
||||||
|
/* GDISP image decoders */
|
||||||
|
#define GDISP_NEED_IMAGE_NATIVE FALSE
|
||||||
|
#define GDISP_NEED_IMAGE_GIF FALSE
|
||||||
|
#define GDISP_NEED_IMAGE_BMP FALSE
|
||||||
|
#define GDISP_NEED_IMAGE_JPG FALSE
|
||||||
|
#define GDISP_NEED_IMAGE_PNG FALSE
|
||||||
|
|
||||||
|
/* Optional image support that can be turned off */
|
||||||
|
/*
|
||||||
|
#define GDISP_NEED_IMAGE_BMP_1 TRUE
|
||||||
|
#define GDISP_NEED_IMAGE_BMP_4 TRUE
|
||||||
|
#define GDISP_NEED_IMAGE_BMP_4_RLE TRUE
|
||||||
|
#define GDISP_NEED_IMAGE_BMP_8 TRUE
|
||||||
|
#define GDISP_NEED_IMAGE_BMP_8_RLE TRUE
|
||||||
|
#define GDISP_NEED_IMAGE_BMP_16 TRUE
|
||||||
|
#define GDISP_NEED_IMAGE_BMP_24 TRUE
|
||||||
|
#define GDISP_NEED_IMAGE_BMP_32 TRUE
|
||||||
|
*/
|
||||||
|
|
||||||
/* Features for the TDISP subsystem. */
|
/* Features for the TDISP subsystem. */
|
||||||
#define TDISP_NEED_MULTITHREAD FALSE
|
#define TDISP_NEED_MULTITHREAD FALSE
|
||||||
|
|
|
@ -966,6 +966,10 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if GDISP_NEED_IMAGE || defined(__DOXYGEN__)
|
||||||
|
#include "gdisp/image.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* GFX_USE_GDISP */
|
#endif /* GFX_USE_GDISP */
|
||||||
|
|
||||||
#endif /* _GDISP_H */
|
#endif /* _GDISP_H */
|
||||||
|
|
355
include/gdisp/image.h
Normal file
|
@ -0,0 +1,355 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/GFX - Copyright (C) 2012, 2013
|
||||||
|
Joel Bodenmann aka Tectu <joel@unormal.org>
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 */
|
||||||
|
/** @} */
|
||||||
|
|
|
@ -130,6 +130,13 @@
|
||||||
#ifndef GDISP_NEED_QUERY
|
#ifndef GDISP_NEED_QUERY
|
||||||
#define GDISP_NEED_QUERY FALSE
|
#define GDISP_NEED_QUERY FALSE
|
||||||
#endif
|
#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.
|
* @brief Is the messaging api interface required.
|
||||||
* @details Defaults to FALSE
|
* @details Defaults to FALSE
|
||||||
|
@ -137,6 +144,48 @@
|
||||||
#ifndef GDISP_NEED_MSGAPI
|
#ifndef GDISP_NEED_MSGAPI
|
||||||
#define GDISP_NEED_MSGAPI FALSE
|
#define GDISP_NEED_MSGAPI FALSE
|
||||||
#endif
|
#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
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,2 +1,9 @@
|
||||||
GFXSRC += $(GFXLIB)/src/gdisp/gdisp.c \
|
GFXSRC += $(GFXLIB)/src/gdisp/gdisp.c \
|
||||||
$(GFXLIB)/src/gdisp/fonts.c
|
$(GFXLIB)/src/gdisp/fonts.c \
|
||||||
|
$(GFXLIB)/src/gdisp/image.c \
|
||||||
|
$(GFXLIB)/src/gdisp/image_native.c \
|
||||||
|
$(GFXLIB)/src/gdisp/image_gif.c \
|
||||||
|
$(GFXLIB)/src/gdisp/image_bmp.c \
|
||||||
|
$(GFXLIB)/src/gdisp/image_jpg.c \
|
||||||
|
$(GFXLIB)/src/gdisp/image_png.c
|
||||||
|
|
210
src/gdisp/image.c
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/GFX - Copyright (C) 2012, 2013
|
||||||
|
Joel Bodenmann aka Tectu <joel@unormal.org>
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 char *memimage) {
|
||||||
|
img->io.fns = &ImageMemoryFunctions;
|
||||||
|
img->io.pos = 0;
|
||||||
|
img->io.fd = (void *)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 <fcntl.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* GFX_USE_GDISP && GDISP_NEED_IMAGE */
|
||||||
|
/** @} */
|
912
src/gdisp/image_bmp.c
Normal file
|
@ -0,0 +1,912 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/GFX - Copyright (C) 2012, 2013
|
||||||
|
Joel Bodenmann aka Tectu <joel@unormal.org>
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file src/gdisp/image_bmp.c
|
||||||
|
* @brief GDISP native image code.
|
||||||
|
*/
|
||||||
|
#include "ch.h"
|
||||||
|
#include "hal.h"
|
||||||
|
#include "gfx.h"
|
||||||
|
|
||||||
|
#if GFX_USE_GDISP && GDISP_NEED_IMAGE && GDISP_NEED_IMAGE_BMP
|
||||||
|
|
||||||
|
#ifndef GDISP_NEED_IMAGE_BMP_1
|
||||||
|
#define GDISP_NEED_IMAGE_BMP_1 TRUE
|
||||||
|
#endif
|
||||||
|
#ifndef GDISP_NEED_IMAGE_BMP_4
|
||||||
|
#define GDISP_NEED_IMAGE_BMP_4 TRUE
|
||||||
|
#endif
|
||||||
|
#ifndef GDISP_NEED_IMAGE_BMP_4_RLE
|
||||||
|
#define GDISP_NEED_IMAGE_BMP_4_RLE FALSE // Currently Broken
|
||||||
|
#endif
|
||||||
|
#ifndef GDISP_NEED_IMAGE_BMP_8
|
||||||
|
#define GDISP_NEED_IMAGE_BMP_8 TRUE
|
||||||
|
#endif
|
||||||
|
#ifndef GDISP_NEED_IMAGE_BMP_8_RLE
|
||||||
|
#define GDISP_NEED_IMAGE_BMP_8_RLE FALSE // Currently Broken
|
||||||
|
#endif
|
||||||
|
#ifndef GDISP_NEED_IMAGE_BMP_16
|
||||||
|
#define GDISP_NEED_IMAGE_BMP_16 FALSE // Currently Broken
|
||||||
|
#endif
|
||||||
|
#ifndef GDISP_NEED_IMAGE_BMP_24
|
||||||
|
#define GDISP_NEED_IMAGE_BMP_24 TRUE
|
||||||
|
#endif
|
||||||
|
#ifndef GDISP_NEED_IMAGE_BMP_32
|
||||||
|
#define GDISP_NEED_IMAGE_BMP_32 TRUE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How big a pixel array to allocate for blitting (in pixels)
|
||||||
|
* Bigger is faster but uses more RAM.
|
||||||
|
* This must be greater than 40 bytes and 32 pixels as we read our headers into this space as well
|
||||||
|
*/
|
||||||
|
#define BLIT_BUFFER_SIZE 32
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determining endianness as at compile time is not guaranteed or compiler portable.
|
||||||
|
* We use the best test we can. If we can't guarantee little endianness we do things the
|
||||||
|
* hard way.
|
||||||
|
*/
|
||||||
|
#define GUARANTEED_LITTLE_ENDIAN (!defined(SAFE_ENDIAN) && !defined(SAFE_ALIGNMENT) && (\
|
||||||
|
(defined(__BYTE_ORDER__)&&(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) \
|
||||||
|
|| defined(__LITTLE_ENDIAN__) \
|
||||||
|
|| defined(__LITTLE_ENDIAN) \
|
||||||
|
|| defined(_LITTLE_ENDIAN) \
|
||||||
|
/* || (1 == *(unsigned char *)&(const int){1})*/ \
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
/* This is a runtime test */
|
||||||
|
static const uint8_t dwordOrder[4] = { 1, 2, 3, 4 };
|
||||||
|
|
||||||
|
#define isWordLittleEndian() (*(uint16_t *)&dwordOrder == 0x0201)
|
||||||
|
#define isDWordLittleEndian() (*(uint32_t *)&dwordOrder == 0x04030201)
|
||||||
|
|
||||||
|
#if GUARANTEED_LITTLE_ENDIAN
|
||||||
|
/* These are fast routines for guaranteed little endian machines */
|
||||||
|
#define CONVERT_FROM_WORD_LE(w)
|
||||||
|
#define CONVERT_FROM_DWORD_LE(dw)
|
||||||
|
#else
|
||||||
|
/* These are slower routines for when little endianness cannot be guaranteed at compile time */
|
||||||
|
#define CONVERT_FROM_WORD_LE(w) { if (!isWordLittleEndian()) w = ((((uint16_t)(w))>>8)|(((uint16_t)(w))<<8)); }
|
||||||
|
#define CONVERT_FROM_DWORD_LE(dw) { if (!isDWordLittleEndian()) dw = (((uint32_t)(((const uint8_t *)(&dw))[0]))|(((uint32_t)(((const uint8_t *)(&dw))[1]))<<8)|(((uint32_t)(((const uint8_t *)(&dw))[2]))<<16)|(((uint32_t)(((const uint8_t *)(&dw))[3]))<<24)); }
|
||||||
|
#endif
|
||||||
|
#define CONVERT_FROM_WORD_BE(w) { if (isWordLittleEndian()) w = ((((uint16_t)(w))>>8)|(((uint16_t)(w))<<8)); }
|
||||||
|
|
||||||
|
typedef struct gdispImagePrivate {
|
||||||
|
uint8_t bmpflags;
|
||||||
|
#define BMP_V2 0x01 // Version 2 (old) header format
|
||||||
|
#define BMP_V4 0x02 // Version 4 (alpha support) header format
|
||||||
|
#define BMP_PALETTE 0x04 // Uses a palette
|
||||||
|
#define BMP_COMP_RLE 0x08 // Uses RLE compression
|
||||||
|
#define BMP_COMP_MASK 0x10 // Uses mask & shift decoding
|
||||||
|
#define BMP_RLE_ENC 0x20 // Currently in RLE encoded run
|
||||||
|
#define BMP_RLE_ABS 0x40 // Currently in RLE absolute run
|
||||||
|
#define BMP_TOP_TO_BOTTOM 0x80 // Decodes bottom to top line
|
||||||
|
uint8_t bitsperpixel;
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_1 || GDISP_NEED_IMAGE_BMP_4 || GDISP_NEED_IMAGE_BMP_4_RLE || GDISP_NEED_IMAGE_BMP_8 || GDISP_NEED_IMAGE_BMP_8_RLE
|
||||||
|
uint16_t palsize;
|
||||||
|
pixel_t *palette;
|
||||||
|
#endif
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_4_RLE || GDISP_NEED_IMAGE_BMP_8_RLE
|
||||||
|
uint16_t rlerun;
|
||||||
|
uint8_t rlecode;
|
||||||
|
#endif
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_16 || GDISP_NEED_IMAGE_BMP_32
|
||||||
|
int8_t shiftred;
|
||||||
|
int8_t shiftgreen;
|
||||||
|
int8_t shiftblue;
|
||||||
|
int8_t shiftalpha;
|
||||||
|
uint32_t maskred;
|
||||||
|
uint32_t maskgreen;
|
||||||
|
uint32_t maskblue;
|
||||||
|
uint32_t maskalpha;
|
||||||
|
#endif
|
||||||
|
size_t frame0pos;
|
||||||
|
pixel_t *frame0cache;
|
||||||
|
pixel_t buf[BLIT_BUFFER_SIZE];
|
||||||
|
} gdispImagePrivate;
|
||||||
|
|
||||||
|
gdispImageError gdispImageOpen_BMP(gdispImage *img) {
|
||||||
|
gdispImagePrivate *priv;
|
||||||
|
uint8_t hdr[2];
|
||||||
|
uint16_t aword;
|
||||||
|
uint32_t adword;
|
||||||
|
uint32_t offsetColorTable;
|
||||||
|
|
||||||
|
/* Read the file identifier */
|
||||||
|
if (img->io.fns->read(&img->io, hdr, 2) != 2)
|
||||||
|
return GDISP_IMAGE_ERR_BADFORMAT; // It can't be us
|
||||||
|
|
||||||
|
/* Process the BITMAPFILEHEADER structure */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We only accept Windows V2+ bitmaps.
|
||||||
|
* - we don't support OS/2 bitmaps, icons, pointers, or Windows V1 bitmaps.
|
||||||
|
*/
|
||||||
|
if (hdr[0] != 'B' || hdr[1] != 'M')
|
||||||
|
return GDISP_IMAGE_ERR_BADFORMAT; // It can't be us
|
||||||
|
|
||||||
|
/* We know we are a BMP format image */
|
||||||
|
img->flags = 0;
|
||||||
|
|
||||||
|
/* Allocate our private area */
|
||||||
|
if (!(img->priv = (gdispImagePrivate *)chHeapAlloc(NULL, sizeof(gdispImagePrivate))))
|
||||||
|
return GDISP_IMAGE_ERR_NOMEMORY;
|
||||||
|
img->membytes = sizeof(gdispImagePrivate);
|
||||||
|
|
||||||
|
/* Initialise the essential bits in the private area */
|
||||||
|
priv = img->priv;
|
||||||
|
priv->frame0cache = 0;
|
||||||
|
priv->bmpflags = 0;
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_1 || GDISP_NEED_IMAGE_BMP_4 || GDISP_NEED_IMAGE_BMP_4_RLE || GDISP_NEED_IMAGE_BMP_8 || GDISP_NEED_IMAGE_BMP_8_RLE
|
||||||
|
priv->palette = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Skip the size field and the 2 reserved fields */
|
||||||
|
if (img->io.fns->read(&img->io, priv->buf, 8) != 8)
|
||||||
|
goto baddatacleanup;
|
||||||
|
|
||||||
|
/* Get the offset to the bitmap data */
|
||||||
|
if (img->io.fns->read(&img->io, &priv->frame0pos, 4) != 4)
|
||||||
|
goto baddatacleanup;
|
||||||
|
CONVERT_FROM_DWORD_LE(priv->frame0pos);
|
||||||
|
|
||||||
|
/* Process the BITMAPCOREHEADER structure */
|
||||||
|
|
||||||
|
/* Get the offset to the colour data */
|
||||||
|
if (img->io.fns->read(&img->io, &offsetColorTable, 4) != 4)
|
||||||
|
goto baddatacleanup;
|
||||||
|
CONVERT_FROM_DWORD_LE(offsetColorTable);
|
||||||
|
offsetColorTable += 14; // Add the size of the BITMAPFILEHEADER
|
||||||
|
|
||||||
|
// Detect our bitmap version
|
||||||
|
if (offsetColorTable == 12+14) {
|
||||||
|
img->priv->bmpflags |= BMP_V2;
|
||||||
|
|
||||||
|
// Read the header
|
||||||
|
if (img->io.fns->read(&img->io, priv->buf, 12-4) != 12-4)
|
||||||
|
goto baddatacleanup;
|
||||||
|
// Get the width
|
||||||
|
img->width = *(uint16_t *)(((uint8_t *)priv->buf)+0);
|
||||||
|
CONVERT_FROM_WORD_LE(img->width);
|
||||||
|
// Get the height
|
||||||
|
img->height = *(uint16_t *)(((uint8_t *)priv->buf)+2);
|
||||||
|
CONVERT_FROM_WORD_LE(img->height);
|
||||||
|
if (img->height < 0) {
|
||||||
|
img->priv->bmpflags |= BMP_TOP_TO_BOTTOM;
|
||||||
|
img->height = -img->height;
|
||||||
|
}
|
||||||
|
// Get the planes
|
||||||
|
aword = *(uint16_t *)(((uint8_t *)priv->buf)+4);
|
||||||
|
CONVERT_FROM_WORD_LE(aword);
|
||||||
|
if (aword != 1)
|
||||||
|
goto unsupportedcleanup;
|
||||||
|
// Get the bits per pixel
|
||||||
|
aword = *(uint16_t *)(((uint8_t *)priv->buf)+6);
|
||||||
|
CONVERT_FROM_WORD_LE(aword);
|
||||||
|
switch(aword) {
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_1
|
||||||
|
case 1:
|
||||||
|
#endif
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_4
|
||||||
|
case 4:
|
||||||
|
#endif
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_8
|
||||||
|
case 8:
|
||||||
|
#endif
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_1 || GDISP_NEED_IMAGE_BMP_4 || GDISP_NEED_IMAGE_BMP_8
|
||||||
|
priv->bmpflags |= BMP_PALETTE;
|
||||||
|
priv->palsize = 1<<aword;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_24
|
||||||
|
case 24:
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
goto unsupportedcleanup;
|
||||||
|
}
|
||||||
|
priv->bitsperpixel = aword;
|
||||||
|
|
||||||
|
} else if (offsetColorTable >= 40+14) {
|
||||||
|
if (offsetColorTable > 40+14)
|
||||||
|
priv->bmpflags |= BMP_V4;
|
||||||
|
|
||||||
|
// Read the header
|
||||||
|
if (img->io.fns->read(&img->io, priv->buf, 40-4) != 40-4)
|
||||||
|
goto baddatacleanup;
|
||||||
|
// Get the width
|
||||||
|
adword = *(uint32_t *)(((uint8_t *)priv->buf)+0);
|
||||||
|
CONVERT_FROM_DWORD_LE(adword);
|
||||||
|
if (adword > 32768) // This also picks up negative values
|
||||||
|
goto unsupportedcleanup;
|
||||||
|
img->width = adword;
|
||||||
|
// Get the height
|
||||||
|
adword = *(uint32_t *)(((uint8_t *)priv->buf)+4);
|
||||||
|
CONVERT_FROM_DWORD_LE(adword);
|
||||||
|
if ((int32_t)adword < 0) { // Negative test
|
||||||
|
priv->bmpflags |= BMP_TOP_TO_BOTTOM;
|
||||||
|
adword = -adword;
|
||||||
|
}
|
||||||
|
if (adword > 32768)
|
||||||
|
goto unsupportedcleanup;
|
||||||
|
img->height = adword;
|
||||||
|
// Get the planes
|
||||||
|
aword = *(uint16_t *)(((uint8_t *)priv->buf)+8);
|
||||||
|
CONVERT_FROM_WORD_LE(aword);
|
||||||
|
if (aword != 1)
|
||||||
|
goto unsupportedcleanup;
|
||||||
|
// Get the bits per pixel
|
||||||
|
aword = *(uint16_t *)(((uint8_t *)priv->buf)+10);
|
||||||
|
CONVERT_FROM_WORD_LE(aword);
|
||||||
|
switch(aword) {
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_1
|
||||||
|
case 1:
|
||||||
|
#endif
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_4 || GDISP_NEED_IMAGE_BMP_4_RLE
|
||||||
|
case 4:
|
||||||
|
#endif
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_8 || GDISP_NEED_IMAGE_BMP_8_RLE
|
||||||
|
case 8:
|
||||||
|
#endif
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_1 || GDISP_NEED_IMAGE_BMP_4 || GDISP_NEED_IMAGE_BMP_4_RLE || GDISP_NEED_IMAGE_BMP_8 || GDISP_NEED_IMAGE_BMP_8_RLE
|
||||||
|
priv->bmpflags |= BMP_PALETTE;
|
||||||
|
priv->palsize = 1<<aword;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_16
|
||||||
|
case 16:
|
||||||
|
#endif
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_24
|
||||||
|
case 24:
|
||||||
|
#endif
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_32
|
||||||
|
case 32:
|
||||||
|
#endif
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_16 || GDISP_NEED_IMAGE_BMP_24 || GDISP_NEED_IMAGE_BMP_32
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
goto unsupportedcleanup;
|
||||||
|
}
|
||||||
|
priv->bitsperpixel = aword;
|
||||||
|
// Get the compression
|
||||||
|
adword = *(uint32_t *)(((uint8_t *)priv->buf)+12);
|
||||||
|
CONVERT_FROM_DWORD_LE(adword);
|
||||||
|
switch(adword) {
|
||||||
|
case 0: // BI_RGB - uncompressed
|
||||||
|
break;
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_8_RLE
|
||||||
|
case 1: // BI_RLE8 compression
|
||||||
|
if (priv->bitsperpixel != 8)
|
||||||
|
goto unsupportedcleanup;
|
||||||
|
priv->bmpflags |= BMP_COMP_RLE;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_4_RLE
|
||||||
|
case 2: // BI_RLE4 compression
|
||||||
|
if (priv->bitsperpixel != 4)
|
||||||
|
goto unsupportedcleanup;
|
||||||
|
priv->bmpflags |= BMP_COMP_RLE;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_16 || GDISP_NEED_IMAGE_BMP_32
|
||||||
|
case 3: // BI_BITFIELDS decoding
|
||||||
|
if (priv->bitsperpixel < 16 || priv->bitsperpixel == 24)
|
||||||
|
goto unsupportedcleanup;
|
||||||
|
priv->bmpflags |= BMP_COMP_MASK;
|
||||||
|
if (priv->bmpflags & BMP_V4) // V4 stored the masks in the header
|
||||||
|
offsetColorTable = 40+14;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
goto unsupportedcleanup;
|
||||||
|
}
|
||||||
|
priv->bitsperpixel = aword;
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_1 || GDISP_NEED_IMAGE_BMP_4 || GDISP_NEED_IMAGE_BMP_4_RLE || GDISP_NEED_IMAGE_BMP_8 || GDISP_NEED_IMAGE_BMP_8_RLE
|
||||||
|
// Get the actual colors used
|
||||||
|
adword = *(uint32_t *)(((uint8_t *)priv->buf)+28);
|
||||||
|
CONVERT_FROM_DWORD_LE(adword);
|
||||||
|
if (adword && adword < priv->palsize)
|
||||||
|
priv->palsize = adword;
|
||||||
|
#endif
|
||||||
|
} else
|
||||||
|
goto baddatacleanup;
|
||||||
|
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_1 || GDISP_NEED_IMAGE_BMP_4 || GDISP_NEED_IMAGE_BMP_4_RLE || GDISP_NEED_IMAGE_BMP_8 || GDISP_NEED_IMAGE_BMP_8_RLE
|
||||||
|
/* Load the palette tables */
|
||||||
|
if (priv->bmpflags & BMP_PALETTE) {
|
||||||
|
img->io.fns->seek(&img->io, offsetColorTable);
|
||||||
|
|
||||||
|
if (!(priv->palette = (color_t *)chHeapAlloc(NULL, priv->palsize*sizeof(color_t))))
|
||||||
|
return GDISP_IMAGE_ERR_NOMEMORY;
|
||||||
|
img->membytes += priv->palsize * sizeof(color_t);
|
||||||
|
if (priv->bmpflags & BMP_V2) {
|
||||||
|
for(aword = 0; aword < priv->palsize; aword++) {
|
||||||
|
if (img->io.fns->read(&img->io, &priv->buf, 3) != 3) goto baddatacleanup;
|
||||||
|
priv->palette[aword] = RGB2COLOR(((uint8_t *)priv->buf)[2], ((uint8_t *)priv->buf)[1], ((uint8_t *)priv->buf)[0]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for(aword = 0; aword < priv->palsize; aword++) {
|
||||||
|
if (img->io.fns->read(&img->io, &priv->buf, 4) != 4) goto baddatacleanup;
|
||||||
|
priv->palette[aword] = RGB2COLOR(((uint8_t *)priv->buf)[2], ((uint8_t *)priv->buf)[1], ((uint8_t *)priv->buf)[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_16 || GDISP_NEED_IMAGE_BMP_32
|
||||||
|
/* Load the bit masks */
|
||||||
|
if (priv->bmpflags & BMP_COMP_MASK) {
|
||||||
|
img->io.fns->seek(&img->io, offsetColorTable);
|
||||||
|
if (img->io.fns->read(&img->io, &priv->maskred, 4) != 4) goto baddatacleanup;
|
||||||
|
CONVERT_FROM_DWORD_LE(priv->maskred);
|
||||||
|
if (img->io.fns->read(&img->io, &priv->maskgreen, 4) != 4) goto baddatacleanup;
|
||||||
|
CONVERT_FROM_DWORD_LE(priv->maskgreen);
|
||||||
|
if (img->io.fns->read(&img->io, &priv->maskblue, 4) != 4) goto baddatacleanup;
|
||||||
|
CONVERT_FROM_DWORD_LE(priv->maskblue);
|
||||||
|
if (priv->bmpflags & BMP_V4) {
|
||||||
|
if (img->io.fns->read(&img->io, &priv->maskalpha, 4) != 4) goto baddatacleanup;
|
||||||
|
CONVERT_FROM_DWORD_LE(priv->maskalpha);
|
||||||
|
} else
|
||||||
|
priv->maskalpha = 0;
|
||||||
|
} else if (priv->bitsperpixel == 16) {
|
||||||
|
priv->bmpflags |= BMP_COMP_MASK;
|
||||||
|
priv->maskred = 0x001F0000;
|
||||||
|
priv->maskgreen = 0x07E00000;
|
||||||
|
priv->maskblue = 0xF8000000;
|
||||||
|
priv->maskalpha = 0;
|
||||||
|
} else if (priv->bitsperpixel == 32) {
|
||||||
|
priv->bmpflags |= BMP_COMP_MASK;
|
||||||
|
priv->maskred = 0x00FF0000;
|
||||||
|
priv->maskgreen = 0x0000FF00;
|
||||||
|
priv->maskblue = 0x000000FF;
|
||||||
|
priv->maskalpha = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We need to adjust the masks and calculate the shift values so the result scales 0 -> 255 */
|
||||||
|
if (priv->bmpflags & BMP_COMP_MASK) {
|
||||||
|
priv->shiftred = 0;
|
||||||
|
priv->shiftgreen = 0;
|
||||||
|
priv->shiftblue = 0;
|
||||||
|
if (priv->bitsperpixel == 16) {
|
||||||
|
priv->maskred >>= 16;
|
||||||
|
priv->maskgreen >>= 16;
|
||||||
|
priv->maskblue >>= 16;
|
||||||
|
}
|
||||||
|
if (priv->maskred) {
|
||||||
|
if (priv->maskred < 256)
|
||||||
|
for(adword = priv->maskred; adword < 128; priv->shiftred--, adword <<= 1);
|
||||||
|
else
|
||||||
|
for(adword = priv->maskred; adword > 255; priv->shiftred++, adword >>= 1);
|
||||||
|
}
|
||||||
|
if (priv->maskgreen) {
|
||||||
|
if (priv->maskgreen < 256)
|
||||||
|
for(adword = priv->maskgreen; adword < 128; priv->shiftgreen--, adword <<= 1);
|
||||||
|
else
|
||||||
|
for(adword = priv->maskgreen; adword > 255; priv->shiftgreen++, adword >>= 1);
|
||||||
|
}
|
||||||
|
if (priv->maskblue) {
|
||||||
|
if (priv->maskblue < 256)
|
||||||
|
for(adword = priv->maskblue; adword < 128; priv->shiftblue--, adword <<= 1);
|
||||||
|
else
|
||||||
|
for(adword = priv->maskblue; adword > 255; priv->shiftblue++, adword >>= 1);
|
||||||
|
}
|
||||||
|
if (priv->maskalpha) {
|
||||||
|
if (priv->maskalpha < 256)
|
||||||
|
for(adword = priv->maskalpha; adword < 128; priv->shiftalpha--, adword <<= 1);
|
||||||
|
else
|
||||||
|
for(adword = priv->maskalpha; adword > 255; priv->shiftalpha++, adword >>= 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return GDISP_IMAGE_ERR_OK;
|
||||||
|
|
||||||
|
baddatacleanup:
|
||||||
|
gdispImageClose_BMP(img); // Clean up the private data area
|
||||||
|
return GDISP_IMAGE_ERR_BADDATA; // Oops - something wrong
|
||||||
|
|
||||||
|
unsupportedcleanup:
|
||||||
|
gdispImageClose_BMP(img); // Clean up the private data area
|
||||||
|
return GDISP_IMAGE_ERR_UNSUPPORTED; // Not supported
|
||||||
|
}
|
||||||
|
|
||||||
|
void gdispImageClose_BMP(gdispImage *img) {
|
||||||
|
if (img->priv) {
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_1 || GDISP_NEED_IMAGE_BMP_4 || GDISP_NEED_IMAGE_BMP_4_RLE || GDISP_NEED_IMAGE_BMP_8 || GDISP_NEED_IMAGE_BMP_8_RLE
|
||||||
|
if (img->priv->palette)
|
||||||
|
chHeapFree((void *)img->priv->palette);
|
||||||
|
#endif
|
||||||
|
if (img->priv->frame0cache)
|
||||||
|
chHeapFree((void *)img->priv->frame0cache);
|
||||||
|
chHeapFree((void *)img->priv);
|
||||||
|
img->priv = 0;
|
||||||
|
}
|
||||||
|
img->membytes = 0;
|
||||||
|
img->io.fns->close(&img->io);
|
||||||
|
}
|
||||||
|
|
||||||
|
static coord_t getPixels(gdispImage *img, coord_t x) {
|
||||||
|
gdispImagePrivate * priv;
|
||||||
|
color_t * pc;
|
||||||
|
coord_t len;
|
||||||
|
|
||||||
|
priv = img->priv;
|
||||||
|
pc = priv->buf;
|
||||||
|
len = 0;
|
||||||
|
|
||||||
|
switch(priv->bitsperpixel) {
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_1
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
uint8_t b[4];
|
||||||
|
uint8_t m;
|
||||||
|
|
||||||
|
priv = img->priv;
|
||||||
|
pc = priv->buf;
|
||||||
|
len = 0;
|
||||||
|
|
||||||
|
while(x < img->width && len <= BLIT_BUFFER_SIZE-32) {
|
||||||
|
if (img->io.fns->read(&img->io, &b, 4) != 4)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for(m=0x80; m; m >>= 1, pc++)
|
||||||
|
pc[0] = priv->palette[(m&b[0]) ? 1 : 0];
|
||||||
|
for(m=0x80; m; m >>= 1, pc++)
|
||||||
|
pc[0] = priv->palette[(m&b[1]) ? 1 : 0];
|
||||||
|
for(m=0x80; m; m >>= 1, pc++)
|
||||||
|
pc[0] = priv->palette[(m&b[2]) ? 1 : 0];
|
||||||
|
for(m=0x80; m; m >>= 1, pc++)
|
||||||
|
pc[0] = priv->palette[(m&b[3]) ? 1 : 0];
|
||||||
|
len += 32;
|
||||||
|
x += 32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_4 || GDISP_NEED_IMAGE_BMP_4_RLE
|
||||||
|
case 4:
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_4_RLE
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_4
|
||||||
|
if (priv->bmpflags & BMP_COMP_RLE)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
uint8_t b[4];
|
||||||
|
|
||||||
|
while(x < img->width) {
|
||||||
|
if (priv->bmpflags & BMP_RLE_ENC) {
|
||||||
|
while (priv->rlerun && len <= BLIT_BUFFER_SIZE-2 && x < img->width) {
|
||||||
|
*pc++ = priv->palette[priv->rlecode >> 4];
|
||||||
|
priv->rlerun--;
|
||||||
|
len++;
|
||||||
|
x++;
|
||||||
|
if (priv->rlerun) {
|
||||||
|
*pc++ = priv->palette[priv->rlecode & 0x0F];
|
||||||
|
priv->rlerun--;
|
||||||
|
len++;
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (priv->rlerun) // Return if we have more run to do
|
||||||
|
return len;
|
||||||
|
} else if (priv->bmpflags & BMP_RLE_ABS) {
|
||||||
|
while (priv->rlerun && len <= BLIT_BUFFER_SIZE-2 && x < img->width) {
|
||||||
|
if (img->io.fns->read(&img->io, &b, 1) != 1)
|
||||||
|
return 0;
|
||||||
|
*pc++ = priv->palette[b[0] >> 4];
|
||||||
|
priv->rlerun--;
|
||||||
|
len++;
|
||||||
|
x++;
|
||||||
|
if (priv->rlerun) {
|
||||||
|
*pc++ = priv->palette[b[0] & 0x0F];
|
||||||
|
priv->rlerun--;
|
||||||
|
len++;
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (priv->rlerun) // Return if we have more run to do
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have finished the current run - read a new run
|
||||||
|
priv->bmpflags &= ~(BMP_RLE_ENC|BMP_RLE_ABS);
|
||||||
|
|
||||||
|
// There are always at least 2 bytes in an RLE code
|
||||||
|
if (img->io.fns->read(&img->io, &b, 2) != 2)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (b[0]) { // Encoded mode
|
||||||
|
priv->rlerun = b[0];
|
||||||
|
priv->rlecode = b[1];
|
||||||
|
priv->bmpflags |= BMP_RLE_ENC;
|
||||||
|
} else if (b[1] == 0) { // End of line
|
||||||
|
if (x < img->width) {
|
||||||
|
priv->rlerun = img->width - x;
|
||||||
|
priv->rlecode = 0; // Who knows what color this should really be
|
||||||
|
priv->bmpflags |= BMP_RLE_ENC;
|
||||||
|
}
|
||||||
|
} else if (b[1] == 1) { // End of file
|
||||||
|
return len;
|
||||||
|
} else if (b[1] == 2) { // Delta x, y
|
||||||
|
// There are always at least 2 bytes in an RLE code
|
||||||
|
if (img->io.fns->read(&img->io, &b, 2) != 2)
|
||||||
|
return 0;
|
||||||
|
priv->rlerun = b[0] + (uint16_t)b[1] * img->width;
|
||||||
|
priv->rlecode = 0; // Who knows what color this should really be
|
||||||
|
priv->bmpflags |= BMP_RLE_ENC;
|
||||||
|
} else { // Absolute mode
|
||||||
|
priv->rlerun = b[1];
|
||||||
|
priv->bmpflags |= BMP_RLE_ABS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_4
|
||||||
|
{
|
||||||
|
uint8_t b[4];
|
||||||
|
|
||||||
|
while(x < img->width && len <= BLIT_BUFFER_SIZE-8) {
|
||||||
|
if (img->io.fns->read(&img->io, &b, 4) != 4)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
*pc++ = priv->palette[b[0] >> 4];
|
||||||
|
*pc++ = priv->palette[b[0] & 0x0F];
|
||||||
|
*pc++ = priv->palette[b[1] >> 4];
|
||||||
|
*pc++ = priv->palette[b[1] & 0x0F];
|
||||||
|
*pc++ = priv->palette[b[2] >> 4];
|
||||||
|
*pc++ = priv->palette[b[2] & 0x0F];
|
||||||
|
*pc++ = priv->palette[b[3] >> 4];
|
||||||
|
*pc++ = priv->palette[b[3] & 0x0F];
|
||||||
|
len += 8;
|
||||||
|
x += 8;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_8 || GDISP_NEED_IMAGE_BMP_8_RLE
|
||||||
|
case 8:
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_8_RLE
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_8
|
||||||
|
if (priv->bmpflags & BMP_COMP_RLE)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
uint8_t b[4];
|
||||||
|
|
||||||
|
while(x < img->width) {
|
||||||
|
if (priv->bmpflags & BMP_RLE_ENC) {
|
||||||
|
while (priv->rlerun && len < BLIT_BUFFER_SIZE && x < img->width) {
|
||||||
|
*pc++ = priv->palette[priv->rlecode];
|
||||||
|
priv->rlerun--;
|
||||||
|
len++;
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
if (priv->rlerun) // Return if we have more run to do
|
||||||
|
return len;
|
||||||
|
} else if (priv->bmpflags & BMP_RLE_ABS) {
|
||||||
|
while (priv->rlerun && len < BLIT_BUFFER_SIZE && x < img->width) {
|
||||||
|
if (img->io.fns->read(&img->io, &b, 1) != 1)
|
||||||
|
return 0;
|
||||||
|
*pc++ = priv->palette[b[0]];
|
||||||
|
priv->rlerun--;
|
||||||
|
len++;
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
if (priv->rlerun) // Return if we have more run to do
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have finished the current run - read a new run
|
||||||
|
priv->bmpflags &= ~(BMP_RLE_ENC|BMP_RLE_ABS);
|
||||||
|
|
||||||
|
// There are always at least 2 bytes in an RLE code
|
||||||
|
if (img->io.fns->read(&img->io, &b, 2) != 2)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (b[0]) { // Encoded mode
|
||||||
|
priv->rlerun = b[0];
|
||||||
|
priv->rlecode = b[1];
|
||||||
|
priv->bmpflags |= BMP_RLE_ENC;
|
||||||
|
} else if (b[1] == 0) { // End of line
|
||||||
|
if (x < img->width) {
|
||||||
|
priv->rlerun = img->width - x;
|
||||||
|
priv->rlecode = 0; // Who knows what color this should really be
|
||||||
|
priv->bmpflags |= BMP_RLE_ENC;
|
||||||
|
}
|
||||||
|
} else if (b[1] == 1) { // End of file
|
||||||
|
return len;
|
||||||
|
} else if (b[1] == 2) { // Delta x, y
|
||||||
|
// There are always at least 2 bytes in an RLE code
|
||||||
|
if (img->io.fns->read(&img->io, &b, 2) != 2)
|
||||||
|
return GDISP_IMAGE_ERR_BADDATA;
|
||||||
|
priv->rlerun = b[0] + (uint16_t)b[1] * img->width;
|
||||||
|
priv->rlecode = 0; // Who knows what color this should really be
|
||||||
|
priv->bmpflags |= BMP_RLE_ENC;
|
||||||
|
} else { // Absolute mode
|
||||||
|
priv->rlerun = b[1];
|
||||||
|
priv->bmpflags |= BMP_RLE_ABS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_8
|
||||||
|
{
|
||||||
|
uint8_t b[4];
|
||||||
|
|
||||||
|
while(x < img->width && len <= BLIT_BUFFER_SIZE-4) {
|
||||||
|
if (img->io.fns->read(&img->io, &b, 4) != 4)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
*pc++ = priv->palette[b[0]];
|
||||||
|
*pc++ = priv->palette[b[1]];
|
||||||
|
*pc++ = priv->palette[b[2]];
|
||||||
|
*pc++ = priv->palette[b[3]];
|
||||||
|
len += 4;
|
||||||
|
x += 4;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_16
|
||||||
|
case 16:
|
||||||
|
{
|
||||||
|
uint16_t w[2];
|
||||||
|
color_t r, g, b;
|
||||||
|
|
||||||
|
while(x < img->width && len <= BLIT_BUFFER_SIZE-2) {
|
||||||
|
if (img->io.fns->read(&img->io, &w, 4) != 4)
|
||||||
|
return 0;
|
||||||
|
CONVERT_FROM_WORD_BE(w[0]);
|
||||||
|
CONVERT_FROM_WORD_BE(w[1]);
|
||||||
|
if (priv->shiftred < 0)
|
||||||
|
r = (color_t)((w[0] & priv->maskred) << -priv->shiftred);
|
||||||
|
else
|
||||||
|
r = (color_t)((w[0] & priv->maskred) >> priv->shiftred);
|
||||||
|
if (priv->shiftgreen < 0)
|
||||||
|
g = (color_t)((w[0] & priv->maskgreen) << -priv->shiftgreen);
|
||||||
|
else
|
||||||
|
g = (color_t)((w[0] & priv->maskgreen) >> priv->shiftgreen);
|
||||||
|
if (priv->shiftblue < 0)
|
||||||
|
b = (color_t)((w[0] & priv->maskblue) << -priv->shiftblue);
|
||||||
|
else
|
||||||
|
b = (color_t)((w[0] & priv->maskblue) >> priv->shiftblue);
|
||||||
|
/* We don't support alpha yet */
|
||||||
|
*pc++ = RGB2COLOR(r, g, b);
|
||||||
|
if (priv->shiftred < 0)
|
||||||
|
r = (color_t)((w[1] & priv->maskred) << -priv->shiftred);
|
||||||
|
else
|
||||||
|
r = (color_t)((w[1] & priv->maskred) >> priv->shiftred);
|
||||||
|
if (priv->shiftgreen < 0)
|
||||||
|
g = (color_t)((w[1] & priv->maskgreen) << -priv->shiftgreen);
|
||||||
|
else
|
||||||
|
g = (color_t)((w[1] & priv->maskgreen) >> priv->shiftgreen);
|
||||||
|
if (priv->shiftblue < 0)
|
||||||
|
b = (color_t)((w[1] & priv->maskblue) << -priv->shiftblue);
|
||||||
|
else
|
||||||
|
b = (uint8_t)((w[1] & priv->maskblue) >> priv->shiftblue);
|
||||||
|
/* We don't support alpha yet */
|
||||||
|
*pc++ = RGB2COLOR(r, g, b);
|
||||||
|
x += 2;
|
||||||
|
len += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_24
|
||||||
|
case 24:
|
||||||
|
{
|
||||||
|
uint8_t b[3];
|
||||||
|
|
||||||
|
while(x < img->width && len < BLIT_BUFFER_SIZE) {
|
||||||
|
if (img->io.fns->read(&img->io, &b, 3) != 3)
|
||||||
|
return 0;
|
||||||
|
*pc++ = RGB2COLOR(b[2], b[1], b[0]);
|
||||||
|
x++;
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x >= img->width) {
|
||||||
|
// Make sure we have read a multiple of 4 bytes for the line
|
||||||
|
if ((x & 3) && img->io.fns->read(&img->io, &b, x & 3) != (x & 3))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_32
|
||||||
|
case 32:
|
||||||
|
{
|
||||||
|
uint32_t dw;
|
||||||
|
color_t r, g, b;
|
||||||
|
|
||||||
|
while(x < img->width && len < BLIT_BUFFER_SIZE) {
|
||||||
|
if (img->io.fns->read(&img->io, &dw, 4) != 4)
|
||||||
|
return 0;
|
||||||
|
CONVERT_FROM_DWORD_LE(dw);
|
||||||
|
if (priv->shiftred < 0)
|
||||||
|
r = (color_t)((dw & priv->maskred) << -priv->shiftred);
|
||||||
|
else
|
||||||
|
r = (color_t)((dw & priv->maskred) >> priv->shiftred);
|
||||||
|
if (priv->shiftgreen < 0)
|
||||||
|
g = (color_t)((dw & priv->maskgreen) << -priv->shiftgreen);
|
||||||
|
else
|
||||||
|
g = (color_t)((dw & priv->maskgreen) >> priv->shiftgreen);
|
||||||
|
if (priv->shiftblue < 0)
|
||||||
|
b = (color_t)((dw & priv->maskblue) << -priv->shiftblue);
|
||||||
|
else
|
||||||
|
b = (color_t)((dw & priv->maskblue) >> priv->shiftblue);
|
||||||
|
/* We don't support alpha yet */
|
||||||
|
*pc++ = RGB2COLOR(r, g, b);
|
||||||
|
x++;
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
default:
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gdispImageError gdispImageCache_BMP(gdispImage *img) {
|
||||||
|
gdispImagePrivate * priv;
|
||||||
|
color_t * pcs;
|
||||||
|
color_t * pcd;
|
||||||
|
coord_t pos, x, y;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
/* If we are already cached - just return OK */
|
||||||
|
priv = img->priv;
|
||||||
|
if (priv->frame0cache)
|
||||||
|
return GDISP_IMAGE_ERR_OK;
|
||||||
|
|
||||||
|
/* We need to allocate the cache */
|
||||||
|
len = img->width * img->height * sizeof(pixel_t);
|
||||||
|
priv->frame0cache = (pixel_t *)chHeapAlloc(NULL, len);
|
||||||
|
if (!priv->frame0cache)
|
||||||
|
return GDISP_IMAGE_ERR_NOMEMORY;
|
||||||
|
img->membytes += len;
|
||||||
|
|
||||||
|
/* Read the entire bitmap into cache */
|
||||||
|
img->io.fns->seek(&img->io, priv->frame0pos);
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_4_RLE || GDISP_NEED_IMAGE_BMP_8_RLE
|
||||||
|
priv->rlerun = 0;
|
||||||
|
priv->rlecode = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (priv->bmpflags & BMP_TOP_TO_BOTTOM) {
|
||||||
|
for(y = 0, pcd = priv->frame0cache; y < img->height; y++) {
|
||||||
|
x = 0; pos = 0;
|
||||||
|
while(x < img->width) {
|
||||||
|
if (!pos) {
|
||||||
|
if (!(pos = getPixels(img, x)))
|
||||||
|
return GDISP_IMAGE_ERR_BADDATA;
|
||||||
|
pcs = priv->buf;
|
||||||
|
}
|
||||||
|
*pcd++ = *pcs++;
|
||||||
|
x++; pos--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for(y = img->height-1, pcd = priv->frame0cache + img->width*(img->height-1); y >= 0; y--, pcd -= 2*img->width) {
|
||||||
|
x = 0; pos = 0;
|
||||||
|
while(x < img->width) {
|
||||||
|
if (!pos) {
|
||||||
|
if (!(pos = getPixels(img, x)))
|
||||||
|
return GDISP_IMAGE_ERR_BADDATA;
|
||||||
|
pcs = priv->buf;
|
||||||
|
}
|
||||||
|
*pcd++ = *pcs++;
|
||||||
|
x++; pos--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return GDISP_IMAGE_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
gdispImageError gdispImageDraw_BMP(gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy) {
|
||||||
|
gdispImagePrivate * priv;
|
||||||
|
coord_t mx, my;
|
||||||
|
coord_t pos, len, st;
|
||||||
|
|
||||||
|
priv = img->priv;
|
||||||
|
|
||||||
|
/* Check some reasonableness */
|
||||||
|
if (sx >= img->width || sy >= img->height) return GDISP_IMAGE_ERR_OK;
|
||||||
|
if (sx + cx > img->width) cx = img->width - sx;
|
||||||
|
if (sy + cy > img->height) cy = img->height - sy;
|
||||||
|
|
||||||
|
/* Draw from the image cache - if it exists */
|
||||||
|
if (priv->frame0cache) {
|
||||||
|
gdispBlitAreaEx(x, y, cx, cy, sx, sy, img->width, priv->frame0cache);
|
||||||
|
return GDISP_IMAGE_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Start decoding from the beginning */
|
||||||
|
img->io.fns->seek(&img->io, priv->frame0pos);
|
||||||
|
#if GDISP_NEED_IMAGE_BMP_4_RLE || GDISP_NEED_IMAGE_BMP_8_RLE
|
||||||
|
priv->rlerun = 0;
|
||||||
|
priv->rlecode = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (priv->bmpflags & BMP_TOP_TO_BOTTOM) {
|
||||||
|
for(my = 0; my < img->height; my++) {
|
||||||
|
mx = 0;
|
||||||
|
while(mx < img->width) {
|
||||||
|
if (!(pos = getPixels(img, mx)))
|
||||||
|
return GDISP_IMAGE_ERR_BADDATA;
|
||||||
|
if (my >= sy && my < sy+cy && mx < sx+cx && mx+pos >= sx) {
|
||||||
|
st = mx < sx ? sx - mx : 0;
|
||||||
|
len = pos-st;
|
||||||
|
if (mx+st+len > sx+cx) len = sx+cx-mx-st;
|
||||||
|
if (len == 1)
|
||||||
|
gdispDrawPixel(x+mx+st-sx, y+my-sy, priv->buf[st]);
|
||||||
|
else
|
||||||
|
gdispBlitAreaEx(x+mx+st-sx, y+my-sy, len, 1, st, 0, pos, priv->buf);
|
||||||
|
}
|
||||||
|
mx += pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for(my = img->height-1; my >= 0; my--) {
|
||||||
|
mx = 0;
|
||||||
|
while(mx < img->width) {
|
||||||
|
if (!(pos = getPixels(img, mx)))
|
||||||
|
return GDISP_IMAGE_ERR_BADDATA;
|
||||||
|
if (my >= sy && my < sy+cy && mx < sx+cx && mx+pos >= sx) {
|
||||||
|
st = mx < sx ? sx - mx : 0;
|
||||||
|
len = pos-st;
|
||||||
|
if (mx+st+len > sx+cx) len = sx+cx-mx-st;
|
||||||
|
if (len == 1)
|
||||||
|
gdispDrawPixel(x+mx+st-sx, y+my-sy, priv->buf[st]);
|
||||||
|
else
|
||||||
|
gdispBlitAreaEx(x+mx+st-sx, y+my-sy, len, 1, st, 0, pos, priv->buf);
|
||||||
|
}
|
||||||
|
mx += pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return GDISP_IMAGE_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
systime_t gdispImageNext_BMP(gdispImage *img) {
|
||||||
|
(void) img;
|
||||||
|
|
||||||
|
/* No more frames/pages */
|
||||||
|
return TIME_INFINITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* GFX_USE_GDISP && GDISP_NEED_IMAGE && GDISP_NEED_IMAGE_BMP */
|
||||||
|
/** @} */
|
47
src/gdisp/image_gif.c
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/GFX - Copyright (C) 2012, 2013
|
||||||
|
Joel Bodenmann aka Tectu <joel@unormal.org>
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file src/gdisp/image_gif.c
|
||||||
|
* @brief GDISP native image code.
|
||||||
|
*/
|
||||||
|
#include "ch.h"
|
||||||
|
#include "hal.h"
|
||||||
|
#include "gfx.h"
|
||||||
|
|
||||||
|
#if GFX_USE_GDISP && GDISP_NEED_IMAGE && GDISP_NEED_IMAGE_GIF
|
||||||
|
|
||||||
|
#error "GIF support not implemented yet"
|
||||||
|
|
||||||
|
/* A pallete structure */
|
||||||
|
typedef struct gdispImagePallete {
|
||||||
|
uint8_t flags;
|
||||||
|
#define GDISP_IMAGE_FLG_INT_TRANSPARENT 0x01
|
||||||
|
uint8_t idxtrans; /* The transparent idx */
|
||||||
|
uint8_t maxidx; /* The maximum index (0..255) */
|
||||||
|
uint8_t repidx; /* The index to use if the image data > maxidx */
|
||||||
|
color_t pal[256]; /* The pallete entries - not all may actually be allocated */
|
||||||
|
} gdispImagePallete;
|
||||||
|
|
||||||
|
/* Draw a single palletized line (or partial line) */
|
||||||
|
static void gdispDrawPalleteLine(const gdispImagePallete *pal, const uint8_t *line, coord_t x, coord_t y, coord_t cx);
|
||||||
|
|
||||||
|
#endif /* GFX_USE_GDISP && GDISP_NEED_IMAGE && GDISP_NEED_IMAGE_GIF */
|
||||||
|
/** @} */
|
34
src/gdisp/image_jpg.c
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/GFX - Copyright (C) 2012, 2013
|
||||||
|
Joel Bodenmann aka Tectu <joel@unormal.org>
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file src/gdisp/image_jpg.c
|
||||||
|
* @brief GDISP native image code.
|
||||||
|
*/
|
||||||
|
#include "ch.h"
|
||||||
|
#include "hal.h"
|
||||||
|
#include "gfx.h"
|
||||||
|
|
||||||
|
#if GFX_USE_GDISP && GDISP_NEED_IMAGE && GDISP_NEED_IMAGE_JPG
|
||||||
|
|
||||||
|
#error "JPG support not implemented yet"
|
||||||
|
|
||||||
|
#endif /* GFX_USE_GDISP && GDISP_NEED_IMAGE && GDISP_NEED_IMAGE_JPG */
|
||||||
|
/** @} */
|
157
src/gdisp/image_native.c
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/GFX - Copyright (C) 2012, 2013
|
||||||
|
Joel Bodenmann aka Tectu <joel@unormal.org>
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file src/gdisp/image_native.c
|
||||||
|
* @brief GDISP native image code.
|
||||||
|
*/
|
||||||
|
#include "ch.h"
|
||||||
|
#include "hal.h"
|
||||||
|
#include "gfx.h"
|
||||||
|
|
||||||
|
#if GFX_USE_GDISP && GDISP_NEED_IMAGE && GDISP_NEED_IMAGE_NATIVE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How big a pixel array to allocate for blitting
|
||||||
|
* Bigger is faster but uses more RAM.
|
||||||
|
*/
|
||||||
|
#define BLIT_BUFFER_SIZE 32
|
||||||
|
|
||||||
|
#define HEADER_SIZE 8
|
||||||
|
#define FRAME0POS (HEADER_SIZE)
|
||||||
|
|
||||||
|
typedef struct gdispImagePrivate {
|
||||||
|
pixel_t *frame0cache;
|
||||||
|
pixel_t buf[BLIT_BUFFER_SIZE];
|
||||||
|
} gdispImagePrivate;
|
||||||
|
|
||||||
|
gdispImageError gdispImageOpen_NATIVE(gdispImage *img) {
|
||||||
|
uint8_t hdr[HEADER_SIZE];
|
||||||
|
|
||||||
|
/* Read the 8 byte header */
|
||||||
|
if (img->io.fns->read(&img->io, hdr, 8) != 8)
|
||||||
|
return GDISP_IMAGE_ERR_BADFORMAT; // It can't be us
|
||||||
|
|
||||||
|
if (hdr[0] != 'N' || hdr[1] != 'I')
|
||||||
|
return GDISP_IMAGE_ERR_BADFORMAT; // It can't be us
|
||||||
|
|
||||||
|
if (hdr[6] != GDISP_PIXELFORMAT/256 || hdr[7] != (GDISP_PIXELFORMAT & 0xFF))
|
||||||
|
return GDISP_IMAGE_ERR_UNSUPPORTED; // Unsupported pixel format
|
||||||
|
|
||||||
|
/* We know we are a native format image */
|
||||||
|
img->flags = 0;
|
||||||
|
img->width = (((uint16_t)hdr[2])<<8) | (hdr[3]);
|
||||||
|
img->height = (((uint16_t)hdr[4])<<8) | (hdr[5]);
|
||||||
|
if (img->width < 1 || img->height < 1)
|
||||||
|
return GDISP_IMAGE_ERR_BADDATA;
|
||||||
|
if (!(img->priv = (gdispImagePrivate *)chHeapAlloc(NULL, sizeof(gdispImagePrivate))))
|
||||||
|
return GDISP_IMAGE_ERR_NOMEMORY;
|
||||||
|
img->membytes = sizeof(gdispImagePrivate);
|
||||||
|
img->priv->frame0cache = 0;
|
||||||
|
|
||||||
|
return GDISP_IMAGE_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gdispImageClose_NATIVE(gdispImage *img) {
|
||||||
|
if (img->priv) {
|
||||||
|
if (img->priv->frame0cache)
|
||||||
|
chHeapFree((void *)img->priv->frame0cache);
|
||||||
|
chHeapFree((void *)img->priv);
|
||||||
|
img->priv = 0;
|
||||||
|
}
|
||||||
|
img->membytes = 0;
|
||||||
|
img->io.fns->close(&img->io);
|
||||||
|
}
|
||||||
|
|
||||||
|
gdispImageError gdispImageCache_NATIVE(gdispImage *img) {
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
/* If we are already cached - just return OK */
|
||||||
|
if (img->priv->frame0cache)
|
||||||
|
return GDISP_IMAGE_ERR_OK;
|
||||||
|
|
||||||
|
/* We need to allocate the cache */
|
||||||
|
len = img->width * img->height * sizeof(pixel_t);
|
||||||
|
img->priv->frame0cache = (pixel_t *)chHeapAlloc(NULL, len);
|
||||||
|
if (!img->priv->frame0cache)
|
||||||
|
return GDISP_IMAGE_ERR_NOMEMORY;
|
||||||
|
img->membytes += len;
|
||||||
|
|
||||||
|
/* Read the entire bitmap into cache */
|
||||||
|
img->io.fns->seek(&img->io, FRAME0POS);
|
||||||
|
if (img->io.fns->read(&img->io, img->priv->frame0cache, len) != len)
|
||||||
|
return GDISP_IMAGE_ERR_BADDATA;
|
||||||
|
|
||||||
|
return GDISP_IMAGE_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
gdispImageError gdispImageDraw_NATIVE(gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy) {
|
||||||
|
coord_t mx, mcx;
|
||||||
|
size_t pos, len;
|
||||||
|
|
||||||
|
/* Check some reasonableness */
|
||||||
|
if (sx >= img->width || sy >= img->height) return GDISP_IMAGE_ERR_OK;
|
||||||
|
if (sx + cx > img->width) cx = img->width - sx;
|
||||||
|
if (sy + cy > img->height) cy = img->height - sy;
|
||||||
|
|
||||||
|
/* Draw from the image cache - if it exists */
|
||||||
|
if (img->priv->frame0cache) {
|
||||||
|
gdispBlitAreaEx(x, y, cx, cy, sx, sy, img->width, img->priv->frame0cache);
|
||||||
|
return GDISP_IMAGE_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For this image decoder we cheat and just seek straight to the region we want to display */
|
||||||
|
pos = FRAME0POS + (img->width * sy + cx) * sizeof(pixel_t);
|
||||||
|
|
||||||
|
/* Cycle through the lines */
|
||||||
|
for(;cy;cy--, y++) {
|
||||||
|
/* Move to the start of the line */
|
||||||
|
img->io.fns->seek(&img->io, pos);
|
||||||
|
|
||||||
|
/* Draw the line in chunks using BitBlt */
|
||||||
|
for(mx = x, mcx = cx; mcx > 0; mcx -= len, mx += len) {
|
||||||
|
// Read the data
|
||||||
|
len = img->io.fns->read(&img->io,
|
||||||
|
img->priv->buf,
|
||||||
|
mx > BLIT_BUFFER_SIZE ? (BLIT_BUFFER_SIZE*sizeof(pixel_t)) : (mx * sizeof(pixel_t)))
|
||||||
|
/ sizeof(pixel_t);
|
||||||
|
if (!len)
|
||||||
|
return GDISP_IMAGE_ERR_BADDATA;
|
||||||
|
|
||||||
|
/* Blit the chunk of data */
|
||||||
|
gdispBlitAreaEx(mx, y, len, 1, 0, 0, len, img->priv->buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the position for the start of the next line */
|
||||||
|
pos += img->width*sizeof(pixel_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
return GDISP_IMAGE_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
systime_t gdispImageNext_NATIVE(gdispImage *img) {
|
||||||
|
(void) img;
|
||||||
|
|
||||||
|
/* No more frames/pages */
|
||||||
|
return TIME_INFINITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* GFX_USE_GDISP && GDISP_NEED_IMAGE && GDISP_NEED_IMAGE_NATIVE */
|
||||||
|
/** @} */
|
34
src/gdisp/image_png.c
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/GFX - Copyright (C) 2012, 2013
|
||||||
|
Joel Bodenmann aka Tectu <joel@unormal.org>
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file src/gdisp/image_png.c
|
||||||
|
* @brief GDISP native image code.
|
||||||
|
*/
|
||||||
|
#include "ch.h"
|
||||||
|
#include "hal.h"
|
||||||
|
#include "gfx.h"
|
||||||
|
|
||||||
|
#if GFX_USE_GDISP && GDISP_NEED_IMAGE && GDISP_NEED_IMAGE_PNG
|
||||||
|
|
||||||
|
#error "PNG support not implemented yet"
|
||||||
|
|
||||||
|
#endif /* GFX_USE_GDISP && GDISP_NEED_IMAGE && GDISP_NEED_IMAGE_PNG */
|
||||||
|
/** @} */
|