Remove JPG and BMP support. Add uPNG support.
This commit is contained in:
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "tftspi.h"
|
#include "tftspi.h"
|
||||||
|
#include "upng.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint16_t x1;
|
uint16_t x1;
|
||||||
@ -601,43 +602,8 @@ void mgos_ili9341_clearStringRect(int x, int y, char *str);
|
|||||||
//----------------------------------------------------------
|
//----------------------------------------------------------
|
||||||
color_t HSBtoRGB(float _hue, float _sat, float _brightness);
|
color_t HSBtoRGB(float _hue, float _sat, float _brightness);
|
||||||
|
|
||||||
/*
|
/* Draw PNG at coords x,y */
|
||||||
* Decodes and displays JPG image
|
int mgos_ili9341_png(int x, int y, char *fname);
|
||||||
* Limits:
|
|
||||||
* Baseline only. Progressive and Lossless JPEG format are not supported.
|
|
||||||
* Image size: Up to 65520 x 65520 pixels
|
|
||||||
* Color space: YCbCr three components only. Gray scale image is not supported.
|
|
||||||
* Sampling factor: 4:4:4, 4:2:2 or 4:2:0.
|
|
||||||
*
|
|
||||||
* Params:
|
|
||||||
* x: image left position; constants CENTER & RIGHT can be used; negative value is accepted
|
|
||||||
* y: image top position; constants CENTER & BOTTOM can be used; negative value is accepted
|
|
||||||
* scale: image scale factor: 0~3; if scale>0, image is scaled by factor 1/(2^scale) (1/2, 1/4 or 1/8)
|
|
||||||
* fname: pointer to the name of the file from which the image will be read
|
|
||||||
* if set to NULL, image will be read from memory buffer pointed to by 'buf'
|
|
||||||
* buf: pointer to the memory buffer from which the image will be read; used if fname=NULL
|
|
||||||
* size: size of the memory buffer from which the image will be read; used if fname=NULL & buf!=NULL
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
//-----------------------------------------------------------------------------------
|
|
||||||
void mgos_ili9341_jpg_image(int x, int y, uint8_t scale, char *fname, uint8_t *buf, int size);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Decodes and displays BMP image
|
|
||||||
* Only uncompressed RGB 24-bit with no color space information BMP images can be displayed
|
|
||||||
*
|
|
||||||
* Params:
|
|
||||||
* x: image left position; constants CENTER & RIGHT can be used; negative value is accepted
|
|
||||||
* y: image top position; constants CENTER & BOTTOM can be used; negative value is accepted
|
|
||||||
* scale: image scale factor: 0~7; if scale>0, image is scaled by factor 1/(scale+1)
|
|
||||||
* fname: pointer to the name of the file from which the image will be read
|
|
||||||
* if set to NULL, image will be read from memory buffer pointed to by 'imgbuf'
|
|
||||||
* imgbuf: pointer to the memory buffer from which the image will be read; used if fname=NULL
|
|
||||||
* size: size of the memory buffer from which the image will be read; used if fname=NULL & imgbuf!=NULL
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
//-------------------------------------------------------------------------------------
|
|
||||||
int mgos_ili9341_bmp_image(int x, int y, uint8_t scale, char *fname, uint8_t *imgbuf, int size);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compile font c source file to .fnt file
|
* Compile font c source file to .fnt file
|
||||||
|
81
libs/ili9341/include/upng.h
Normal file
81
libs/ili9341/include/upng.h
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
uPNG -- derived from LodePNG version 20100808
|
||||||
|
|
||||||
|
Copyright (c) 2005-2010 Lode Vandevenne
|
||||||
|
Copyright (c) 2010 Sean Middleditch
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
|
||||||
|
3. This notice may not be removed or altered from any source
|
||||||
|
distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(UPNG_H)
|
||||||
|
#define UPNG_H
|
||||||
|
|
||||||
|
typedef enum upng_error {
|
||||||
|
UPNG_EOK = 0, /* success (no error) */
|
||||||
|
UPNG_ENOMEM = 1, /* memory allocation failed */
|
||||||
|
UPNG_ENOTFOUND = 2, /* resource not found (file missing) */
|
||||||
|
UPNG_ENOTPNG = 3, /* image data does not have a PNG header */
|
||||||
|
UPNG_EMALFORMED = 4, /* image data is not a valid PNG image */
|
||||||
|
UPNG_EUNSUPPORTED = 5, /* critical PNG chunk type is not supported */
|
||||||
|
UPNG_EUNINTERLACED = 6, /* image interlacing is not supported */
|
||||||
|
UPNG_EUNFORMAT = 7, /* image color format is not supported */
|
||||||
|
UPNG_EPARAM = 8 /* invalid parameter to method call */
|
||||||
|
} upng_error;
|
||||||
|
|
||||||
|
typedef enum upng_format {
|
||||||
|
UPNG_BADFORMAT,
|
||||||
|
UPNG_RGB8,
|
||||||
|
UPNG_RGB16,
|
||||||
|
UPNG_RGBA8,
|
||||||
|
UPNG_RGBA16,
|
||||||
|
UPNG_LUMINANCE1,
|
||||||
|
UPNG_LUMINANCE2,
|
||||||
|
UPNG_LUMINANCE4,
|
||||||
|
UPNG_LUMINANCE8,
|
||||||
|
UPNG_LUMINANCE_ALPHA1,
|
||||||
|
UPNG_LUMINANCE_ALPHA2,
|
||||||
|
UPNG_LUMINANCE_ALPHA4,
|
||||||
|
UPNG_LUMINANCE_ALPHA8
|
||||||
|
} upng_format;
|
||||||
|
|
||||||
|
typedef struct upng_t upng_t;
|
||||||
|
|
||||||
|
upng_t* upng_new_from_bytes (const unsigned char* buffer, unsigned long size);
|
||||||
|
upng_t* upng_new_from_file (const char* path);
|
||||||
|
void upng_free (upng_t* upng);
|
||||||
|
|
||||||
|
upng_error upng_header (upng_t* upng);
|
||||||
|
upng_error upng_decode (upng_t* upng);
|
||||||
|
|
||||||
|
upng_error upng_get_error (const upng_t* upng);
|
||||||
|
unsigned upng_get_error_line (const upng_t* upng);
|
||||||
|
|
||||||
|
unsigned upng_get_width (const upng_t* upng);
|
||||||
|
unsigned upng_get_height (const upng_t* upng);
|
||||||
|
unsigned upng_get_bpp (const upng_t* upng);
|
||||||
|
unsigned upng_get_bitdepth (const upng_t* upng);
|
||||||
|
unsigned upng_get_components (const upng_t* upng);
|
||||||
|
unsigned upng_get_pixelsize (const upng_t* upng);
|
||||||
|
upng_format upng_get_format (const upng_t* upng);
|
||||||
|
|
||||||
|
const unsigned char* upng_get_buffer (const upng_t* upng);
|
||||||
|
unsigned upng_get_size (const upng_t* upng);
|
||||||
|
|
||||||
|
#endif /*defined(UPNG_H)*/
|
@ -15,7 +15,7 @@
|
|||||||
#include "tft.h"
|
#include "tft.h"
|
||||||
#include "time.h"
|
#include "time.h"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "rom/tjpgd.h"
|
// #include "rom/tjpgd.h"
|
||||||
#include "esp_heap_caps.h"
|
#include "esp_heap_caps.h"
|
||||||
#include "tftspi.h"
|
#include "tftspi.h"
|
||||||
#include "mgos.h"
|
#include "mgos.h"
|
||||||
@ -2242,520 +2242,51 @@ void mgos_ili9341_restoreClipWin()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ================ JPG SUPPORT ================================================
|
int mgos_ili9341_png(int x, int y, char *fname)
|
||||||
// User defined device identifier
|
|
||||||
typedef struct {
|
|
||||||
FILE *fhndl; // File handler for input function
|
|
||||||
int x; // image top left point X position
|
|
||||||
int y; // image top left point Y position
|
|
||||||
uint8_t *membuff; // memory buffer containing the image
|
|
||||||
uint32_t bufsize; // size of the memory buffer
|
|
||||||
uint32_t bufptr; // memory buffer current position
|
|
||||||
color_t *linbuf[2]; // memory buffer used for display output
|
|
||||||
uint8_t linbuf_idx;
|
|
||||||
} JPGIODEV;
|
|
||||||
|
|
||||||
|
|
||||||
// User defined call-back function to input JPEG data from file
|
|
||||||
//---------------------
|
|
||||||
static UINT tjd_input (
|
|
||||||
JDEC* jd, // Decompression object
|
|
||||||
BYTE* buff, // Pointer to the read buffer (NULL:skip)
|
|
||||||
UINT nd // Number of bytes to read/skip from input stream
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
int rb = 0;
|
upng_t* upng;
|
||||||
// Device identifier for the session (5th argument of jd_prepare function)
|
const uint8_t *png_buf;
|
||||||
JPGIODEV *dev = (JPGIODEV*)jd->device;
|
uint16_t i,j;
|
||||||
|
color_t pixel;
|
||||||
|
|
||||||
if (buff) { // Read nd bytes from the input strem
|
int ret = -1;
|
||||||
rb = fread(buff, 1, nd, dev->fhndl);
|
|
||||||
return rb; // Returns actual number of bytes read
|
|
||||||
}
|
|
||||||
else { // Remove nd bytes from the input stream
|
|
||||||
if (fseek(dev->fhndl, nd, SEEK_CUR) >= 0) return nd;
|
|
||||||
else return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// User defined call-back function to input JPEG data from memory buffer
|
if (!(upng = upng_new_from_file(fname))) {
|
||||||
//-------------------------
|
LOG(LL_ERROR, ("Can't read %s", fname));
|
||||||
static UINT tjd_buf_input (
|
goto exit;
|
||||||
JDEC* jd, // Decompression object
|
}
|
||||||
BYTE* buff, // Pointer to the read buffer (NULL:skip)
|
|
||||||
UINT nd // Number of bytes to read/skip from input stream
|
|
||||||
)
|
|
||||||
{
|
|
||||||
// Device identifier for the session (5th argument of jd_prepare function)
|
|
||||||
JPGIODEV *dev = (JPGIODEV*)jd->device;
|
|
||||||
if (!dev->membuff) return 0;
|
|
||||||
if (dev->bufptr >= (dev->bufsize + 2)) return 0; // end of stream
|
|
||||||
|
|
||||||
if ((dev->bufptr + nd) > (dev->bufsize + 2)) nd = (dev->bufsize + 2) - dev->bufptr;
|
upng_decode(upng);
|
||||||
|
if (upng_get_error(upng) != UPNG_EOK) {
|
||||||
|
LOG(LL_ERROR, ("PNG decode error"));
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (upng_get_format(upng) != UPNG_RGB8) {
|
||||||
|
LOG(LL_ERROR, ("PNG is not in RGB8 format"));
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
// Do stuff with upng data
|
||||||
|
LOG(LL_INFO, ("%s: w=%d h=%d size=%d bpp=%d bitdepth=%d pixelsize=%d", fname, upng_get_width(upng), upng_get_height(upng), upng_get_size(upng), upng_get_bpp(upng), upng_get_bitdepth(upng), upng_get_pixelsize(upng)));
|
||||||
|
|
||||||
if (buff) { // Read nd bytes from the input strem
|
png_buf = upng_get_buffer(upng);
|
||||||
memcpy(buff, dev->membuff + dev->bufptr, nd);
|
disp_select();
|
||||||
dev->bufptr += nd;
|
for(j=0; j<upng_get_height(upng); j++) {
|
||||||
return nd; // Returns number of bytes read
|
for(i=0; i<upng_get_width(upng); i++) {
|
||||||
}
|
pixel.r = *png_buf++;
|
||||||
else { // Remove nd bytes from the input stream
|
pixel.g = *png_buf++;
|
||||||
dev->bufptr += nd;
|
pixel.b = *png_buf++;
|
||||||
return nd;
|
mgos_ili9341_drawPixel(i, j, pixel, 0);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// User defined call-back function to output RGB bitmap to display device
|
|
||||||
//----------------------
|
|
||||||
static UINT tjd_output (
|
|
||||||
JDEC* jd, // Decompression object of current session
|
|
||||||
void* bitmap, // Bitmap data to be output
|
|
||||||
JRECT* rect // Rectangular region to output
|
|
||||||
)
|
|
||||||
{
|
|
||||||
// Device identifier for the session (5th argument of jd_prepare function)
|
|
||||||
JPGIODEV *dev = (JPGIODEV*)jd->device;
|
|
||||||
|
|
||||||
// ** Put the rectangular into the display device **
|
|
||||||
int x;
|
|
||||||
int y;
|
|
||||||
int dleft, dtop, dright, dbottom;
|
|
||||||
BYTE *src = (BYTE*)bitmap;
|
|
||||||
|
|
||||||
int left = rect->left + dev->x;
|
|
||||||
int top = rect->top + dev->y;
|
|
||||||
int right = rect->right + dev->x;
|
|
||||||
int bottom = rect->bottom + dev->y;
|
|
||||||
|
|
||||||
if ((left > dispWin.x2) || (top > dispWin.y2)) return 1; // out of screen area, return
|
|
||||||
if ((right < dispWin.x1) || (bottom < dispWin.y1)) return 1;// out of screen area, return
|
|
||||||
|
|
||||||
if (left < dispWin.x1) dleft = dispWin.x1;
|
|
||||||
else dleft = left;
|
|
||||||
if (top < dispWin.y1) dtop = dispWin.y1;
|
|
||||||
else dtop = top;
|
|
||||||
if (right > dispWin.x2) dright = dispWin.x2;
|
|
||||||
else dright = right;
|
|
||||||
if (bottom > dispWin.y2) dbottom = dispWin.y2;
|
|
||||||
else dbottom = bottom;
|
|
||||||
|
|
||||||
if ((dleft > dispWin.x2) || (dtop > dispWin.y2)) return 1; // out of screen area, return
|
|
||||||
if ((dright < dispWin.x1) || (dbottom < dispWin.y1)) return 1; // out of screen area, return
|
|
||||||
|
|
||||||
uint32_t len = ((dright-dleft+1) * (dbottom-dtop+1)); // calculate length of data
|
|
||||||
|
|
||||||
|
|
||||||
if ((len > 0) && (len <= JPG_IMAGE_LINE_BUF_SIZE)) {
|
|
||||||
uint8_t *dest = (uint8_t *)(dev->linbuf[dev->linbuf_idx]);
|
|
||||||
|
|
||||||
for (y = top; y <= bottom; y++) {
|
|
||||||
for (x = left; x <= right; x++) {
|
|
||||||
// Clip to display area
|
|
||||||
if ((x >= dleft) && (y >= dtop) && (x <= dright) && (y <= dbottom)) {
|
|
||||||
*dest++ = (*src++) & 0xFC;
|
|
||||||
*dest++ = (*src++) & 0xFC;
|
|
||||||
*dest++ = (*src++) & 0xFC;
|
|
||||||
}
|
|
||||||
else src += 3; // skip
|
|
||||||
}
|
|
||||||
}
|
|
||||||
wait_trans_finish(1);
|
|
||||||
send_data(dleft, dtop, dright, dbottom, len, dev->linbuf[dev->linbuf_idx]);
|
|
||||||
dev->linbuf_idx = ((dev->linbuf_idx + 1) & 1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
wait_trans_finish(1);
|
|
||||||
LOG(LL_ERROR, ("Data size error: %d jpg: (%d,%d,%d,%d) disp: (%d,%d,%d,%d)", len, left,top,right,bottom, dleft,dtop,dright,dbottom));
|
|
||||||
return 0; // stop decompression
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1; // Continue to decompression
|
|
||||||
}
|
|
||||||
|
|
||||||
// tft.jpgimage(X, Y, scale, file_name, buf, size]
|
|
||||||
// X & Y can be < 0 !
|
|
||||||
//==================================================================================
|
|
||||||
void mgos_ili9341_jpg_image(int x, int y, uint8_t scale, char *fname, uint8_t *buf, int size)
|
|
||||||
{
|
|
||||||
JPGIODEV dev;
|
|
||||||
struct stat sb;
|
|
||||||
char *work = NULL; // Pointer to the working buffer (must be 4-byte aligned)
|
|
||||||
UINT sz_work = 3800; // Size of the working buffer (must be power of 2)
|
|
||||||
JDEC jd; // Decompression object (70 bytes)
|
|
||||||
JRESULT rc;
|
|
||||||
|
|
||||||
dev.linbuf[0] = NULL;
|
|
||||||
dev.linbuf[1] = NULL;
|
|
||||||
dev.linbuf_idx = 0;
|
|
||||||
|
|
||||||
dev.fhndl = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
x+= dispWin.x1;
|
|
||||||
y+= dispWin.y1;
|
|
||||||
|
|
||||||
if (fname == NULL) {
|
|
||||||
// image from buffer
|
|
||||||
dev.membuff = buf;
|
|
||||||
dev.bufsize = size;
|
|
||||||
dev.bufptr = 0;
|
|
||||||
}
|
}
|
||||||
else {
|
}
|
||||||
// image from file
|
disp_deselect();
|
||||||
dev.membuff = NULL;
|
|
||||||
dev.bufsize = 0;
|
|
||||||
dev.bufptr = 0;
|
|
||||||
|
|
||||||
if (stat(fname, &sb) != 0) {
|
|
||||||
if (image_debug) LOG(LL_ERROR, ("File error: %ss", strerror(errno)));
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev.fhndl = fopen(fname, "r");
|
|
||||||
if (!dev.fhndl) {
|
|
||||||
if (image_debug) LOG(LL_ERROR, ("Error opening file: %s", strerror(errno)));
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scale > 3) scale = 3;
|
|
||||||
|
|
||||||
work = malloc(sz_work);
|
|
||||||
if (work) {
|
|
||||||
if (dev.membuff) rc = jd_prepare(&jd, tjd_buf_input, (void *)work, sz_work, &dev);
|
|
||||||
else rc = jd_prepare(&jd, tjd_input, (void *)work, sz_work, &dev);
|
|
||||||
if (rc == JDR_OK) {
|
|
||||||
if (x == CENTER) x = ((dispWin.x2 - dispWin.x1 + 1 - (int)(jd.width >> scale)) / 2) + dispWin.x1;
|
|
||||||
else if (x == RIGHT) x = dispWin.x2 + 1 - (int)(jd.width >> scale);
|
|
||||||
|
|
||||||
if (y == CENTER) y = ((dispWin.y2 - dispWin.y1 + 1 - (int)(jd.height >> scale)) / 2) + dispWin.y1;
|
|
||||||
else if (y == BOTTOM) y = dispWin.y2 + 1 - (int)(jd.height >> scale);
|
|
||||||
|
|
||||||
if (x < ((dispWin.x2-1) * -1)) x = (dispWin.x2-1) * -1;
|
|
||||||
if (y < ((dispWin.y2-1)) * -1) y = (dispWin.y2-1) * -1;
|
|
||||||
if (x > (dispWin.x2-1)) x = dispWin.x2 - 1;
|
|
||||||
if (y > (dispWin.y2-1)) y = dispWin.y2-1;
|
|
||||||
|
|
||||||
dev.x = x;
|
|
||||||
dev.y = y;
|
|
||||||
|
|
||||||
dev.linbuf[0] = heap_caps_malloc(JPG_IMAGE_LINE_BUF_SIZE*3, MALLOC_CAP_DMA);
|
|
||||||
if (dev.linbuf[0] == NULL) {
|
|
||||||
if (image_debug) LOG(LL_ERROR, ("Error allocating line buffer #0"));
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
dev.linbuf[1] = heap_caps_malloc(JPG_IMAGE_LINE_BUF_SIZE*3, MALLOC_CAP_DMA);
|
|
||||||
if (dev.linbuf[1] == NULL) {
|
|
||||||
if (image_debug) LOG(LL_ERROR, ("Error allocating line buffer #1"));
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start to decode the JPEG file
|
|
||||||
disp_select();
|
|
||||||
rc = jd_decomp(&jd, tjd_output, scale);
|
|
||||||
disp_deselect();
|
|
||||||
|
|
||||||
if (rc != JDR_OK) {
|
|
||||||
if (image_debug) LOG(LL_ERROR, ("Jpg decompression error %d", rc));
|
|
||||||
}
|
|
||||||
if (image_debug) LOG(LL_INFO, ("Jpg size: %dx%d, position; %d,%d, scale: %d, bytes used: %d", jd.width, jd.height, x, y, scale, jd.sz_pool));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (image_debug) LOG(LL_ERROR, ("jpg prepare error %d", rc));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (image_debug) LOG(LL_ERROR, ("work buffer allocation error"));
|
|
||||||
}
|
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
if (work) free(work); // free work buffer
|
if (upng) upng_free(upng);
|
||||||
if (dev.linbuf[0]) free(dev.linbuf[0]);
|
return ret;
|
||||||
if (dev.linbuf[1]) free(dev.linbuf[1]);
|
|
||||||
if (dev.fhndl) fclose(dev.fhndl); // close input file
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//====================================================================================
|
|
||||||
int mgos_ili9341_bmp_image(int x, int y, uint8_t scale, char *fname, uint8_t *imgbuf, int size)
|
|
||||||
{
|
|
||||||
FILE *fhndl = NULL;
|
|
||||||
struct stat sb;
|
|
||||||
int i, err=0;
|
|
||||||
int img_xsize, img_ysize, img_xstart, img_xlen, img_ystart, img_ylen;
|
|
||||||
int img_pos, img_pix_pos, scan_lines, rd_len;
|
|
||||||
uint8_t tmpc;
|
|
||||||
uint16_t wtemp;
|
|
||||||
uint32_t temp;
|
|
||||||
int disp_xstart, disp_xend, disp_ystart, disp_yend;
|
|
||||||
uint8_t buf[56];
|
|
||||||
char err_buf[64];
|
|
||||||
uint8_t *line_buf[2] = {NULL,NULL};
|
|
||||||
uint8_t lb_idx = 0;
|
|
||||||
uint8_t *scale_buf = NULL;
|
|
||||||
uint8_t scale_pix;
|
|
||||||
uint16_t co[3] = {0,0,0}; // RGB sum
|
|
||||||
uint8_t npix;
|
|
||||||
|
|
||||||
if (scale > 7) scale = 7;
|
|
||||||
scale_pix = scale+1; // scale factor ( 1~8 )
|
|
||||||
|
|
||||||
if (fname) {
|
|
||||||
// * File name is given, reading image from file
|
|
||||||
if (stat(fname, &sb) != 0) {
|
|
||||||
sprintf(err_buf, "opening file");
|
|
||||||
err = -1;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
size = sb.st_size;
|
|
||||||
fhndl = fopen(fname, "r");
|
|
||||||
if (!fhndl) {
|
|
||||||
sprintf(err_buf, "opening file");
|
|
||||||
err = -2;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
i = fread(buf, 1, 54, fhndl); // read header
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// * Reading image from buffer
|
|
||||||
if ((imgbuf) && (size > 54)) {
|
|
||||||
memcpy(buf, imgbuf, 54);
|
|
||||||
i = 54;
|
|
||||||
}
|
|
||||||
else i = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
sprintf(err_buf, "reading header");
|
|
||||||
if (i != 54) {err = -3; goto exit;}
|
|
||||||
|
|
||||||
// ** Check image header and get image properties
|
|
||||||
if ((buf[0] != 'B') || (buf[1] != 'M')) {err=-4; goto exit;} // accept only images with 'BM' id
|
|
||||||
|
|
||||||
memcpy(&temp, buf+2, 4); // file size
|
|
||||||
if (temp != size) {err=-5; goto exit;}
|
|
||||||
|
|
||||||
memcpy(&img_pos, buf+10, 4); // start of pixel data
|
|
||||||
|
|
||||||
memcpy(&temp, buf+14, 4); // BMP header size
|
|
||||||
if (temp != 40) {err=-6; goto exit;}
|
|
||||||
|
|
||||||
memcpy(&wtemp, buf+26, 2); // the number of color planes
|
|
||||||
if (wtemp != 1) {err=-7; goto exit;}
|
|
||||||
|
|
||||||
memcpy(&wtemp, buf+28, 2); // the number of bits per pixel
|
|
||||||
if (wtemp != 24) {err=-8; goto exit;}
|
|
||||||
|
|
||||||
memcpy(&temp, buf+30, 4); // the compression method being used
|
|
||||||
if (temp != 0) {err=-9; goto exit;}
|
|
||||||
|
|
||||||
memcpy(&img_xsize, buf+18, 4); // the bitmap width in pixels
|
|
||||||
memcpy(&img_ysize, buf+22, 4); // the bitmap height in pixels
|
|
||||||
|
|
||||||
|
|
||||||
// * scale image dimensions
|
|
||||||
|
|
||||||
img_xlen = img_xsize / scale_pix; // image display horizontal size
|
|
||||||
img_ylen = img_ysize / scale_pix; // image display vertical size
|
|
||||||
|
|
||||||
if (x == CENTER) x = ((dispWin.x2 - dispWin.x1 + 1 - img_xlen) / 2) + dispWin.x1;
|
|
||||||
else if (x == RIGHT) x = dispWin.x2 + 1 - img_xlen;
|
|
||||||
|
|
||||||
if (y == CENTER) y = ((dispWin.y2 - dispWin.y1 + 1 - img_ylen) / 2) + dispWin.y1;
|
|
||||||
else if (y == BOTTOM) y = dispWin.y2 + 1 - img_ylen;
|
|
||||||
|
|
||||||
if ((x < ((dispWin.x2 + 1) * -1)) || (x > (dispWin.x2 + 1)) || (y < ((dispWin.y2 + 1) * -1)) || (y > (dispWin.y2 + 1))) {
|
|
||||||
sprintf(err_buf, "out of display area (%d,%d", x, y);
|
|
||||||
err = -10;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ** set display and image areas
|
|
||||||
if (x < dispWin.x1) {
|
|
||||||
disp_xstart = dispWin.x1;
|
|
||||||
img_xstart = -x; // image pixel line X offset
|
|
||||||
img_xlen += x;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
disp_xstart = x;
|
|
||||||
img_xstart = 0;
|
|
||||||
}
|
|
||||||
if (y < dispWin.y1) {
|
|
||||||
disp_ystart = dispWin.y1;
|
|
||||||
img_ystart = -y; // image pixel line Y offset
|
|
||||||
img_ylen += y;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
disp_ystart = y;
|
|
||||||
img_ystart = 0;
|
|
||||||
}
|
|
||||||
disp_xend = disp_xstart + img_xlen - 1;
|
|
||||||
disp_yend = disp_ystart + img_ylen - 1;
|
|
||||||
if (disp_xend > dispWin.x2) {
|
|
||||||
disp_xend = dispWin.x2;
|
|
||||||
img_xlen = disp_xend - disp_xstart + 1;
|
|
||||||
}
|
|
||||||
if (disp_yend > dispWin.y2) {
|
|
||||||
disp_yend = dispWin.y2;
|
|
||||||
img_ylen = disp_yend - disp_ystart + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((img_xlen < 8) || (img_ylen < 8) || (img_xstart >= (img_xsize-2)) || ((img_ysize - img_ystart) < 2)) {
|
|
||||||
sprintf(err_buf, "image too small");
|
|
||||||
err = -11;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ** Allocate memory for 2 lines of image pixels
|
|
||||||
line_buf[0] = heap_caps_malloc(img_xsize*3, MALLOC_CAP_DMA);
|
|
||||||
if (line_buf[0] == NULL) {
|
|
||||||
sprintf(err_buf, "allocating line buffer #1");
|
|
||||||
err=-12;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
line_buf[1] = heap_caps_malloc(img_xsize*3, MALLOC_CAP_DMA);
|
|
||||||
if (line_buf[1] == NULL) {
|
|
||||||
sprintf(err_buf, "allocating line buffer #2");
|
|
||||||
err=-13;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scale) {
|
|
||||||
// Allocate memory for scale buffer
|
|
||||||
rd_len = img_xlen * 3 * scale_pix;
|
|
||||||
scale_buf = malloc(rd_len*scale_pix);
|
|
||||||
if (scale_buf == NULL) {
|
|
||||||
sprintf(err_buf, "allocating scale buffer");
|
|
||||||
err=-14;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else rd_len = img_xlen * 3;
|
|
||||||
|
|
||||||
// ** ***************************************************** **
|
|
||||||
// ** BMP images are stored in file from LAST to FIRST line **
|
|
||||||
// ** ***************************************************** **
|
|
||||||
|
|
||||||
/* Used variables:
|
|
||||||
img_xsize horizontal image size in pixels
|
|
||||||
img_ysize number of image lines
|
|
||||||
img_xlen image display horizontal scaled size in pixels
|
|
||||||
img_ylen image display vertical scaled size in pixels
|
|
||||||
img_xstart first pixel in line to be displayed
|
|
||||||
img_ystart first image line to be displayed
|
|
||||||
img_xlen number of pixels in image line to be displayed, starting with 'img_xstart'
|
|
||||||
img_ylen number of lines in image to be displayed, starting with 'img_ystart'
|
|
||||||
rd_len length of color data which are read from image line in bytes
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Set position in image to the first color data (beginning of the LAST line)
|
|
||||||
img_pos += (img_ystart * (img_xsize*3));
|
|
||||||
if (fhndl) {
|
|
||||||
if (fseek(fhndl, img_pos, SEEK_SET) != 0) {
|
|
||||||
sprintf(err_buf, "file seek at %d", img_pos);
|
|
||||||
err = -15;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (image_debug) LOG(LL_INFO, ("BMP: image size: (%d,%d) scale: %d disp size: (%d,%d) img xofs: %d img yofs: %d at: %d,%d; line buf: 2* %d scale buf: %d",
|
|
||||||
img_xsize, img_ysize, scale_pix, img_xlen, img_ylen, img_xstart, img_ystart, disp_xstart, disp_ystart, img_xsize*3, ((scale) ? (rd_len*scale_pix) : 0)));
|
|
||||||
|
|
||||||
// * Select the display
|
|
||||||
disp_select();
|
|
||||||
|
|
||||||
while ((disp_yend >= disp_ystart) && ((img_pos + (img_xsize*3)) <= size)) {
|
|
||||||
if (img_pos > size) {
|
|
||||||
sprintf(err_buf, "EOF reached: %d > %d", img_pos, size);
|
|
||||||
err = -16;
|
|
||||||
goto exit1;
|
|
||||||
}
|
|
||||||
if (scale == 0) {
|
|
||||||
// Read the line of color data into color buffer
|
|
||||||
if (fhndl) {
|
|
||||||
i = fread(line_buf[lb_idx], 1, img_xsize*3, fhndl); // read line from file
|
|
||||||
if (i != (img_xsize*3)) {
|
|
||||||
sprintf(err_buf, "file read at %d (%d<>%d)", img_pos, i, img_xsize*3);
|
|
||||||
err = -16;
|
|
||||||
goto exit1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else memcpy(line_buf[lb_idx], imgbuf+img_pos, img_xsize*3);
|
|
||||||
|
|
||||||
if (img_xstart > 0) memmove(line_buf[lb_idx], line_buf[lb_idx]+(img_xstart*3), rd_len);
|
|
||||||
// Convert colors BGR-888 (BMP) -> RGB-888 (DISPLAY) ===
|
|
||||||
for (i=0; i < rd_len; i += 3) {
|
|
||||||
tmpc = line_buf[lb_idx][i+2] & 0xfc; // save R
|
|
||||||
line_buf[lb_idx][i+2] = line_buf[lb_idx][i] & 0xfc; // B -> R
|
|
||||||
line_buf[lb_idx][i] = tmpc; // R -> B
|
|
||||||
line_buf[lb_idx][i+1] &= 0xfc; // G
|
|
||||||
}
|
|
||||||
img_pos += (img_xsize*3);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// scale image, read 'scale_pix' lines and find the average color
|
|
||||||
for (scan_lines=0; scan_lines<scale_pix; scan_lines++) {
|
|
||||||
if (img_pos > size) break;
|
|
||||||
if (fhndl) {
|
|
||||||
i = fread(line_buf[lb_idx], 1, img_xsize*3, fhndl); // read line from file
|
|
||||||
if (i != (img_xsize*3)) {
|
|
||||||
sprintf(err_buf, "file read at %d (%d<>%d)", img_pos, i, img_xsize*3);
|
|
||||||
err = -17;
|
|
||||||
goto exit1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else memcpy(line_buf[lb_idx], imgbuf+img_pos, img_xsize*3);
|
|
||||||
img_pos += (img_xsize*3);
|
|
||||||
|
|
||||||
// copy only data which are displayed to scale buffer
|
|
||||||
memcpy(scale_buf + (rd_len * scan_lines), line_buf[lb_idx]+img_xstart, rd_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Populate display line buffer
|
|
||||||
for (int n=0;n<(img_xlen*3);n += 3) {
|
|
||||||
memset(co, 0, sizeof(co)); // initialize color sum
|
|
||||||
npix = 0; // initialize number of pixels in scale rectangle
|
|
||||||
|
|
||||||
// sum all pixels in scale rectangle
|
|
||||||
for (int sc_line=0; sc_line<scan_lines; sc_line++) {
|
|
||||||
// Get colors position in scale buffer
|
|
||||||
img_pix_pos = (rd_len * sc_line) + (n * scale_pix);
|
|
||||||
|
|
||||||
for (int sc_col=0; sc_col<scale_pix; sc_col++) {
|
|
||||||
co[0] += scale_buf[img_pix_pos];
|
|
||||||
co[1] += scale_buf[img_pix_pos + 1];
|
|
||||||
co[2] += scale_buf[img_pix_pos + 2];
|
|
||||||
npix++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Place the average in display buffer, convert BGR-888 (BMP) -> RGB-888 (DISPLAY)
|
|
||||||
line_buf[lb_idx][n+2] = (uint8_t)(co[0] / npix); // B
|
|
||||||
line_buf[lb_idx][n+1] = (uint8_t)(co[1] / npix); // G
|
|
||||||
line_buf[lb_idx][n] = (uint8_t)(co[2] / npix); // R
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wait_trans_finish(1);
|
|
||||||
send_data(disp_xstart, disp_yend, disp_xend, disp_yend, img_xlen, (color_t *)line_buf[lb_idx]);
|
|
||||||
lb_idx = (lb_idx + 1) & 1; // change buffer
|
|
||||||
|
|
||||||
disp_yend--;
|
|
||||||
}
|
|
||||||
err = 0;
|
|
||||||
exit1:
|
|
||||||
disp_deselect();
|
|
||||||
exit:
|
|
||||||
if (scale_buf) free(scale_buf);
|
|
||||||
if (line_buf[0]) free(line_buf[0]);
|
|
||||||
if (line_buf[1]) free(line_buf[1]);
|
|
||||||
if (fhndl) fclose(fhndl);
|
|
||||||
if ((err) && (image_debug)) LOG(LL_ERROR, ("Error: %d [%s]", err, err_buf));
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void mgos_ili9341_set_fg(const color_t *color)
|
void mgos_ili9341_set_fg(const color_t *color)
|
||||||
{
|
{
|
||||||
_fg = *color;
|
_fg = *color;
|
||||||
|
1281
libs/ili9341/src/upng.c
Normal file
1281
libs/ili9341/src/upng.c
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user