arch add small 3rd party libs to lvgl (#2569)

* move png, sjpg, bmp, gif, fs_if to extra/libs

* reorganize the examples

* update lv_conf_internal.h

* fix warnings

* add freetype

* remove unused assets

* add the new libs to build tests

* update the docs
This commit is contained in:
Gabor Kiss-Vamosi
2021-10-04 14:34:11 +02:00
committed by GitHub
parent b20a706112
commit 18f61c5f77
69 changed files with 17841 additions and 0 deletions

42
docs/libs/bmp.md Normal file
View File

@@ -0,0 +1,42 @@
```eval_rst
.. include:: /header.rst
:github_url: |github_link_base|/libs/bmp.md
```
# BMP decoder
This extension allows the use of BMP images in LVGL.
This implementation uses [bmp-decoder](https://github.com/caj-johnson/bmp-decoder) library.
The pixel are read on demand (not the whole image is loaded) so using BMP images requires very little RAM.
If enabled in `lv_conf.h` by `LV_USE_BMP` LVGL will register a new image decoder automatically so BMP files can be directly used as image sources. For example:
```
lv_img_set_src(my_img, "S:path/to/picture.bmp");
```
Note that, a file system driver needs to registered to open images from files. Read more about it [here](https://docs.lvgl.io/master/overview/file-system.html) or just enable one in `lv_conf.h` with `LV_USE_FS_...`
## Limitations
- Only BMP files are supported and BMP images as C array (`lv_img_dsc_t`) are not. It's because there is no practical differences between how the BMP files and LVGL's image format stores the image data.
- BMP files can be loaded only from file. If you want to store them in flash it's better to convert them to C array with [LVGL's image converter](https://lvgl.io/tools/imageconverter).
- The BMP files color format needs to match with `LV_COLOR_DEPTH`. Use GIMP to save the image in the required format.
Both RGB888 and ARGB888 works with `LV_COLOR_DEPTH 32`
- Palette is not supported.
- Because not the whole image is read in can not be zoomed or rotated.
## Example
```eval_rst
.. include:: ../../../examples/libs/bmp/index.rst
```
## API
```eval_rst
.. doxygenfile:: lv_bmp.h
:project: lvgl
```

39
docs/libs/freetype.md Normal file
View File

@@ -0,0 +1,39 @@
```eval_rst
.. include:: /header.rst
:github_url: |github_link_base|/libs/bmp.md
```
# FreeType support
Interface to [FreeType](https://www.freetype.org/) to generate font bitmaps run time.
## Install FreeType
- Download Freetype from [here](https://sourceforge.net/projects/freetype/files/)
- `make`
- `sudo make install`
## Add FreeType to your project
- Add include path: `/usr/include/freetype2` (for GCC: `-I/usr/include/freetype2 -L/usr/local/lib`)
- Add library: `freetype` (for GCC: `-L/usr/local/lib -lfreetype`)
## Usage
Enable `LV_USE_FREETYPE` in `lv_conf.h`.
See the examples below.
Note that, the FreeType extension doesn't use LVGL's file system.
You can simply pass the path to the font as usual on your operating system or platform.
## Learn more
- FreeType [tutorial](https://www.freetype.org/freetype2/docs/tutorial/step1.html)
- LVGL's [font interface](https://docs.lvgl.io/v7/en/html/overview/font.html#add-a-new-font-engine)
## API
```eval_rst
.. doxygenfile:: lv_freetype.h
:project: lvgl
```

19
docs/libs/fs.md Normal file
View File

@@ -0,0 +1,19 @@
```eval_rst
.. include:: /header.rst
:github_url: |github_link_base|/libs/fs.md
```
# File System Interfaces
LVGL has a [File system](https://docs.lvgl.io/master/overview/file-system.html) module to provides an abstraction layer for various file system drivers.
LVG has build in support for
- [FATFS](http://elm-chan.org/fsw/ff/00index_e.html)
- STDIO (Linux and Windows using C standard function .e.g fopen, fread)
- POSIX (Linux and Windows using POSIX function .e.g open, read)
You still need to provide the drivers and libraries, this extensions provide only the bridge between FATFS, STDIO, POSIX and LVGL.
## Usage
In `lv_conf.h` set a driver letter for one or more `LV_FS_USE_...` define(s). After that you can access files using that driver letter. Setting `'\0'` will disable use of that interface.

48
docs/libs/gif.md Normal file
View File

@@ -0,0 +1,48 @@
```eval_rst
.. include:: /header.rst
:github_url: |github_link_base|/libs/gif.md
```
# GIF decoder
Allow to use of GIF images in LVGL. Based on https://github.com/lecram/gifdec
When enabled in `lv_conf.h` with `LV_USE_GIF` `lv_gif_create(parent)` can be used to create a gif widget.
`lv_gif_set_src(obj, src)` works very similarly to `lv_img_set_src`. As source It also accepts images as variables (`lv_img_dsc_t`) or files.
## Convert GIF files to C array
To convert a GIF file to byte values array use [LVGL's online converter](https://lvgl.io/tools/imageconverter). Select "Raw" color format and "C array" Output format.
## Use GIF images from file
For example:
```c
lv_gif_set_src(obj, "S:path/to/example.gif");
```
Note that, a file system driver needs to regsitered to open images from files. Read more about it [here](https://docs.lvgl.io/master/overview/file-system.html) or just enable one in `lv_conf.h` with `LV_USE_FS_...`
## Memory requirements
To decode and display a GIF animation the following amount of RAM is required:
- `LV_COLOR_DEPTH 8`: 3 x image width x image height
- `LV_COLOR_DEPTH 16`: 4 x image width x image height
- `LV_COLOR_DEPTH 32`: 5 x image width x image height
## Example
```eval_rst
.. include:: ../../../examples/libs/gif/index.rst
```
## API
```eval_rst
.. doxygenfile:: lv_gif.h
:project: lvgl
```

21
docs/libs/index.md Normal file
View File

@@ -0,0 +1,21 @@
```eval_rst
.. include:: /header.rst
:github_url: |github_link_base|/libs/index.md
```
# 3rd party libraries
```eval_rst
.. toctree::
:maxdepth: 1
fs
bpm
jpg
png
gif
freetype
qrcode
```

31
docs/libs/png.md Normal file
View File

@@ -0,0 +1,31 @@
```eval_rst
.. include:: /header.rst
:github_url: |github_link_base|/libs/png.md
```
# PNG decoder
Allow the use of PNG images in LVGL. This implementation uses [lodepng](https://github.com/lvandeve/lodepng) library.
If enabled in `lv_conf.h` by `LV_USE_PNG` LVGL will register a new image decoder automatically so PNG files can be directly used as any other image sources.
Note that, a file system driver needs to registered to open images from files. Read more about it [here](https://docs.lvgl.io/master/overview/file-system.html) or just enable one in `lv_conf.h` with `LV_USE_FS_...`
The whole PNG image is decoded so during decoding RAM equals to `image width x image height x 4` bytes are required.
As it might take significant time to decode PNG images LVGL's [images caching](https://docs.lvgl.io/master/overview/image.html#image-caching) feature can be useful.
## Example
```eval_rst
.. include:: ../../../examples/libs/png/index.rst
```
## API
```eval_rst
.. doxygenfile:: lv_png.h
:project: lvgl

28
docs/libs/qrcode.md Normal file
View File

@@ -0,0 +1,28 @@
```eval_rst
.. include:: /header.rst
:github_url: |github_link_base|/libs/qrcode.md
```
# QR code
QR code generation with LVGL. Uses [QR-Code-generator](https://github.com/nayuki/QR-Code-generator) by [nayuki](https://github.com/nayuki).
## Get started
- Download or clone this repository
- [Download](https://github.com/littlevgl/lv_lib_qrcode.git) from GitHub
- Clone: git clone https://github.com/littlevgl/lv_lib_qrcode.git
- Include the library: `#include "lv_lib_qrcode/lv_qrcode.h"`
- Test with the following code:
```c
const char * data = "Hello world";
/*Create a 100x100 QR code*/
lv_obj_t * qr = lv_qrcode_create(lv_scr_act(), 100, lv_color_hex3(0x33f), lv_color_hex3(0xeef));
/*Set data*/
lv_qrcode_update(qr, data, strlen(data));
```
## Notes
- QR codes with less data are smaller but they scaled by an integer numbers number to best fit to the given size

77
docs/libs/sjpg.md Normal file
View File

@@ -0,0 +1,77 @@
```eval_rst
.. include:: /header.rst
:github_url: |github_link_base|/libs/sjpg.md
```
# JPG decoder
Allow the use of JPG images in LVGL. Besides that it also allows the use of a custom format, called Split JPG (SJPG), which can be decided in more optimal way on embedded systems.
## Overview
- Supports both normal JPG and the custom SJPG formats.
- Decoding normal JPG consumes RAM with the size fo the whole uncompressed image (recommended only for devices with more RAM)
- SJPG is a custom format based on "normal" JPG and specially made for LVGL.
- SJPG is 'split-jpeg' which is a bundle of small jpeg fragments with an sjpg header.
- SJPG size will be almost comparable to the jpg file or might be a slightly larger.
- File read from file and c-array are implemented.
- SJPEG frame fragment cache enables fast fetching of lines if availble in cache.
- By default the sjpg image cache will be image width * 2 * 16 bytes (can be modified)
- Currently only 16 bit image format is supported (TODO)
- Only the required partion of the JPG and SJPG images are decoded, therefore they can't be zoomed or rotated.
## Usage
If enabled in `lv_conf.h` by `LV_USE_SJPG` LVGL will register a new image decoder automatically so JPG and SJPG files can be directly used as image sources. For example:
```
lv_img_set_src(my_img, "S:path/to/picture.jpg");
```
Note that, a file system driver needs to registered to open images from files. Read more about it [here](https://docs.lvgl.io/master/overview/file-system.html) or just enable one in `lv_conf.h` with `LV_USE_FS_...`
## Converter
### Converting JPG to C array
- Use lvgl online tool https://lvgl.io/tools/imageconverter
- Color format = RAW, output format = C Array
### Converting JPG to SJPG
python3 and the PIL library required. (PIL can be installed with `pip3 install pillow`)
To create SJPG from JPG:
- Copy the image to convert into `lvgl/scripts`
- `cd lvgl/scripts`
- `python3 jpg_to_sjpg.py image_to_convert.jpg`. It creates both a C files and an SJPG image.
The expected result is:
```sh
Conversion started...
Input:
image_to_convert.jpg
RES = 640 x 480
Output:
Time taken = 1.66 sec
bin size = 77.1 KB
walpaper.sjpg (bin file)
walpaper.c (c array)
All good!
```
## Example
```eval_rst
.. include:: ../../../examples/libs/sjpg/index.rst
```
## API
```eval_rst
.. doxygenfile:: lv_sjpg.h
:project: lvgl

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

View File

@@ -0,0 +1,6 @@
Open a BMP image from file
"""""""""""""""""""""""""""""""""""""""""""""""
.. lv_example:: libs/bmp/lv_example_bmp_1
:language: c

View File

@@ -0,0 +1,38 @@
/**
* @file lv_example_bmp.h
*
*/
#ifndef LV_EXAMPLE_BMP_H
#define LV_EXAMPLE_BMP_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void lv_example_bmp_1(void);
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_EXAMPLE_BMP_H*/

View File

@@ -0,0 +1,17 @@
#include "../../lv_examples.h"
#if LV_USE_BMP && LV_BUILD_EXAMPLES
/**
* Open a BMP file from a file
*/
void lv_example_bmp_1(void)
{
lv_obj_t * img = lv_img_create(lv_scr_act());
/* Assuming a File system is attached to letter 'A'
* E.g. set LV_USE_FS_STDIO 'A' in lv_conf.h */
lv_img_set_src(img, "A:lvgl/examples/libs/bmp/example_32bit.bmp");
lv_obj_center(img);
}
#endif

Binary file not shown.

View File

@@ -0,0 +1,6 @@
Open a front with FreeTpye
"""""""""""""""""""""""""""""""""""""""""""""""
.. lv_example:: libs/freetype/lv_example_freetype_1
:language: c

View File

@@ -0,0 +1,38 @@
/**
* @file lv_example_freetype.h
*
*/
#ifndef LV_EXAMPLE_FREETYPE_H
#define LV_EXAMPLE_FREETYPE_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void lv_example_freetype_1(void);
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_EXAMPLE_FREETYPE_H*/

View File

@@ -0,0 +1,30 @@
#include "../../lv_examples.h"
#if LV_USE_FREETYPE && LV_BUILD_EXAMPLES
/**
* Load a font with FreeType
*/
void lv_example_freetype_1(void)
{
/*Create a font*/
static lv_ft_info_t info;
/*FreeType uses C standard file system, so no driver letter is required.*/
info.name = "./lvgl/examples/libs/freetype/arial.ttf";
info.weight = 24;
info.style = FT_FONT_STYLE_NORMAL;
lv_ft_font_init(&info);
/*Create style with the new font*/
static lv_style_t style;
lv_style_init(&style);
lv_style_set_text_font(&style, info.font);
lv_style_set_text_align(&style, LV_TEXT_ALIGN_CENTER);
/*Create a label with the new style*/
lv_obj_t * label = lv_label_create(lv_scr_act());
lv_obj_add_style(label, &style, 0);
lv_label_set_text(label, "Hello world\nI'm a font created with FreeType");
lv_obj_center(label);
}
#endif

BIN
examples/libs/gif/bulb.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,6 @@
Open a GIF image from file and variable
"""""""""""""""""""""""""""""""""""""""""""""""
.. lv_example:: libs/bmp/lv_example_gif_1
:language: c

View File

@@ -0,0 +1,38 @@
/**
* @file lv_example_gif.h
*
*/
#ifndef LV_EXAMPLE_GIF_H
#define LV_EXAMPLE_GIF_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void lv_example_gif_1(void);
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_EXAMPLE_GIF_H*/

View File

@@ -0,0 +1,23 @@
#include "../../lv_examples.h"
#if LV_USE_GIF && LV_BUILD_EXAMPLES
/**
* Open a GIF image from a file and a variable
*/
void lv_example_gif_1(void)
{
LV_IMG_DECLARE(img_bulb_gif);
lv_obj_t * img;
img = lv_gif_create(lv_scr_act());
lv_gif_set_src(img, &img_bulb_gif);
lv_obj_align(img, LV_ALIGN_LEFT_MID, 20, 0);
img = lv_gif_create(lv_scr_act());
/* Assuming a File system is attached to letter 'A'
* E.g. set LV_USE_FS_STDIO 'A' in lv_conf.h */
lv_gif_set_src(img, "A:lvgl/examples/libs/gif/bulb.gif");
lv_obj_align(img, LV_ALIGN_RIGHT_MID, -20, 0);
}
#endif

View File

@@ -0,0 +1,43 @@
/**
* @file lv_example_libs.h
*
*/
#ifndef LV_EXAMPLE_LIBS_H
#define LV_EXAMPLE_LIBS_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "bmp/lv_example_bmp.h"
#include "gif/lv_example_gif.h"
#include "png/lv_example_png.h"
#include "sjpg/lv_example_sjpg.h"
#include "qrcode/lv_example_qrcode.h"
#include "freetype/lv_example_freetype.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_EXAMPLE_LIBS_H*/

View File

@@ -0,0 +1,348 @@
#include "../../../lvgl.h"
#if LV_USE_PNG && LV_BUILD_EXAMPLES
#ifndef LV_ATTRIBUTE_MEM_ALIGN
#define LV_ATTRIBUTE_MEM_ALIGN
#endif
#ifndef LV_ATTRIBUTE_IMG_PNG_DECODER_TEST
#define LV_ATTRIBUTE_IMG_PNG_DECODER_TEST
#endif
const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_LARGE_CONST LV_ATTRIBUTE_IMG_PNG_DECODER_TEST uint8_t img_wink_png_map[] = {
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x32, 0x08, 0x06, 0x00, 0x00, 0x00, 0x1e, 0x3f, 0x88,
0xb1, 0x00, 0x00, 0x00, 0x06, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xa0,
0xbd, 0xa7, 0x93, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00,
0x00, 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45,
0x07, 0xe5, 0x05, 0x07, 0x0c, 0x1b, 0x26, 0xad, 0x4b, 0x20, 0x5b, 0x00, 0x00, 0x00, 0x1d, 0x69,
0x54, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43,
0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50,
0x64, 0x2e, 0x65, 0x07, 0x00, 0x00, 0x13, 0x8a, 0x49, 0x44, 0x41, 0x54, 0x68, 0xde, 0xad, 0x9a,
0x69, 0x94, 0x5d, 0xd5, 0x75, 0xe7, 0x7f, 0xe7, 0xdc, 0x7b, 0xdf, 0x7d, 0x43, 0xd5, 0xab, 0xe9,
0x55, 0x49, 0x05, 0xaa, 0xd2, 0x80, 0x10, 0x12, 0x48, 0xa8, 0x24, 0x04, 0x66, 0x72, 0x6c, 0xec,
0xd8, 0xd0, 0x6e, 0x27, 0xc4, 0x6d, 0x4c, 0x08, 0x21, 0xdd, 0xed, 0x24, 0xbd, 0x1c, 0x67, 0x39,
0xcb, 0x6d, 0x33, 0xc7, 0x6e, 0x9b, 0xc6, 0x18, 0x64, 0x90, 0x43, 0xda, 0xb1, 0x1d, 0x7f, 0x31,
0x89, 0x93, 0xb8, 0x33, 0x38, 0x84, 0x15, 0x63, 0xe3, 0x38, 0x84, 0x80, 0x99, 0x67, 0x24, 0x10,
0x83, 0x06, 0x84, 0x84, 0x54, 0x52, 0x95, 0x6a, 0x7e, 0xf5, 0xa6, 0x3b, 0x9c, 0xb3, 0xfb, 0xc3,
0xbd, 0x6f, 0x28, 0xa1, 0xac, 0x0e, 0x8e, 0x6b, 0xad, 0xb3, 0x6e, 0xd5, 0x7b, 0xa7, 0xce, 0xd9,
0xff, 0xb3, 0xa7, 0xff, 0xde, 0xf7, 0x28, 0x7e, 0x8e, 0x9f, 0x97, 0x6f, 0x18, 0xe2, 0xec, 0x3b,
0x8f, 0x03, 0xf0, 0xe0, 0xd5, 0x5b, 0x19, 0x1e, 0xdd, 0xa7, 0x4b, 0xab, 0x95, 0x5a, 0x98, 0xee,
0xe9, 0x6d, 0xcc, 0x95, 0xcf, 0xcb, 0xf5, 0xc8, 0xe6, 0x6c, 0x97, 0x3e, 0x5d, 0x3b, 0x76, 0xd0,
0x51, 0xaa, 0x28, 0x56, 0x10, 0xc3, 0xa2, 0x89, 0xd5, 0x74, 0x58, 0xe3, 0x50, 0xa3, 0xa6, 0x5e,
0x15, 0xed, 0xbf, 0x30, 0x30, 0x5c, 0x38, 0x52, 0x9f, 0x1a, 0x8f, 0xe7, 0xaa, 0x3d, 0xb2, 0xed,
0xee, 0xe3, 0xd2, 0x5e, 0x7f, 0x19, 0x67, 0xdf, 0x39, 0xf9, 0xae, 0x64, 0x52, 0xef, 0x66, 0xf2,
0x4b, 0xd7, 0x0d, 0xb3, 0x65, 0xc7, 0x31, 0x00, 0x7e, 0x70, 0xee, 0x6a, 0xb5, 0xed, 0x13, 0xc7,
0xfd, 0x58, 0x7a, 0x46, 0x95, 0xa9, 0x7c, 0xa2, 0xab, 0xa4, 0xaf, 0xcc, 0xe4, 0xe3, 0xb3, 0xf3,
0xbd, 0x1a, 0x37, 0x23, 0x80, 0x80, 0xa8, 0xe4, 0x69, 0x01, 0x63, 0x51, 0x06, 0xc4, 0x28, 0x6c,
0x03, 0x1a, 0x65, 0xa1, 0x51, 0xd3, 0xc7, 0xeb, 0x55, 0x1e, 0x08, 0x43, 0xef, 0xaf, 0x5d, 0x47,
0xbf, 0x30, 0xb7, 0xa0, 0xcb, 0x5b, 0xef, 0x9e, 0x8a, 0x9a, 0xfb, 0xed, 0xba, 0x6e, 0x19, 0x9b,
0x77, 0x4c, 0xfe, 0xe2, 0x80, 0xec, 0xff, 0xf6, 0xc7, 0x88, 0x8f, 0xfd, 0x88, 0xf5, 0x5f, 0x49,
0xf6, 0x78, 0xe3, 0xcb, 0x5d, 0x5d, 0x5e, 0x2e, 0x7b, 0x6e, 0xb6, 0x18, 0x7f, 0x26, 0xdf, 0x6b,
0xff, 0x4b, 0xd7, 0xa0, 0x42, 0x39, 0x2e, 0x38, 0x59, 0x20, 0x83, 0x68, 0x0f, 0x94, 0x87, 0xd2,
0x39, 0x40, 0x83, 0x44, 0x88, 0xa9, 0x83, 0x09, 0xc0, 0x84, 0xa8, 0x30, 0x40, 0x05, 0x01, 0x84,
0x06, 0x22, 0x45, 0xa3, 0x6c, 0xa9, 0x2e, 0xea, 0xb7, 0xea, 0x81, 0xf7, 0x4d, 0x1b, 0xdb, 0xfb,
0x0e, 0x8e, 0x17, 0x0f, 0x5f, 0xf2, 0xdd, 0x23, 0x31, 0xc0, 0xab, 0x5f, 0x7b, 0x2f, 0x67, 0xdd,
0xf8, 0xd8, 0x7f, 0x1c, 0xc8, 0xae, 0x1b, 0x47, 0xd8, 0xfc, 0xb5, 0xc3, 0x00, 0xfc, 0xf4, 0xd2,
0x62, 0x66, 0xed, 0x07, 0x33, 0x9b, 0xb3, 0xdd, 0xe6, 0xf3, 0xdd, 0x83, 0x72, 0x55, 0xae, 0x17,
0x54, 0xa6, 0x1b, 0x71, 0xfb, 0x20, 0xbb, 0x12, 0xd5, 0xb3, 0x09, 0x95, 0x3f, 0x1d, 0x72, 0x23,
0xe0, 0xf5, 0x82, 0xd2, 0xed, 0x85, 0x24, 0x86, 0x60, 0x06, 0xea, 0x87, 0x91, 0xea, 0x5e, 0x98,
0x7f, 0x05, 0x16, 0x0f, 0x41, 0x75, 0x0e, 0x55, 0xab, 0xa0, 0x02, 0x4b, 0x54, 0x83, 0xc5, 0xb2,
0x3a, 0xdc, 0x08, 0xdd, 0xdb, 0xe6, 0xe6, 0xd5, 0x8f, 0x37, 0x7d, 0x7d, 0x61, 0x1c, 0xe0, 0xa5,
0xeb, 0x57, 0xb0, 0xe5, 0xae, 0x23, 0x3f, 0x3f, 0x90, 0x5d, 0xd7, 0x95, 0xd8, 0xbc, 0x63, 0x3a,
0xb5, 0xdb, 0x81, 0xc1, 0xbe, 0x11, 0xf9, 0xaf, 0x85, 0x12, 0x37, 0x15, 0x06, 0x28, 0x39, 0xd9,
0x02, 0xf8, 0xa3, 0xd0, 0x77, 0x1e, 0xaa, 0xff, 0x62, 0xc8, 0xad, 0x04, 0x31, 0xe9, 0xb0, 0x24,
0xf6, 0x74, 0x92, 0xed, 0x54, 0x3a, 0x50, 0x50, 0x3f, 0x02, 0x33, 0xcf, 0x20, 0x53, 0xcf, 0xc3,
0xec, 0x01, 0x58, 0x9c, 0x46, 0x87, 0x50, 0xaf, 0xc2, 0x62, 0xc5, 0xf9, 0x49, 0xad, 0xae, 0xef,
0x58, 0x73, 0x6b, 0xf9, 0x31, 0x80, 0x9d, 0x37, 0x0c, 0x33, 0x76, 0xe7, 0xb1, 0x77, 0x0f, 0x64,
0xd7, 0xf5, 0x7d, 0x6c, 0xbe, 0x6b, 0x0e, 0x80, 0x3d, 0xb7, 0x0e, 0x9c, 0xd5, 0x73, 0x8a, 0xfa,
0x52, 0xf7, 0x32, 0x75, 0xa5, 0xdf, 0x25, 0x90, 0x1d, 0x81, 0xbe, 0x8b, 0x50, 0x43, 0x97, 0x42,
0x66, 0x28, 0x39, 0x6d, 0x31, 0x27, 0x59, 0x45, 0xda, 0xcf, 0x14, 0xa0, 0x12, 0x83, 0x60, 0xdb,
0xf3, 0xb5, 0x87, 0x8a, 0xab, 0xc8, 0xec, 0x0b, 0xc8, 0xb1, 0xa7, 0x60, 0xe2, 0x15, 0x54, 0xb5,
0x82, 0xc4, 0x9a, 0x85, 0x05, 0xa6, 0x2a, 0x55, 0xe7, 0xe6, 0xaf, 0xfd, 0xf0, 0xb2, 0xef, 0x7d,
0xfb, 0xc5, 0x1f, 0xc4, 0x3b, 0x3f, 0xd7, 0xcb, 0xd8, 0xdd, 0xf3, 0xff, 0x7e, 0x20, 0x2f, 0xdf,
0x50, 0xe2, 0xec, 0x3b, 0x13, 0x4d, 0xec, 0xbb, 0xbd, 0xff, 0xe2, 0xbe, 0x11, 0xe7, 0xae, 0xc2,
0xa0, 0x3e, 0xdf, 0xcb, 0x6b, 0xe8, 0xda, 0x8c, 0x5a, 0x76, 0x39, 0x14, 0xcf, 0x4e, 0x65, 0x3c,
0x19, 0x00, 0x8b, 0x12, 0x69, 0x09, 0xac, 0xc4, 0x22, 0x62, 0x81, 0xb6, 0xb6, 0x94, 0x98, 0x44,
0x6b, 0x62, 0x12, 0xa0, 0xda, 0x43, 0xa2, 0x05, 0x98, 0x7c, 0x16, 0x79, 0xfb, 0x31, 0x98, 0x3c,
0x80, 0xb2, 0x0e, 0xd5, 0x2a, 0x71, 0xb9, 0xa2, 0xbf, 0xf2, 0xe1, 0xff, 0x75, 0xda, 0x57, 0x5f,
0x63, 0x97, 0xd9, 0x79, 0xfd, 0x72, 0xc6, 0xee, 0x9a, 0xf8, 0xff, 0x03, 0xd9, 0x79, 0xdd, 0x10,
0x63, 0x3b, 0x92, 0xd0, 0xba, 0xff, 0x8e, 0xfe, 0x4b, 0xfa, 0x56, 0x39, 0xdf, 0x28, 0x94, 0xdc,
0x8d, 0xae, 0xef, 0x42, 0xdf, 0xc5, 0xa8, 0xe1, 0x2b, 0xc0, 0x1f, 0x6e, 0x0b, 0xd0, 0x71, 0xfa,
0x0a, 0x0b, 0xa9, 0xd0, 0x4b, 0x4e, 0x5e, 0x92, 0xcf, 0x15, 0x6d, 0xe1, 0x45, 0x2c, 0x8a, 0x14,
0x60, 0x13, 0x14, 0x02, 0xca, 0x81, 0x85, 0x03, 0x70, 0xe8, 0x11, 0xe4, 0xd0, 0x73, 0x28, 0xeb,
0xd0, 0x68, 0x88, 0x99, 0x9d, 0x77, 0x76, 0x8c, 0x7c, 0xa9, 0x72, 0x13, 0xc0, 0xce, 0x9b, 0x4f,
0x63, 0xec, 0x8e, 0x37, 0xff, 0x6d, 0x20, 0xaf, 0x7c, 0x69, 0x3d, 0x9b, 0x6e, 0x7d, 0x23, 0xd1,
0xc4, 0xf6, 0xd2, 0x7b, 0xfa, 0x47, 0xf5, 0x9f, 0x77, 0x2d, 0xf3, 0xd6, 0x3b, 0x9e, 0x03, 0xfd,
0xef, 0x47, 0x9d, 0x72, 0x25, 0x78, 0xfd, 0x20, 0x31, 0xda, 0x71, 0x00, 0x41, 0x4c, 0x94, 0x0a,
0xd3, 0x71, 0xe2, 0x1d, 0xc2, 0xa9, 0xa6, 0xbf, 0x88, 0x41, 0x3a, 0xb5, 0xd0, 0xfa, 0xbc, 0x03,
0x88, 0x4d, 0xd7, 0x50, 0x1a, 0x82, 0x39, 0xe4, 0xd0, 0xa3, 0xb0, 0xff, 0x31, 0xb0, 0x2e, 0x41,
0x40, 0x70, 0x7c, 0x46, 0x6f, 0x5f, 0xfd, 0xbf, 0x2b, 0xb7, 0xc8, 0x93, 0xb0, 0xff, 0xe0, 0xe7,
0x38, 0xfd, 0xea, 0xbb, 0x4f, 0x0e, 0x44, 0x9e, 0x06, 0x75, 0x3e, 0xec, 0xbf, 0x63, 0x68, 0x4d,
0xf7, 0x72, 0xfe, 0xae, 0x6f, 0xa5, 0x7f, 0x8e, 0x76, 0x25, 0xf1, 0x87, 0x53, 0xaf, 0x49, 0x40,
0xd8, 0x08, 0x9d, 0xcd, 0x30, 0x77, 0xe8, 0x6d, 0x4c, 0x14, 0xd2, 0x37, 0x3c, 0x88, 0x52, 0xd2,
0x21, 0x98, 0x39, 0x41, 0xf8, 0x26, 0xc0, 0x7f, 0x43, 0x78, 0x39, 0x11, 0x4c, 0xf2, 0x14, 0x80,
0xb8, 0x06, 0x6f, 0xfd, 0x0c, 0xde, 0x7c, 0x0a, 0xf0, 0x68, 0x04, 0xcc, 0x1e, 0x3e, 0xea, 0x5d,
0xbf, 0x61, 0xfb, 0xc2, 0x3d, 0x6f, 0x5c, 0xeb, 0xa9, 0xf5, 0x5f, 0x8f, 0x5a, 0x26, 0xd1, 0x8a,
0x8f, 0xbb, 0x6f, 0x2e, 0xa1, 0xce, 0x87, 0xdd, 0x37, 0xf6, 0xf4, 0xe6, 0x7a, 0xf8, 0x4a, 0xdf,
0x68, 0x36, 0x01, 0xd1, 0x75, 0x26, 0x6a, 0xf9, 0xc7, 0x50, 0x6e, 0x2f, 0xd8, 0x06, 0xda, 0x85,
0xf1, 0x5d, 0x3b, 0xf9, 0xfe, 0x1f, 0x7e, 0x95, 0x3f, 0xbe, 0xe6, 0xb3, 0x4c, 0xee, 0x7f, 0x13,
0x4c, 0x80, 0xb2, 0x01, 0x2a, 0x7d, 0x62, 0x1b, 0x88, 0x69, 0x20, 0x36, 0x00, 0x69, 0x80, 0x0d,
0xc0, 0x86, 0x1d, 0x23, 0x48, 0x86, 0x49, 0x9f, 0x36, 0x99, 0x23, 0x26, 0x40, 0x6c, 0x88, 0x98,
0x10, 0xe2, 0x46, 0x22, 0xd8, 0xc8, 0x36, 0x18, 0x5c, 0x05, 0x62, 0xf1, 0x33, 0xf4, 0x9f, 0xb2,
0x2c, 0xba, 0xe1, 0xa9, 0x4f, 0x97, 0xc6, 0xd6, 0x7f, 0x3d, 0x92, 0x97, 0x3e, 0x37, 0xc0, 0x12,
0x20, 0xaf, 0x6f, 0xbf, 0x90, 0x8d, 0x77, 0x4c, 0xf3, 0xd3, 0x4b, 0xbb, 0xbd, 0xc2, 0x90, 0x7f,
0x79, 0xef, 0x4a, 0xef, 0x6a, 0x27, 0xa3, 0x21, 0xb3, 0x1c, 0x55, 0xfa, 0x00, 0x64, 0x96, 0x23,
0xa6, 0x86, 0x92, 0x64, 0xd3, 0x87, 0xee, 0xf9, 0x1b, 0x0e, 0xbc, 0xf0, 0x0a, 0xc3, 0x83, 0x73,
0x44, 0xf3, 0x7b, 0xc0, 0xd4, 0x11, 0xdb, 0x48, 0x47, 0x80, 0x48, 0x08, 0xd2, 0x21, 0x6c, 0x4b,
0xe0, 0xce, 0xbf, 0xc3, 0xb6, 0xf0, 0x26, 0x15, 0xde, 0x86, 0xe9, 0x77, 0x8d, 0xf6, 0x50, 0x0a,
0xd6, 0x5c, 0x08, 0x19, 0x8d, 0x52, 0x90, 0xf5, 0x39, 0x63, 0xf5, 0x68, 0xfd, 0x36, 0x80, 0x2d,
0x77, 0xcf, 0x2c, 0x05, 0xb2, 0xe1, 0xa6, 0x27, 0x01, 0xd8, 0xf0, 0xab, 0xbd, 0xc3, 0x85, 0x41,
0xbd, 0x23, 0xdb, 0xe3, 0x23, 0x78, 0xd0, 0xbd, 0x11, 0xba, 0xb7, 0x82, 0xa9, 0x82, 0x6d, 0xa0,
0x1c, 0x61, 0xdf, 0x53, 0xcf, 0x72, 0xf4, 0x8d, 0xfd, 0xfc, 0xca, 0x15, 0x9a, 0x2b, 0x3e, 0xbd,
0x8e, 0xe5, 0xab, 0x4a, 0x40, 0x08, 0x92, 0x0e, 0xdb, 0x00, 0xd3, 0xe8, 0x10, 0xbe, 0x53, 0xc0,
0xf6, 0x48, 0x34, 0x76, 0xc2, 0x77, 0xa6, 0x91, 0x1e, 0x40, 0x73, 0xad, 0x44, 0xa3, 0x2a, 0x9b,
0x85, 0xe5, 0xa7, 0x03, 0x06, 0xc7, 0x81, 0x62, 0xb7, 0x5c, 0xb0, 0xf7, 0x0b, 0xdd, 0xbf, 0xdf,
0xcc, 0x75, 0x00, 0xfa, 0xf5, 0x3b, 0xce, 0x4f, 0xf2, 0xc6, 0xb5, 0x3d, 0x59, 0x1b, 0x36, 0x3e,
0xdd, 0x37, 0x9a, 0x2d, 0x89, 0x08, 0xe4, 0x4e, 0x41, 0xf5, 0x5d, 0x90, 0x2e, 0xdc, 0x40, 0xd9,
0x10, 0x1c, 0xc3, 0x6b, 0x8f, 0xbf, 0xc4, 0x59, 0x1b, 0xa6, 0xd9, 0xf4, 0xc1, 0x8b, 0x29, 0x9d,
0xf7, 0x07, 0x78, 0x3d, 0x2b, 0x52, 0x61, 0x52, 0x00, 0x9d, 0x26, 0x74, 0x52, 0xd3, 0x09, 0x96,
0x9e, 0xbe, 0x09, 0xda, 0xda, 0x6b, 0x3d, 0x1b, 0x09, 0x00, 0x09, 0x50, 0x12, 0x02, 0x21, 0xaa,
0x74, 0x2a, 0xe8, 0xc4, 0x25, 0x5c, 0x87, 0xfe, 0xc1, 0x7e, 0x73, 0xcd, 0x7d, 0x57, 0xad, 0x1c,
0x68, 0x26, 0x6c, 0x77, 0xc3, 0xcd, 0x4f, 0x03, 0xd0, 0xbf, 0xba, 0xbb, 0x94, 0xef, 0x33, 0x9f,
0xd7, 0x9e, 0x83, 0xe0, 0x43, 0x7e, 0x2d, 0xf8, 0xa7, 0xa0, 0x4c, 0x2d, 0x71, 0x44, 0x25, 0x44,
0x0b, 0x55, 0xa4, 0x72, 0x80, 0xb5, 0xdb, 0xce, 0x64, 0x60, 0xe3, 0xaf, 0x22, 0xda, 0x4f, 0x4f,
0x51, 0x3a, 0x9c, 0xd9, 0xb4, 0x9d, 0xb7, 0x95, 0x3f, 0x52, 0x87, 0xb6, 0x16, 0x6b, 0x63, 0xac,
0x89, 0x40, 0x2c, 0x5a, 0x83, 0xd6, 0xd2, 0xfe, 0x3f, 0x3a, 0x02, 0x45, 0xcb, 0xf1, 0xd3, 0x40,
0xe1, 0x79, 0xe0, 0x29, 0x08, 0xc0, 0xd1, 0xe0, 0xfb, 0x9c, 0x35, 0xb6, 0x6e, 0xe6, 0x93, 0xc0,
0x0e, 0x00, 0x07, 0x60, 0xe7, 0xb5, 0x3d, 0xae, 0x93, 0x91, 0x4f, 0x2d, 0xdb, 0x50, 0xb8, 0x14,
0xad, 0xc1, 0x2f, 0xa1, 0x4a, 0xef, 0x47, 0x39, 0x99, 0xc4, 0x61, 0x89, 0xd1, 0x8e, 0xe5, 0xf0,
0xee, 0x37, 0xc9, 0x98, 0x43, 0xac, 0x7e, 0xcf, 0x2f, 0x93, 0xe9, 0x1e, 0x02, 0x13, 0x82, 0x8d,
0x41, 0xa2, 0x64, 0x10, 0x81, 0x8d, 0x11, 0x1b, 0xa7, 0xd9, 0xbe, 0x63, 0xd8, 0x88, 0xe9, 0xa3,
0xd3, 0x3c, 0xf3, 0xc0, 0x8b, 0x3c, 0x75, 0xff, 0xf3, 0xbc, 0xf1, 0xcc, 0x1e, 0x2a, 0xb3, 0x0b,
0x14, 0xba, 0x1c, 0x72, 0x79, 0x85, 0x52, 0x06, 0x4d, 0x8c, 0x22, 0x42, 0x49, 0x9c, 0xac, 0x23,
0x21, 0xd8, 0x28, 0xd9, 0xa7, 0x32, 0x0e, 0x8b, 0x53, 0x60, 0x54, 0x33, 0x7d, 0xf9, 0x5a, 0x8b,
0xda, 0xdc, 0x7d, 0xf6, 0x7d, 0xf7, 0xbe, 0x7e, 0x2c, 0x74, 0x13, 0x6d, 0x14, 0x7c, 0xbf, 0xcb,
0xfe, 0x8e, 0xce, 0x38, 0x88, 0x38, 0x90, 0x29, 0x81, 0xbf, 0x0c, 0x69, 0x6a, 0x43, 0x2c, 0x28,
0x85, 0x69, 0xcc, 0xb3, 0x62, 0xec, 0x42, 0xba, 0x4b, 0x43, 0xd8, 0xb8, 0xb6, 0x24, 0xd9, 0xc9,
0x92, 0x70, 0x6a, 0x96, 0x84, 0x54, 0xad, 0x85, 0xb9, 0xa9, 0x05, 0xfe, 0xf5, 0xff, 0x3e, 0xcc,
0xe4, 0xbe, 0x37, 0x39, 0x73, 0x4b, 0x0f, 0x5d, 0x3d, 0x1e, 0x8d, 0xd9, 0x79, 0x9e, 0xbb, 0x7f,
0x1f, 0xe7, 0x7e, 0x64, 0x1b, 0x83, 0x23, 0x7d, 0x2c, 0xcc, 0x87, 0xcc, 0x97, 0x03, 0x72, 0xbe,
0xd0, 0xdf, 0x2d, 0x29, 0xa0, 0x06, 0x34, 0x8e, 0x23, 0x0b, 0x87, 0x50, 0x19, 0x07, 0x22, 0x01,
0x23, 0xb8, 0x2e, 0xf8, 0x19, 0xb5, 0x7e, 0xcb, 0xda, 0xbd, 0x97, 0x02, 0xf7, 0xba, 0xcf, 0x7d,
0x66, 0x98, 0xfa, 0x3c, 0xeb, 0xfa, 0x46, 0xdc, 0xd3, 0x11, 0x05, 0x4e, 0x1e, 0x95, 0x5b, 0x09,
0xa6, 0x9e, 0x2c, 0x92, 0x0a, 0x6a, 0x03, 0xcb, 0xea, 0x4d, 0xab, 0x00, 0xc1, 0x5a, 0x83, 0xc2,
0x24, 0x7e, 0x83, 0xc5, 0x88, 0x4e, 0xcc, 0x40, 0xe2, 0x0e, 0xda, 0x61, 0x5b, 0x79, 0x43, 0x8c,
0xc5, 0xcf, 0x84, 0xbc, 0xef, 0x23, 0x25, 0x06, 0x4a, 0x7d, 0xf8, 0xc5, 0x65, 0x90, 0x29, 0x24,
0x59, 0x4c, 0x37, 0xa8, 0x4e, 0x2f, 0xf2, 0xf0, 0xcf, 0x8e, 0xf1, 0xd0, 0xb3, 0x65, 0x76, 0xef,
0x5b, 0xe4, 0x03, 0x5b, 0x35, 0x9f, 0xba, 0x3c, 0x87, 0x23, 0xb5, 0x54, 0x0e, 0x9b, 0xd8, 0x8e,
0x23, 0xe0, 0x28, 0x50, 0x92, 0x90, 0x00, 0xcd, 0x48, 0x5f, 0x2f, 0x17, 0x00, 0xf7, 0xba, 0x5d,
0xa5, 0x50, 0x3b, 0x9e, 0xfe, 0xb5, 0x7c, 0xa9, 0x88, 0xa0, 0x40, 0xfb, 0xe0, 0x2f, 0x03, 0x53,
0x4b, 0xcd, 0x66, 0xa9, 0x50, 0x00, 0x3a, 0x98, 0x62, 0x71, 0x62, 0x9c, 0xc9, 0x63, 0x53, 0x64,
0x33, 0x2e, 0x2b, 0x46, 0x06, 0x90, 0xae, 0x21, 0xac, 0x93, 0x49, 0xe7, 0x37, 0x35, 0x12, 0x03,
0x31, 0xd8, 0x90, 0x7c, 0x3e, 0xa4, 0x70, 0xc6, 0xa9, 0x88, 0x69, 0x60, 0xa2, 0x2a, 0x54, 0x66,
0x70, 0x1c, 0xc3, 0xf4, 0x74, 0x9d, 0xef, 0xde, 0x37, 0xc5, 0x4f, 0x9e, 0xb1, 0x6c, 0x5c, 0x57,
0xe4, 0xca, 0x8b, 0x84, 0x4d, 0x2b, 0x0d, 0xd1, 0x62, 0x15, 0xa7, 0x4b, 0x81, 0xf2, 0x40, 0x27,
0x72, 0x88, 0x23, 0x28, 0x27, 0x2d, 0x71, 0x0c, 0xb8, 0x8e, 0xe0, 0x67, 0xec, 0xfa, 0x7f, 0xf8,
0xf5, 0x95, 0xfd, 0x6e, 0x71, 0x59, 0x84, 0x72, 0xf3, 0x97, 0xb4, 0xa8, 0xb5, 0xe3, 0x83, 0x53,
0x48, 0x9d, 0xd8, 0x74, 0x38, 0xad, 0xa0, 0x94, 0xa0, 0x17, 0x0f, 0xf2, 0xc4, 0x03, 0x0f, 0xf3,
0x8f, 0x3f, 0x3b, 0xc2, 0xa4, 0x9c, 0x42, 0x57, 0x06, 0xce, 0xec, 0x1e, 0xe7, 0xaa, 0xcb, 0x37,
0xd0, 0xbf, 0xe1, 0x5c, 0x6c, 0x26, 0x07, 0x12, 0x27, 0x66, 0x21, 0x21, 0x22, 0x21, 0x22, 0x8d,
0xc4, 0xf4, 0x62, 0x83, 0x12, 0x83, 0x02, 0x94, 0xeb, 0x51, 0xad, 0x5a, 0xbe, 0xf5, 0xf7, 0x65,
0x0e, 0xcd, 0xaf, 0xe1, 0x1b, 0xb7, 0x6d, 0x61, 0x53, 0xdf, 0x01, 0xe2, 0x50, 0x13, 0xeb, 0x6e,
0xa2, 0xb9, 0x37, 0x80, 0xe3, 0x49, 0x1e, 0x91, 0x94, 0xfa, 0x6b, 0x95, 0x24, 0x0c, 0xa5, 0x40,
0x04, 0xc7, 0x01, 0xd7, 0x91, 0x15, 0x6b, 0x86, 0x67, 0xce, 0x70, 0x73, 0xa7, 0x9e, 0xa7, 0x4d,
0xf9, 0xd5, 0x73, 0x40, 0x27, 0x84, 0xcd, 0xc9, 0x27, 0x9a, 0x30, 0x01, 0x82, 0x49, 0xf9, 0x8f,
0x05, 0xa5, 0xd1, 0xf5, 0xc3, 0xfc, 0xe3, 0xf7, 0x7f, 0xc8, 0x9f, 0x3c, 0xd6, 0x83, 0xb7, 0xf5,
0xcb, 0xac, 0x1e, 0x7b, 0x0f, 0x91, 0x11, 0x1e, 0xdc, 0xf3, 0x1c, 0x6f, 0xfd, 0xcd, 0xb7, 0xf8,
0xd2, 0x55, 0x4f, 0xd2, 0xb5, 0xe9, 0xa2, 0x94, 0xb6, 0x47, 0x69, 0x24, 0x22, 0x39, 0xd5, 0x44,
0x7c, 0x04, 0x41, 0xa1, 0x51, 0x1e, 0xfc, 0xdd, 0x3f, 0xcf, 0x12, 0x66, 0xcf, 0x66, 0xfb, 0x6d,
0x57, 0xd2, 0xb7, 0xf8, 0x02, 0x8b, 0x0b, 0x45, 0x0a, 0xcb, 0x47, 0xc8, 0xd6, 0xde, 0xc6, 0xb7,
0x71, 0x12, 0xb4, 0x44, 0xb5, 0xfe, 0x17, 0x9d, 0x9a, 0x97, 0x6e, 0x93, 0x2b, 0xa5, 0xd5, 0xf2,
0xde, 0x5e, 0xbd, 0xca, 0x9d, 0x7c, 0x65, 0x7c, 0xf8, 0x94, 0xf5, 0x3a, 0x9f, 0x14, 0x3d, 0x1a,
0xb4, 0x9f, 0x94, 0xa5, 0x36, 0x5c, 0xc2, 0x4a, 0x1d, 0x15, 0xf0, 0xec, 0xbf, 0x3e, 0xc3, 0x77,
0x9f, 0x1d, 0xe0, 0xcc, 0xdf, 0xbc, 0x9d, 0xf7, 0xff, 0xda, 0xc7, 0xc9, 0xf9, 0xc9, 0xb7, 0xb5,
0xf0, 0xc3, 0x3c, 0xfe, 0xc0, 0x39, 0x7c, 0xe3, 0xfe, 0x4f, 0xf2, 0xc5, 0x55, 0x47, 0xb1, 0xc5,
0x15, 0x2d, 0x66, 0xac, 0x50, 0x88, 0x48, 0x5a, 0x2d, 0x5a, 0x40, 0xa3, 0x5d, 0x87, 0x57, 0x5e,
0x9d, 0x67, 0x31, 0x1a, 0xe4, 0xb7, 0x7f, 0xf3, 0x7d, 0x0c, 0x66, 0xea, 0x94, 0xe7, 0x0f, 0x53,
0x28, 0xe6, 0x61, 0xef, 0x3f, 0x63, 0xe7, 0xf6, 0x42, 0xb7, 0x86, 0xbe, 0xde, 0xb4, 0x10, 0x63,
0xe9, 0xd0, 0x4b, 0x88, 0xef, 0x40, 0xc6, 0x63, 0xb9, 0x8e, 0xca, 0xf3, 0x6b, 0xfd, 0x6e, 0xb7,
0xb5, 0x2d, 0xa2, 0x96, 0x64, 0x60, 0x6c, 0x80, 0x22, 0x22, 0x9e, 0x3a, 0xc4, 0xf7, 0x1f, 0x9a,
0x61, 0xe5, 0xa5, 0x9f, 0xe3, 0xe3, 0x9f, 0xf8, 0x38, 0xa7, 0x75, 0xc1, 0x4a, 0x0f, 0x46, 0x5d,
0x58, 0xdb, 0x0d, 0x57, 0xfc, 0xc6, 0x65, 0x54, 0x2f, 0xde, 0xce, 0xae, 0xa7, 0x5f, 0x45, 0x3b,
0x5e, 0xa2, 0x5d, 0x9c, 0x04, 0x8a, 0xd2, 0x9c, 0x28, 0xcd, 0xc1, 0x63, 0x96, 0xcd, 0x1b, 0x86,
0x38, 0xed, 0xd4, 0x90, 0xf2, 0xde, 0x07, 0xf1, 0x33, 0x35, 0xd4, 0x5b, 0x8f, 0x63, 0x8f, 0xec,
0x85, 0x48, 0x43, 0xa1, 0xa7, 0x5d, 0x49, 0xb6, 0x34, 0xd2, 0x04, 0xd5, 0xe6, 0xba, 0x4a, 0xe1,
0x3a, 0x8e, 0xed, 0x75, 0x91, 0x60, 0xb9, 0x9b, 0xcd, 0x75, 0x14, 0x73, 0x61, 0x9b, 0x5a, 0xd0,
0x0c, 0x9f, 0xf0, 0xe8, 0xd3, 0xfb, 0x31, 0xcb, 0xdf, 0xcb, 0x07, 0x2e, 0xfb, 0x28, 0x6b, 0x7a,
0xa0, 0xa8, 0xc0, 0xd3, 0x90, 0x77, 0xe0, 0xde, 0x07, 0xc7, 0x79, 0xee, 0x65, 0x4d, 0x39, 0x7a,
0x2f, 0x7f, 0xff, 0x7a, 0x89, 0xcd, 0x1f, 0xaa, 0x83, 0xca, 0xa4, 0x94, 0x5c, 0x2d, 0x31, 0x0f,
0xc7, 0xd1, 0x1c, 0x3c, 0x5c, 0x61, 0x59, 0xaf, 0xe2, 0x8c, 0xd5, 0x75, 0xe2, 0xe3, 0xbb, 0x50,
0xf6, 0x18, 0xba, 0x72, 0x14, 0xe2, 0xe3, 0xe8, 0x5e, 0x17, 0xfa, 0xbb, 0xc1, 0xd7, 0x69, 0x80,
0x69, 0x96, 0xc8, 0x27, 0xf0, 0xf5, 0xe6, 0x53, 0x04, 0xa5, 0x9c, 0x6e, 0xd7, 0x71, 0x29, 0x2a,
0xad, 0x12, 0x1c, 0x22, 0x49, 0xb4, 0x6a, 0x51, 0x03, 0x0b, 0xca, 0x42, 0x5c, 0x63, 0xe7, 0xbe,
0x32, 0x83, 0xeb, 0x2f, 0x61, 0xeb, 0xfa, 0x15, 0x94, 0xdc, 0x64, 0x1f, 0x0d, 0xfc, 0xd5, 0xdf,
0x1e, 0xe0, 0xc1, 0xfd, 0xfd, 0xbc, 0xbd, 0xff, 0x11, 0xf2, 0xf9, 0x5e, 0xe6, 0xb8, 0x1a, 0x6a,
0x8f, 0x40, 0xd7, 0x8a, 0x14, 0xc0, 0xd2, 0xea, 0x47, 0x04, 0xb2, 0xae, 0x61, 0xb4, 0x77, 0x81,
0xa2, 0xaa, 0x53, 0x3e, 0x78, 0x98, 0x4c, 0x21, 0xc6, 0xf1, 0x23, 0x18, 0xea, 0x05, 0xd7, 0x87,
0xdc, 0x08, 0x2a, 0xbf, 0x0a, 0x2a, 0x7b, 0x90, 0xda, 0xc1, 0xd4, 0xe7, 0x4e, 0x5e, 0x49, 0x2b,
0x25, 0xe0, 0x78, 0x59, 0xad, 0xb2, 0x5e, 0xbe, 0xb3, 0x44, 0x45, 0xea, 0x28, 0x5b, 0x69, 0x73,
0x2c, 0x13, 0x40, 0x65, 0x96, 0xd8, 0x1f, 0xa6, 0x67, 0xf9, 0x5a, 0xfa, 0x7c, 0xc8, 0xa4, 0x7e,
0x77, 0x64, 0x7c, 0x91, 0xe9, 0x28, 0xc7, 0x1f, 0x7d, 0xb6, 0x97, 0xb3, 0x7a, 0x9e, 0xe0, 0xa1,
0x3f, 0xbb, 0x9c, 0x89, 0x60, 0x82, 0xf2, 0x54, 0x39, 0xd5, 0xbe, 0x24, 0x92, 0x77, 0x6c, 0x6c,
0xad, 0xa5, 0x34, 0x90, 0xa7, 0xb4, 0x62, 0x05, 0xe2, 0x17, 0xc9, 0x14, 0x5d, 0x9c, 0x5c, 0x16,
0xb2, 0x03, 0x90, 0x2d, 0xa2, 0xfc, 0x6e, 0xb4, 0x6b, 0x51, 0x32, 0x0f, 0x85, 0xd1, 0xa5, 0x55,
0xa8, 0x9c, 0xa4, 0xbe, 0x15, 0x50, 0x26, 0xa8, 0x6b, 0xa9, 0xd5, 0x17, 0x97, 0xcc, 0x30, 0x21,
0x04, 0x53, 0x60, 0x42, 0xc4, 0x34, 0x40, 0x42, 0x2a, 0x73, 0x65, 0xdc, 0xc2, 0x20, 0x7d, 0xa5,
0xa1, 0x56, 0xf4, 0x03, 0x78, 0xf8, 0xf1, 0x69, 0x3e, 0xf8, 0x4b, 0x03, 0x0c, 0x74, 0xc1, 0x15,
0x1f, 0xfb, 0x28, 0x71, 0x58, 0xe5, 0xe0, 0xce, 0x7f, 0x61, 0x7e, 0xa1, 0xd1, 0x2e, 0x6b, 0x91,
0x8e, 0x67, 0xb2, 0x4f, 0xc2, 0xb1, 0x34, 0xa2, 0x32, 0x64, 0x8a, 0x79, 0x9c, 0x4c, 0x06, 0x14,
0x58, 0xa3, 0x98, 0xde, 0x3b, 0xc3, 0x9b, 0x0f, 0xed, 0xe6, 0xc8, 0xa3, 0x4f, 0x20, 0x33, 0x2f,
0xbe, 0xb3, 0x1a, 0x97, 0x25, 0x4b, 0x21, 0x4a, 0x63, 0x85, 0xba, 0x6b, 0x6c, 0xa6, 0x62, 0x8d,
0x45, 0xb9, 0xa9, 0xfa, 0x24, 0x46, 0xa2, 0x69, 0x5a, 0x31, 0x4e, 0x2c, 0x36, 0xac, 0xe0, 0xe7,
0x4e, 0xc5, 0xc9, 0x16, 0x08, 0x0c, 0xe4, 0x74, 0xe2, 0x77, 0x95, 0xc8, 0x72, 0x60, 0x41, 0x71,
0x26, 0x70, 0xdf, 0x7d, 0xf7, 0x21, 0x22, 0xe8, 0x8c, 0x8f, 0xb4, 0xba, 0x26, 0x69, 0xb5, 0x27,
0x36, 0xd5, 0x4c, 0x93, 0x40, 0x4a, 0x12, 0xc9, 0x9a, 0x12, 0x29, 0x01, 0x2b, 0x68, 0xad, 0x28,
0x0e, 0x67, 0x71, 0x7d, 0x8b, 0x76, 0x84, 0xc6, 0xdc, 0x3c, 0xd9, 0x1e, 0x67, 0x29, 0x02, 0x51,
0x4b, 0xb4, 0x2c, 0x02, 0x46, 0x54, 0x59, 0xa3, 0x33, 0x6f, 0x47, 0x35, 0xb3, 0x74, 0xb2, 0x69,
0x40, 0x78, 0x14, 0xe2, 0x29, 0xc4, 0x2e, 0xd0, 0x95, 0x37, 0xe4, 0x3c, 0x4b, 0xb9, 0x11, 0x33,
0x1b, 0x42, 0x35, 0x9d, 0x3e, 0x54, 0xd0, 0x3c, 0xb0, 0xc7, 0x63, 0xeb, 0x65, 0xff, 0x8d, 0x3f,
0xf9, 0xe6, 0x9f, 0xa2, 0xbd, 0x2c, 0x6b, 0xce, 0xb9, 0x84, 0xbe, 0x81, 0x7c, 0x42, 0x1c, 0xe9,
0xa8, 0xd3, 0x5b, 0xd9, 0xbe, 0x03, 0x80, 0x2c, 0x7d, 0x2a, 0x47, 0x98, 0x3f, 0x52, 0xa5, 0x7b,
0xc8, 0xa7, 0xd0, 0xe7, 0xe2, 0x75, 0x79, 0x29, 0xb3, 0x4e, 0x0f, 0xd9, 0xb4, 0xe2, 0x4f, 0xe7,
0xcf, 0x7c, 0x1c, 0xe9, 0x29, 0x37, 0x53, 0x1a, 0xde, 0x17, 0x2e, 0x8e, 0xe3, 0x17, 0x7d, 0xa4,
0x89, 0x56, 0x35, 0x37, 0x88, 0x11, 0xd1, 0x38, 0x85, 0x2c, 0x03, 0xde, 0x14, 0xe5, 0xfa, 0x34,
0x13, 0x01, 0xc4, 0x31, 0x04, 0x59, 0x18, 0xbb, 0x60, 0x88, 0x1f, 0x7f, 0x6b, 0x9c, 0x75, 0x1f,
0xb9, 0x0b, 0xaf, 0x6f, 0x03, 0xc5, 0x91, 0xb3, 0xd8, 0x96, 0x7f, 0x91, 0xe2, 0xf0, 0x00, 0x56,
0xc2, 0xa5, 0xf5, 0x7a, 0x53, 0x1b, 0x9d, 0x0d, 0x0a, 0xda, 0xc0, 0x94, 0x08, 0xb5, 0xb9, 0x00,
0xbf, 0xe0, 0x24, 0xa6, 0xeb, 0x24, 0xb4, 0x6a, 0x09, 0xd8, 0x4e, 0x2b, 0x6d, 0x6b, 0x64, 0xaa,
0x5a, 0xb3, 0xe3, 0xfa, 0x8c, 0xb1, 0x17, 0xa6, 0xc3, 0x9a, 0x4c, 0xb4, 0x66, 0x34, 0x4f, 0x2d,
0x1d, 0x36, 0x88, 0x88, 0xa2, 0x2c, 0xeb, 0xbb, 0x67, 0x58, 0x19, 0xbf, 0xc4, 0xc2, 0xf4, 0x24,
0x93, 0xb3, 0xd3, 0xec, 0x9b, 0x8d, 0xa8, 0x14, 0x0b, 0x6c, 0xdd, 0xa6, 0xc9, 0x1e, 0xb1, 0x6c,
0x39, 0xf7, 0x26, 0xfa, 0x2a, 0xa3, 0x7c, 0xb8, 0xf7, 0x27, 0x88, 0xe3, 0x22, 0x4d, 0x9e, 0xd5,
0xe4, 0x5e, 0x36, 0x46, 0x59, 0x83, 0xb2, 0x29, 0x53, 0xee, 0x04, 0x63, 0x0d, 0x41, 0x25, 0xa0,
0x3a, 0x55, 0xa7, 0x6b, 0x28, 0x93, 0x36, 0x33, 0x3a, 0xb5, 0x65, 0x9b, 0x36, 0x94, 0x6a, 0x44,
0x5a, 0x66, 0x25, 0x22, 0xc7, 0x8e, 0x1f, 0x57, 0x6f, 0x39, 0x9f, 0x1c, 0x2b, 0x69, 0x6b, 0x38,
0xb7, 0x7b, 0x38, 0x73, 0x16, 0xa2, 0xdb, 0x6d, 0x4d, 0xad, 0x31, 0xa1, 0xa1, 0x3e, 0x5d, 0x27,
0x8a, 0x72, 0x0c, 0xac, 0x58, 0xc3, 0x5a, 0xbd, 0x97, 0xc1, 0xa3, 0x0f, 0xe0, 0x4c, 0xbe, 0x40,
0x50, 0x99, 0x60, 0xb6, 0x6a, 0xe9, 0x1a, 0x1d, 0x24, 0xbf, 0x26, 0x4b, 0xed, 0xd8, 0xd3, 0x9c,
0x2b, 0xb7, 0xf3, 0x89, 0xff, 0xec, 0x63, 0x95, 0xea, 0x28, 0xb2, 0x4c, 0xda, 0x59, 0x31, 0xed,
0x96, 0x50, 0xab, 0x49, 0x17, 0x23, 0x51, 0x9d, 0x60, 0xbe, 0x4e, 0x65, 0xaa, 0x46, 0xff, 0x68,
0x1e, 0xc7, 0x11, 0xc4, 0x9a, 0x25, 0xcd, 0x3c, 0xac, 0x05, 0x2b, 0xa8, 0x40, 0x20, 0x48, 0xca,
0x1e, 0x48, 0x2c, 0xa3, 0x11, 0xe8, 0xc7, 0x36, 0xdc, 0x59, 0xfe, 0xae, 0x5b, 0x9e, 0x10, 0xf1,
0xbb, 0xd5, 0x0f, 0xa3, 0x5a, 0x7c, 0xa5, 0x9b, 0xd5, 0x09, 0x95, 0x68, 0xd6, 0x12, 0x56, 0xf0,
0xf3, 0x21, 0xbe, 0x3f, 0x89, 0xcc, 0x1e, 0x46, 0x2a, 0x01, 0x03, 0x51, 0xcc, 0xa0, 0xa7, 0x31,
0x95, 0x7b, 0x98, 0x9e, 0x18, 0xe1, 0x70, 0xe9, 0x6a, 0x82, 0xc6, 0x0a, 0x4e, 0x73, 0x7f, 0xc4,
0x2f, 0xff, 0xa7, 0x59, 0xac, 0xdb, 0x9f, 0x16, 0x53, 0xd2, 0xd1, 0x98, 0x6b, 0x6a, 0xa1, 0xdd,
0xd7, 0x52, 0xa6, 0x46, 0xb4, 0x38, 0x4f, 0xa3, 0x96, 0x25, 0x0a, 0x72, 0xf4, 0xae, 0xf0, 0x71,
0xdc, 0x08, 0x31, 0x1d, 0x16, 0xd1, 0xaa, 0x6f, 0x04, 0x8c, 0x4d, 0x8a, 0x2a, 0x63, 0x9b, 0x14,
0x1e, 0x63, 0x55, 0x50, 0x6b, 0xb0, 0x1b, 0x94, 0xb8, 0x47, 0x5e, 0x1d, 0x90, 0xd3, 0x2e, 0xaa,
0x3e, 0x54, 0x9d, 0x0a, 0x83, 0xde, 0x51, 0xd7, 0x4f, 0x9c, 0x53, 0x81, 0xb5, 0x38, 0x9e, 0xc5,
0x09, 0xe7, 0xb1, 0x13, 0x0b, 0xb0, 0x00, 0x36, 0x48, 0x42, 0xa1, 0xf8, 0x02, 0x7d, 0x9a, 0xc1,
0xae, 0xc3, 0x2c, 0x2b, 0x3d, 0xc7, 0xba, 0x89, 0x47, 0x29, 0x8c, 0x81, 0xf5, 0x73, 0x48, 0x1c,
0xa0, 0xb4, 0x4a, 0xc9, 0x66, 0x02, 0x46, 0x68, 0x97, 0xb3, 0xca, 0x54, 0x30, 0x95, 0x59, 0x1a,
0x0b, 0x31, 0xb1, 0x1e, 0x41, 0xe7, 0x87, 0x28, 0x16, 0xe7, 0x70, 0x64, 0x3e, 0x05, 0x61, 0xdb,
0x1e, 0x9d, 0x96, 0xc7, 0x88, 0x45, 0xc5, 0xa9, 0x26, 0x4c, 0x3b, 0xb1, 0x5a, 0x2b, 0xfb, 0x67,
0x66, 0xbd, 0x47, 0x01, 0xdc, 0x8f, 0xfc, 0x78, 0x2f, 0x07, 0x3f, 0x50, 0x9c, 0xae, 0x4e, 0x67,
0x7e, 0xd0, 0xb3, 0xc2, 0x5c, 0x93, 0x78, 0x5a, 0x47, 0x93, 0xd9, 0x2b, 0x40, 0xc1, 0x49, 0xa8,
0x79, 0x2c, 0x28, 0xcf, 0x85, 0x42, 0x06, 0x0a, 0x3e, 0xd2, 0xb5, 0x06, 0x72, 0xc3, 0x28, 0x7f,
0x9a, 0x6a, 0xbd, 0x8c, 0xaa, 0x96, 0xc9, 0x14, 0x32, 0x78, 0x05, 0xbf, 0x1d, 0x5a, 0x34, 0x28,
0x53, 0x87, 0x70, 0x81, 0xb8, 0x3c, 0x4f, 0x6d, 0xc1, 0x26, 0xaf, 0x20, 0x8a, 0xa3, 0x64, 0xf3,
0x19, 0xdc, 0xe8, 0x28, 0x04, 0x8b, 0xe0, 0x06, 0xed, 0x28, 0xd7, 0xa1, 0xcd, 0x96, 0x6f, 0x44,
0x0a, 0x62, 0x69, 0x2d, 0x1b, 0xc7, 0xd0, 0x68, 0xa8, 0xdd, 0x63, 0x77, 0xcf, 0x3d, 0x05, 0x0a,
0x17, 0xe0, 0xc0, 0x53, 0x9e, 0x19, 0xdd, 0xa6, 0xbe, 0x59, 0x9d, 0x0e, 0xaf, 0x29, 0x0c, 0xa6,
0xdc, 0x48, 0x00, 0xe5, 0x42, 0xa6, 0x0b, 0xbc, 0x2e, 0x28, 0x0a, 0x0a, 0x05, 0xda, 0x05, 0x2f,
0x03, 0x8e, 0x87, 0xf2, 0x8b, 0x94, 0x0f, 0xee, 0xa7, 0x36, 0x35, 0x89, 0x58, 0x8b, 0x97, 0xf7,
0x71, 0x32, 0xe0, 0xc6, 0x0a, 0x31, 0x01, 0x71, 0xb5, 0x4a, 0xb0, 0xb0, 0x88, 0x09, 0x2c, 0xb8,
0x3d, 0x38, 0xb9, 0x33, 0xf0, 0x96, 0xf5, 0xa3, 0x5c, 0x0f, 0x4f, 0x37, 0x50, 0x8d, 0x23, 0x48,
0x5c, 0x41, 0x7b, 0x89, 0xe1, 0x4b, 0xb3, 0x9f, 0x2c, 0x69, 0xe3, 0xa1, 0xa9, 0x8d, 0x28, 0xe9,
0x38, 0x11, 0xb7, 0xc3, 0x95, 0xb1, 0xea, 0xf8, 0xf4, 0x9c, 0x73, 0x3f, 0x28, 0x9e, 0xff, 0x5d,
0x70, 0xdf, 0xf8, 0x0c, 0xac, 0xff, 0xe6, 0x8c, 0xec, 0x1d, 0x5b, 0xb6, 0xbb, 0x7c, 0x34, 0xbe,
0xaf, 0x50, 0x72, 0x3f, 0x96, 0xe8, 0x2e, 0x0d, 0x73, 0xda, 0x49, 0x98, 0xac, 0xe7, 0x26, 0x86,
0xa9, 0x9c, 0x94, 0x6b, 0x18, 0xd4, 0xe2, 0xeb, 0xd4, 0x26, 0x6b, 0xf4, 0xac, 0x1c, 0x48, 0x6a,
0x0d, 0x2b, 0x44, 0x95, 0x06, 0xc1, 0x6c, 0x05, 0xc1, 0x26, 0x85, 0x4f, 0xbe, 0x17, 0xaf, 0xcb,
0x07, 0xeb, 0xa2, 0x1c, 0xc1, 0x55, 0x0b, 0x10, 0xd4, 0x92, 0x5e, 0x99, 0x13, 0xa1, 0x33, 0x51,
0x1a, 0xe6, 0x53, 0x1f, 0xb2, 0xcd, 0xca, 0x32, 0x15, 0x20, 0x16, 0x08, 0x15, 0x84, 0xd2, 0x2a,
0x6f, 0x8c, 0x81, 0x6a, 0x4d, 0x5e, 0xdc, 0x7e, 0xcf, 0x39, 0x7f, 0x0b, 0x0f, 0x53, 0x7a, 0xdf,
0xef, 0xa1, 0xe3, 0xd2, 0x46, 0x00, 0xfe, 0xfa, 0x8b, 0x23, 0x55, 0x13, 0x39, 0x77, 0x94, 0xc7,
0x43, 0x51, 0xca, 0x24, 0x91, 0x43, 0x4c, 0x5a, 0x8b, 0x27, 0xe1, 0x33, 0x29, 0xb8, 0xa2, 0xf4,
0xf7, 0x08, 0xab, 0x5c, 0x7a, 0x57, 0x14, 0xc9, 0xe4, 0x34, 0x99, 0xbc, 0xc6, 0x2f, 0x38, 0xe4,
0x7a, 0x5d, 0xf2, 0x25, 0x9f, 0xc2, 0x60, 0x8e, 0x7c, 0x29, 0x87, 0x5f, 0xf0, 0xf0, 0x5c, 0xc1,
0xf3, 0x02, 0x5c, 0x35, 0x8f, 0x8a, 0x27, 0x51, 0x7a, 0x1e, 0x9d, 0x09, 0x50, 0x6e, 0xd8, 0x06,
0x61, 0x6d, 0x1b, 0x44, 0xd3, 0x37, 0x8c, 0x41, 0x85, 0xef, 0xd4, 0x46, 0x1c, 0xcb, 0xc4, 0xe4,
0x94, 0xfb, 0xad, 0xef, 0x1d, 0x7f, 0x38, 0xde, 0xf7, 0xfb, 0xb0, 0xea, 0xb7, 0xbe, 0x83, 0xde,
0x78, 0xcb, 0x6e, 0x0e, 0xff, 0x0f, 0xf8, 0x32, 0xcf, 0x33, 0x7b, 0x48, 0x76, 0x57, 0xa7, 0xed,
0x2d, 0x61, 0x25, 0x4a, 0x5e, 0x0b, 0x48, 0xda, 0x50, 0xb0, 0x71, 0xaa, 0x6a, 0xb3, 0xa4, 0xbd,
0x03, 0xe0, 0xe5, 0x55, 0x0b, 0x18, 0x12, 0xe1, 0xb8, 0x09, 0x81, 0x75, 0x3d, 0xd0, 0xda, 0xa2,
0x74, 0x84, 0xce, 0x04, 0xe9, 0x08, 0x51, 0x5e, 0x84, 0x72, 0x62, 0x50, 0x69, 0xeb, 0xa8, 0xf3,
0xb0, 0x3a, 0x41, 0xd8, 0x14, 0x44, 0xa0, 0x20, 0xb0, 0x2d, 0xdf, 0x30, 0x86, 0x78, 0x66, 0xce,
0xfd, 0xf1, 0xa6, 0x1d, 0xe5, 0x1f, 0x01, 0x34, 0x4a, 0x1b, 0xda, 0x2d, 0xd3, 0x85, 0xb5, 0xbf,
0x04, 0xc0, 0xd6, 0x3f, 0x3e, 0x5e, 0xaf, 0xcd, 0x98, 0x3f, 0x9f, 0x3f, 0x12, 0x3f, 0x91, 0x24,
0xb3, 0xb8, 0x0d, 0xa6, 0xd9, 0xbb, 0x6a, 0x6a, 0x47, 0xe2, 0x0e, 0x60, 0x51, 0x5b, 0x63, 0x36,
0x4c, 0xb5, 0x16, 0xb6, 0xe7, 0x49, 0x94, 0x24, 0x47, 0x96, 0x1e, 0x8c, 0xb4, 0xd6, 0x32, 0x4b,
0x5a, 0x4b, 0x88, 0x4d, 0x4c, 0xa9, 0xa1, 0x20, 0x68, 0x9b, 0x94, 0xb5, 0x50, 0x5e, 0xe4, 0xb5,
0xd7, 0x0f, 0x9e, 0x72, 0x2d, 0xc0, 0xae, 0xdf, 0x83, 0x4d, 0xb7, 0xbe, 0xde, 0x06, 0xb2, 0xf1,
0xc6, 0x47, 0xd9, 0x7d, 0x73, 0xd2, 0x43, 0x3d, 0xe3, 0x96, 0xb9, 0xb7, 0x83, 0xb2, 0xbd, 0x6e,
0xfe, 0xed, 0x70, 0x4e, 0xa9, 0x64, 0x23, 0x31, 0xa6, 0xad, 0x11, 0x1b, 0x2d, 0x05, 0x61, 0x3b,
0xcc, 0xae, 0x25, 0x64, 0xe7, 0xf7, 0x71, 0x87, 0x69, 0x46, 0x2d, 0x8d, 0x4a, 0x6b, 0x4e, 0xc7,
0xb0, 0x36, 0x99, 0x17, 0x5a, 0x54, 0xa0, 0xa0, 0x21, 0x09, 0xa0, 0x34, 0xad, 0xd4, 0xeb, 0x32,
0xf9, 0xd6, 0x78, 0xee, 0x77, 0x2e, 0xfd, 0xb3, 0x3d, 0x0b, 0x00, 0xa5, 0x8f, 0xde, 0xc6, 0x3b,
0x5e, 0x2b, 0x6c, 0xbc, 0x63, 0x9a, 0x97, 0x6f, 0x5e, 0x05, 0xc0, 0xaa, 0x6b, 0x7f, 0xfd, 0x99,
0xea, 0xb4, 0x7c, 0xaa, 0x32, 0x11, 0xc6, 0x09, 0x1d, 0x6f, 0x6e, 0xfc, 0xef, 0x18, 0x9d, 0xfe,
0xf4, 0x8e, 0xef, 0x92, 0x43, 0x69, 0x1f, 0x4c, 0xdc, 0x36, 0xa9, 0xe6, 0x41, 0x45, 0x92, 0x80,
0xa8, 0xb7, 0x41, 0x00, 0x04, 0x81, 0xcc, 0x1f, 0x3a, 0x9a, 0xfb, 0x83, 0xf3, 0xbe, 0x31, 0xf3,
0xfc, 0xee, 0x1b, 0xfa, 0x00, 0x38, 0xf5, 0xa3, 0x5f, 0x6c, 0x01, 0x71, 0x3a, 0x69, 0xe4, 0x9f,
0x3e, 0x3e, 0xcf, 0xce, 0xeb, 0x96, 0xf1, 0x9d, 0x27, 0x1f, 0x61, 0xe0, 0xa7, 0xa5, 0xbd, 0x1b,
0x2e, 0x0e, 0xa7, 0x9d, 0x8c, 0xf9, 0x90, 0x97, 0x4d, 0xe7, 0x75, 0x30, 0x57, 0xd5, 0x34, 0x01,
0x75, 0x32, 0x32, 0xd8, 0xd9, 0x69, 0x34, 0xed, 0x17, 0x3e, 0x9d, 0x1d, 0x48, 0x89, 0x97, 0x6a,
0x42, 0x6c, 0x02, 0xa2, 0xde, 0x01, 0x22, 0x4d, 0x23, 0x41, 0x28, 0x73, 0x87, 0x8e, 0xe4, 0x6e,
0xd8, 0xb4, 0x63, 0xf6, 0xaf, 0xf6, 0xfc, 0x61, 0x2f, 0x67, 0x6e, 0x7f, 0xe7, 0x0b, 0x51, 0xe7,
0xc4, 0x0f, 0xbe, 0xf3, 0x64, 0x95, 0x97, 0x6f, 0x2c, 0x71, 0xe5, 0x13, 0x13, 0x36, 0xff, 0x4f,
0x63, 0x2f, 0x6d, 0xbc, 0x60, 0x7a, 0xde, 0xf5, 0xcc, 0x45, 0x9e, 0x8f, 0x9f, 0x74, 0xc3, 0xe5,
0x24, 0x54, 0xdc, 0x2e, 0xb5, 0xef, 0xce, 0x46, 0xf4, 0x12, 0xa6, 0x7b, 0x42, 0xa3, 0xbb, 0x09,
0xc0, 0x58, 0x08, 0x40, 0x35, 0x7d, 0x22, 0x90, 0x16, 0xc5, 0x6a, 0x34, 0xd4, 0xd1, 0x83, 0xe3,
0xd9, 0xff, 0xb9, 0xf1, 0xae, 0xd9, 0xbf, 0xd8, 0xf7, 0x85, 0x5e, 0xb5, 0xee, 0xf6, 0xf9, 0x77,
0xf7, 0x7a, 0x7a, 0xf7, 0x17, 0x96, 0xb3, 0xf1, 0xab, 0xc9, 0xdb, 0xd3, 0xb7, 0xee, 0xec, 0xfd,
0xef, 0x7d, 0x23, 0xdc, 0x92, 0xeb, 0x57, 0x2b, 0xb5, 0xab, 0xd3, 0x74, 0xad, 0xda, 0x04, 0xf3,
0xc4, 0x06, 0x41, 0x93, 0x72, 0x73, 0x32, 0xc0, 0xd2, 0xe4, 0x17, 0x69, 0x88, 0x15, 0x54, 0x90,
0x46, 0xa7, 0x50, 0x92, 0xde, 0xae, 0x4d, 0x32, 0x77, 0xb5, 0xaa, 0x5e, 0x3c, 0x38, 0x9e, 0xfd,
0xec, 0x39, 0xff, 0x67, 0xe6, 0xf1, 0xbd, 0x5f, 0xe8, 0x65, 0xdd, 0x57, 0xe7, 0x7f, 0xce, 0x0b,
0x03, 0xd7, 0x0f, 0xb0, 0xf9, 0xae, 0xe4, 0xad, 0xd0, 0x6b, 0x5f, 0xec, 0x79, 0xff, 0xe0, 0x69,
0x72, 0x73, 0xbe, 0x5f, 0x5d, 0xe2, 0xe5, 0x94, 0xa7, 0x1d, 0xdd, 0x6e, 0x21, 0x35, 0x8b, 0xe7,
0x13, 0x8b, 0x69, 0x78, 0x27, 0x1d, 0xb7, 0x92, 0x0e, 0x20, 0x14, 0x54, 0xa8, 0x92, 0x3c, 0x11,
0x25, 0x77, 0x55, 0x4c, 0x0c, 0x51, 0xa4, 0xa6, 0xe6, 0xcb, 0x3c, 0xf0, 0xda, 0x81, 0xbe, 0x9b,
0x3e, 0x74, 0xcf, 0x91, 0x89, 0xd7, 0x6f, 0xea, 0x63, 0xc3, 0xf6, 0xb9, 0xff, 0xe0, 0x15, 0x8e,
0xeb, 0x86, 0xd9, 0x9c, 0x5e, 0xa4, 0x79, 0xe4, 0xaa, 0xfe, 0xe1, 0xb5, 0x17, 0xc6, 0xbf, 0xdb,
0x55, 0x52, 0x57, 0x78, 0x79, 0x39, 0x3b, 0x93, 0x07, 0xa5, 0x75, 0xfb, 0xf0, 0x4f, 0xd6, 0xe6,
0x68, 0x6a, 0x47, 0x52, 0x00, 0x46, 0x52, 0x02, 0x98, 0x68, 0x40, 0x45, 0x80, 0x11, 0x6c, 0x24,
0x04, 0x91, 0x0e, 0xc3, 0x90, 0xc7, 0xa6, 0x67, 0xf5, 0xf7, 0xd6, 0xdd, 0xbe, 0xf8, 0x97, 0xc9,
0xfe, 0x83, 0x6c, 0xde, 0x31, 0xf5, 0x8b, 0xb9, 0x54, 0xf3, 0xc6, 0x9d, 0xef, 0x43, 0x55, 0x1e,
0xe5, 0x8c, 0x5b, 0x13, 0x69, 0x77, 0xdf, 0xd4, 0x77, 0xce, 0xc0, 0xca, 0xf8, 0x57, 0xb2, 0xdd,
0xea, 0x43, 0x8e, 0x6b, 0x2f, 0xf4, 0x0b, 0xe0, 0x64, 0xd4, 0xd2, 0x66, 0x87, 0x95, 0x56, 0xa1,
0x89, 0x11, 0xc4, 0x2a, 0x54, 0x2c, 0x10, 0x2b, 0x94, 0x91, 0x94, 0xc9, 0x0a, 0x51, 0x43, 0x08,
0x23, 0xbd, 0x18, 0xc7, 0x3c, 0x5a, 0xa9, 0xe9, 0x7f, 0x3a, 0x74, 0x34, 0x7f, 0xef, 0x7b, 0xbf,
0x33, 0x79, 0xec, 0xdd, 0x5e, 0xbd, 0x7a, 0x57, 0xd7, 0x9c, 0x76, 0x5d, 0xb7, 0x9c, 0xcd, 0x3b,
0xda, 0xb7, 0x0e, 0x5e, 0xbe, 0xbe, 0xef, 0xac, 0x81, 0xd1, 0x68, 0x8b, 0x9b, 0xd1, 0xe7, 0xbb,
0xae, 0xdd, 0xe6, 0x38, 0x6c, 0xd0, 0xda, 0x16, 0xbd, 0x0c, 0xb8, 0xae, 0x4a, 0x62, 0xbb, 0x55,
0xad, 0xca, 0x4e, 0x62, 0x88, 0x03, 0x21, 0x0a, 0x04, 0x13, 0xeb, 0xb2, 0x31, 0x6a, 0xa7, 0xb1,
0x3c, 0xd5, 0x08, 0xd4, 0xb3, 0xe3, 0x13, 0x99, 0x67, 0x2e, 0xf8, 0xf6, 0xcc, 0xf8, 0xc9, 0xee,
0xc1, 0xfc, 0xc2, 0x81, 0xb4, 0x6e, 0x47, 0x5c, 0x3b, 0xc4, 0xd8, 0xd7, 0x8f, 0xb7, 0xfe, 0xfe,
0xe1, 0x65, 0x23, 0xc5, 0xd3, 0xb7, 0x2c, 0x9c, 0x5a, 0xec, 0xb7, 0x43, 0x4e, 0xd6, 0x5d, 0xae,
0x2c, 0x23, 0x62, 0xed, 0x90, 0x42, 0x7a, 0x94, 0x98, 0x0c, 0xa2, 0xb5, 0x18, 0x09, 0xb0, 0x7a,
0x11, 0xd4, 0x04, 0xc2, 0xdb, 0x51, 0x64, 0x8e, 0xcd, 0x96, 0x9d, 0x89, 0xe7, 0xf7, 0xac, 0x3c,
0xf4, 0xdb, 0xf7, 0xbf, 0x12, 0xb4, 0xd6, 0xfe, 0x7c, 0x3f, 0x63, 0x7f, 0x34, 0xfb, 0xae, 0x65,
0xfa, 0x7f, 0x4c, 0xe8, 0x21, 0x04, 0x29, 0xb0, 0x36, 0x16, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45,
0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
};
const lv_img_dsc_t img_wink_png = {
.header.always_zero = 0,
.header.w = 50,
.header.h = 50,
.data_size = 5158,
.header.cf = LV_IMG_CF_RAW_ALPHA,
.data = img_wink_png_map,
};
#endif /*LV_USE_PNG && LV_BUILD_EXAMPLES*/

View File

@@ -0,0 +1,6 @@
Open a PNG image from file and variable
"""""""""""""""""""""""""""""""""""""""""""""""
.. lv_example:: libs/bmp/lv_example_png_1
:language: c

View File

@@ -0,0 +1,38 @@
/**
* @file lv_example_png.h
*
*/
#ifndef LV_EXAMPLE_PNG_H
#define LV_EXAMPLE_PNG_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void lv_example_png_1(void);
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_EXAMPLE_PNG_H*/

View File

@@ -0,0 +1,23 @@
#include "../../lv_examples.h"
#if LV_USE_PNG && LV_BUILD_EXAMPLES
/**
* Open a PNG image from a file and a variable
*/
void lv_example_png_1(void)
{
LV_IMG_DECLARE(img_wink_png);
lv_obj_t * img;
img = lv_img_create(lv_scr_act());
lv_img_set_src(img, &img_wink_png);
lv_obj_align(img, LV_ALIGN_LEFT_MID, 20, 0);
img = lv_img_create(lv_scr_act());
/* Assuming a File system is attached to letter 'A'
* E.g. set LV_USE_FS_STDIO 'A' in lv_conf.h */
lv_img_set_src(img, "A:lvgl/examples/libs/png/wink.png");
lv_obj_align(img, LV_ALIGN_RIGHT_MID, -20, 0);
}
#endif

BIN
examples/libs/png/wink.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@@ -0,0 +1,6 @@
Create a QR Code
"""""""""""""""""""""""""""""""""""""""""""""""
.. lv_example:: libs/bmp/lv_example_qrcode_1
:language: c

View File

@@ -0,0 +1,38 @@
/**
* @file lv_example_qrcode.h
*
*/
#ifndef LV_EXAMPLE_QRCODE_H
#define LV_EXAMPLE_QRCODE_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void lv_example_qrcode_1(void);
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_EXAMPLE_QRCODE_H*/

View File

@@ -0,0 +1,32 @@
#include "../../lv_examples.h"
#if LV_USE_QRCODE && LV_BUILD_EXAMPLES
/**
* Create a QR Code
*/
void lv_example_qrcode_1(void)
{
lv_color_t bg_color = lv_palette_lighten(LV_PALETTE_LIGHT_BLUE, 5);
lv_color_t fg_color = lv_palette_darken(LV_PALETTE_BLUE, 4);
lv_obj_t * qr = lv_qrcode_create(lv_scr_act(), 150, fg_color, bg_color);
/*Set data*/
const char * data = "https://lvgl.io";
lv_qrcode_update(qr, data, strlen(data));
lv_obj_center(qr);
/*Add a border with bg_color*/
lv_obj_set_style_border_color(qr, bg_color, 0);
lv_obj_set_style_border_width(qr, 5, 0);
}
#endif

View File

@@ -0,0 +1,38 @@
/**
* @file lv_example_sjpg.h
*
*/
#ifndef LV_EXAMPLE_SJPG_H
#define LV_EXAMPLE_SJPG_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void lv_example_sjpg_1(void);
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_EXAMPLE_SJPG_H*/

View File

@@ -0,0 +1,14 @@
#include "../../lv_examples.h"
#if LV_USE_SJPG && LV_BUILD_EXAMPLES
void lv_example_sjpg_1(void)
{
lv_obj_t * wp;
wp = lv_img_create(lv_scr_act());
/* Assuming a File system is attached to letter 'A'
* E.g. set LV_USE_FS_STDIO 'A' in lv_conf.h */
lv_img_set_src(wp, "A:lvgl/examples/libs/sjpg/small_image.sjpg");
}
#endif

Binary file not shown.

View File

@@ -24,6 +24,7 @@ extern "C" {
#include "event/lv_example_event.h"
#include "styles/lv_example_style.h"
#include "others/lv_example_others.h"
#include "libs/lv_example_libs.h"
/*********************
* DEFINES

View File

@@ -537,6 +537,44 @@ e.g. "stm32f769xx.h" or "stm32f429xx.h"*/
/*A layout similar to Grid in CSS.*/
#define LV_USE_GRID 1
/*---------------------
* 3rd party libraries
*--------------------*/
/*File system interfaces for common APIs
*To enable set a driver letter for that API*/
#define LV_USE_FS_STDIO '\0' /*Uses fopen, fread, etc*/
//#define LV_FS_STDIO_PATH "/home/john/" /*Set the working directory. If commented it will be "./" */
#define LV_USE_FS_POSIX '\0' /*Uses open, read, etc*/
//#define LV_FS_POSIX_PATH "/home/john/" /*Set the working directory. If commented it will be "./" */
#define LV_USE_FS_FATFS '\0' /*Uses f_open, f_read, etc*/
/*PNG decoder library*/
#define LV_USE_PNG 0
/*BMP decoder library*/
#define LV_USE_BMP 0
/* JPG + split JPG decoder library.
* Split JPG is a custom format optimized for embedded systems. */
#define LV_USE_SJPG 0
/*GIF decoder library*/
#define LV_USE_GIF 0
/*QR code library*/
#define LV_USE_QRCODE 0
/*FreeType library*/
#define LV_USE_FREETYPE 0
#if LV_USE_FREETYPE
/*Memory used by FreeType to cache characters [bytes] (-1: no caching)*/
# define LV_FREETYPE_CACHE_SIZE (16 * 1024)
#endif
/*==================
* EXAMPLES
*==================*/

1
lvgl.h
View File

@@ -71,6 +71,7 @@ extern "C" {
#include "src/extra/layouts/lv_layouts.h"
#include "src/extra/themes/lv_themes.h"
#include "src/extra/others/lv_others.h"
#include "src/extra/libs/lv_libs.h"
/*********************
* DEFINES

138
scripts/jpg_to_sjpg.py Executable file
View File

@@ -0,0 +1,138 @@
##################################################################
# sjpeg converter script version 1.0
# Dependencies: (PYTHON-3)
##################################################################
SJPG_FILE_FORMAT_VERSION = "V1.00" #
JPEG_SPLIT_HEIGHT = 16
##################################################################
import math, os, sys, time
from PIL import Image
OUTPUT_FILE_NAME = ""
INPUT_FILE = ""
if len(sys.argv) == 2:
INPUT_FILE = sys.argv[1]
OUTPUT_FILE_NAME = INPUT_FILE.split("/")[-1].split("\\")[-1].split(".")[0]
else:
print("usage:\n\t python " + sys.argv[0] + " input_file.jpg")
sys.exit(0)
try:
im = Image.open(INPUT_FILE)
except:
print("\nFile not found!")
sys.exit(0)
print("\nConversion started...\n")
start_time = time.time()
width, height = im.size
print("Input:")
print("\t" + INPUT_FILE)
print("\tRES = " + str(width) + " x " + str(height) + '\n')
lenbuf = []
block_size = JPEG_SPLIT_HEIGHT;
spilts = math.ceil(height/block_size)
c_code = '''//LVGL SJPG C ARRAY\n#include "lvgl/lvgl.h"\n\nconst uint8_t ''' + OUTPUT_FILE_NAME + '''_map[] = {\n'''
sjpeg_data = bytearray()
sjpeg = bytearray()
row_remaining = height;
for i in range(spilts):
if row_remaining < block_size:
crop = im.crop((0, i*block_size, width, row_remaining + i*block_size))
else:
crop = im.crop((0, i*block_size, width, block_size + i*block_size))
row_remaining = row_remaining - block_size;
crop.save(str(i)+".jpg", quality=90)
for i in range(spilts):
f = open(str(i)+".jpg", "rb")
a = f.read()
f.close()
sjpeg_data = sjpeg_data + a
lenbuf.append(len(a))
header = bytearray()
#4 BYTES
header = header + bytearray("_SJPG__".encode("UTF-8"));
#6 BYTES VERSION
header = header + bytearray(("\x00" + SJPG_FILE_FORMAT_VERSION + "\x00").encode("UTF-8"));
#WIDTH 2 BYTES
header = header + width.to_bytes(2, byteorder='little');
#HEIGHT 2 BYTES
header = header + height.to_bytes(2, byteorder='little');
#NUMBER OF ITEMS 2 BYTES
header = header + spilts.to_bytes(2, byteorder='little');
#NUMBER OF ITEMS 2 BYTES
header = header + int(JPEG_SPLIT_HEIGHT).to_bytes(2, byteorder='little');
for item_len in lenbuf:
# WIDTH 2 BYTES
header = header + item_len.to_bytes(2, byteorder='little');
data = bytearray()
sjpeg = header + sjpeg_data;
if 1:
for i in range(len(lenbuf)):
os.remove(str(i) + ".jpg")
f = open(OUTPUT_FILE_NAME+".sjpg","wb");
f.write(sjpeg)
f.close()
new_line_threshold = 0
for i in range(len(sjpeg)):
c_code = c_code + "\t" + str(hex(sjpeg[i])) + ","
new_line_threshold = new_line_threshold + 1
if (new_line_threshold >= 16):
c_code = c_code + "\n"
new_line_threshold = 0
c_code = c_code + "\n};\n\nlv_img_dsc_t "
c_code = c_code + OUTPUT_FILE_NAME + " = {\n"
c_code = c_code + "\t.header.always_zero = 0,\n"
c_code = c_code + "\t.header.w = " + str(width) + ",\n"
c_code = c_code + "\t.header.h = " + str(height) + ",\n"
c_code = c_code + "\t.data_size = " + str(len(sjpeg)) + ",\n"
c_code = c_code + "\t.header.cf = LV_IMG_CF_RAW,\n"
c_code = c_code + "\t.data = " + OUTPUT_FILE_NAME+"_map" + ",\n};"
f = open(OUTPUT_FILE_NAME + '.c', 'w')
f.write(c_code)
f.close()
time_taken = (time.time() - start_time)
print("Output:")
print("\tTime taken = " + str(round(time_taken,2)) + " sec")
print("\tbin size = " + str(round(len(sjpeg)/1024, 1)) + " KB" )
print("\t" + OUTPUT_FILE_NAME + ".sjpg\t(bin file)" + "\n\t" + OUTPUT_FILE_NAME + ".c\t\t(c array)")
print("\nAll good!")

228
src/extra/libs/bmp/lv_bmp.c Normal file
View File

@@ -0,0 +1,228 @@
/**
* @file lv_bmp.c
*
*/
/*********************
* INCLUDES
*********************/
#include "../../../lvgl.h"
#if LV_USE_BMP
#include <string.h>
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef struct {
lv_fs_file_t f;
unsigned int px_offset;
int px_width;
int px_height;
unsigned int bpp;
int row_size_bytes;
} bmp_dsc_t;
/**********************
* STATIC PROTOTYPES
**********************/
static lv_res_t decoder_info(lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header);
static lv_res_t decoder_open(lv_img_decoder_t * dec, lv_img_decoder_dsc_t * dsc);
static lv_res_t decoder_read_line(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc,
lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf);
static void decoder_close(lv_img_decoder_t * dec, lv_img_decoder_dsc_t * dsc);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_bmp_init(void)
{
lv_img_decoder_t * dec = lv_img_decoder_create();
lv_img_decoder_set_info_cb(dec, decoder_info);
lv_img_decoder_set_open_cb(dec, decoder_open);
lv_img_decoder_set_read_line_cb(dec, decoder_read_line);
lv_img_decoder_set_close_cb(dec, decoder_close);
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Get info about a PNG image
* @param src can be file name or pointer to a C array
* @param header store the info here
* @return LV_RES_OK: no error; LV_RES_INV: can't get the info
*/
static lv_res_t decoder_info(lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header)
{
LV_UNUSED(decoder);
lv_img_src_t src_type = lv_img_src_get_type(src); /*Get the source type*/
/*If it's a BMP file...*/
if(src_type == LV_IMG_SRC_FILE) {
const char * fn = src;
if(!strcmp(&fn[strlen(fn) - 3], "bmp")) { /*Check the extension*/
/*Save the data in the header*/
lv_fs_file_t f;
lv_fs_res_t res = lv_fs_open(&f, src, LV_FS_MODE_RD);
if(res != LV_FS_RES_OK) return LV_RES_INV;
uint8_t headers[54];
lv_fs_read(&f, headers, 54, NULL);
uint32_t w;
uint32_t h;
memcpy(&w, headers + 18, 4);
memcpy(&h, headers + 22, 4);
header->w = w;
header->h = h;
header->always_zero = 0;
lv_fs_close(&f);
#if LV_COLOR_DEPTH == 32
uint16_t bpp;
memcpy(&bpp, headers + 28, 2);
header->cf = bpp == 32 ? LV_IMG_CF_TRUE_COLOR_ALPHA : LV_IMG_CF_TRUE_COLOR;
#else
header->cf = LV_IMG_CF_TRUE_COLOR;
#endif
return LV_RES_OK;
}
}
/* BMP file as data not supported for simplicity.
* Convert them to LVGL compatible C arrays directly. */
else if(src_type == LV_IMG_SRC_VARIABLE) {
return LV_RES_INV;
}
return LV_RES_INV; /*If didn't succeeded earlier then it's an error*/
}
/**
* Open a PNG image and return the decided image
* @param src can be file name or pointer to a C array
* @param style style of the image object (unused now but certain formats might use it)
* @return pointer to the decoded image or `LV_IMG_DECODER_OPEN_FAIL` if failed
*/
static lv_res_t decoder_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
{
LV_UNUSED(decoder);
/*If it's a PNG file...*/
if(dsc->src_type == LV_IMG_SRC_FILE) {
const char * fn = dsc->src;
if(strcmp(&fn[strlen(fn) - 3], "bmp")) return LV_RES_INV; /*Check the extension*/
bmp_dsc_t b;
memset(&b, 0x00, sizeof(b));
lv_fs_res_t res = lv_fs_open(&b.f, dsc->src, LV_FS_MODE_RD);
if(res == LV_RES_OK) return LV_RES_INV;
uint8_t header[54];
lv_fs_read(&b.f, header, 54, NULL);
if (0x42 != header[0] || 0x4d != header[1]) {
return LV_RES_INV;
}
memcpy(&b.px_offset, header + 10, 4);
memcpy(&b.px_width, header + 18, 4);
memcpy(&b.px_height, header + 22, 4);
memcpy(&b.bpp, header + 28, 2);
b.row_size_bytes = (b.bpp * b.px_width) / 8;
dsc->user_data = lv_mem_alloc(sizeof(bmp_dsc_t));
LV_ASSERT_MALLOC(dsc->user_data);
if(dsc->user_data == NULL) return LV_RES_INV;
memcpy(dsc->user_data, &b, sizeof(b));
dsc->img_data = NULL;
return LV_RES_OK;
}
/* BMP file as data not supported for simplicity.
* Convert them to LVGL compatible C arrays directly. */
else if(dsc->src_type == LV_IMG_SRC_VARIABLE) {
return LV_RES_INV;
}
return LV_RES_INV; /*If not returned earlier then it failed*/
}
static lv_res_t decoder_read_line(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc,
lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf)
{
LV_UNUSED(decoder);
bmp_dsc_t * b = dsc->user_data;
y = (b->px_height - 1) - y; /*BMP images are stored upside down*/
uint32_t p = b->px_offset + b->row_size_bytes * y;
p += x * (b->bpp / 8);
lv_fs_seek(&b->f, p, LV_FS_SEEK_SET);
lv_fs_read(&b->f, buf, len * (b->bpp / 8), NULL);
#if LV_COLOR_DEPTH == 32
if(b->bpp == 32) {
lv_coord_t i;
for(i = 0; i < len; i++) {
uint8_t b0 = buf[i * 4];
uint8_t b1 = buf[i * 4 + 1];
uint8_t b2 = buf[i * 4 + 2];
uint8_t b3 = buf[i * 4 + 3];
lv_color32_t *c = (lv_color32_t*)&buf[i*4];
c->ch.red = b2;
c->ch.green = b1;
c->ch.blue = b0;
c->ch.alpha = b3;
}
}
if(b->bpp == 24) {
lv_coord_t i;
for(i = len - 1; i >= 0; i--) {
uint8_t * t = &buf[i * 3];
lv_color32_t *c = (lv_color32_t*)&buf[i*4];
c->ch.red = t[2];
c->ch.green = t[1];
c->ch.blue = t[0];
c->ch.alpha = 0xff;
}
}
#endif
return LV_RES_OK;
}
/**
* Free the allocated resources
*/
static void decoder_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
{
LV_UNUSED(decoder);
bmp_dsc_t * b = dsc->user_data;
lv_fs_close(&b->f);
lv_mem_free(dsc->user_data);
}
#endif /*LV_USE_BMP*/

View File

@@ -0,0 +1,42 @@
/**
* @file lv_templ.h
*
*/
#ifndef LV_BMP_H
#define LV_BMP_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../../lv_conf_internal.h"
#if LV_USE_BMP
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void lv_bmp_init(void);
/**********************
* MACROS
**********************/
#endif /*LV_USE_BMP*/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*LV_BMP_H*/

Binary file not shown.

View File

@@ -0,0 +1,480 @@
/**
* @file lv_freetype.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_freetype.h"
#if LV_USE_FREETYPE
#include "ft2build.h"
#include FT_FREETYPE_H
#include FT_GLYPH_H
#include FT_CACHE_H
#include FT_SIZES_H
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef struct {
char * name;
} lv_face_info_t;
typedef struct {
lv_ll_t face_ll;
} lv_faces_control_t;
typedef struct {
#if LV_FREETYPE_CACHE_SIZE >= 0
void * face_id;
#else
FT_Size size;
#endif
lv_font_t * font;
uint16_t style;
uint16_t height;
} lv_font_fmt_ft_dsc_t;
/**********************
* STATIC PROTOTYPES
**********************/
#if LV_FREETYPE_CACHE_SIZE >= 0
static FT_Error font_face_requester(FTC_FaceID face_id,
FT_Library library_is, FT_Pointer req_data, FT_Face * aface);
static bool lv_ft_font_init_cache(lv_ft_info_t * info);
static void lv_ft_font_destroy_cache(lv_font_t * font);
static bool lv_ft_font_init_cache(lv_ft_info_t * info);
static void lv_ft_font_destroy_cache(lv_font_t * font);
#else
static FT_Face face_find_in_list(lv_ft_info_t * info);
static void face_add_to_list(FT_Face face);
static void face_remove_from_list(FT_Face face);
static void face_generic_finalizer(void * object);
static bool lv_ft_font_init_nocache(lv_ft_info_t * info);
static void lv_ft_font_destroy_nocache(lv_font_t * font);
#endif
/**********************
* STATIC VARIABLES
**********************/
static FT_Library library;
#if LV_FREETYPE_CACHE_SIZE >= 0
static FTC_Manager cache_manager;
static FTC_CMapCache cmap_cache;
static FTC_SBitCache sbit_cache;
static FTC_SBit sbit;
#else
static lv_faces_control_t face_control;
#endif
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
bool lv_freetype_init(uint16_t max_faces, uint16_t max_sizes, uint32_t max_bytes)
{
FT_Error error = FT_Init_FreeType(&library);
if(error) {
LV_LOG_ERROR("init freeType error(%d)", error);
return false;
}
#if LV_FREETYPE_CACHE_SIZE >= 0
error = FTC_Manager_New(library, max_faces, max_sizes,
max_bytes, font_face_requester, NULL, &cache_manager);
if(error) {
FT_Done_FreeType(library);
LV_LOG_ERROR("Failed to open cache manager");
return false;
}
error = FTC_CMapCache_New(cache_manager, &cmap_cache);
if(error) {
LV_LOG_ERROR("Failed to open Cmap Cache");
goto Fail;
}
error = FTC_SBitCache_New(cache_manager, &sbit_cache);
if(error) {
LV_LOG_ERROR("Failed to open sbit cache");
goto Fail;
}
return true;
Fail:
FTC_Manager_Done(cache_manager);
FT_Done_FreeType(library);
return false;
#else
LV_UNUSED(max_faces);
LV_UNUSED(max_sizes);
LV_UNUSED(max_bytes);
_lv_ll_init(&face_control.face_ll, sizeof(FT_Face *));
return true;
#endif/* LV_FREETYPE_CACHE_SIZE */
}
void lv_freetype_destroy(void)
{
#if LV_FREETYPE_CACHE_SIZE >= 0
FTC_Manager_Done(cache_manager);
#endif
FT_Done_FreeType(library);
}
bool lv_ft_font_init(lv_ft_info_t * info)
{
#if LV_FREETYPE_CACHE_SIZE >= 0
return lv_ft_font_init_cache(info);
#else
return lv_ft_font_init_nocache(info);
#endif
}
void lv_ft_font_destroy(lv_font_t * font)
{
#if LV_FREETYPE_CACHE_SIZE >= 0
lv_ft_font_destroy_cache(font);
#else
lv_ft_font_destroy_nocache(font);
#endif
}
/**********************
* STATIC FUNCTIONS
**********************/
#if LV_FREETYPE_CACHE_SIZE >= 0
static FT_Error font_face_requester(FTC_FaceID face_id,
FT_Library library_is, FT_Pointer req_data, FT_Face * aface)
{
LV_UNUSED(library_is);
LV_UNUSED(req_data);
lv_face_info_t * info = (lv_face_info_t *)face_id;
FT_Error error = FT_New_Face(library, info->name, 0, aface);
if(error) {
LV_LOG_ERROR("FT_New_Face error:%d\n", error);
return error;
}
return FT_Err_Ok;
}
static bool get_glyph_dsc_cb_cache(const lv_font_t * font,
lv_font_glyph_dsc_t * dsc_out, uint32_t unicode_letter, uint32_t unicode_letter_next)
{
LV_UNUSED(unicode_letter_next);
if(unicode_letter < 0x20) {
dsc_out->adv_w = 0;
dsc_out->box_h = 0;
dsc_out->box_w = 0;
dsc_out->ofs_x = 0;
dsc_out->ofs_y = 0;
dsc_out->bpp = 0;
return true;
}
lv_font_fmt_ft_dsc_t * dsc = (lv_font_fmt_ft_dsc_t *)(font->dsc);
FT_Face face;
FTC_ImageTypeRec desc_sbit_type;
FTC_FaceID face_id = (FTC_FaceID)dsc->face_id;
FTC_Manager_LookupFace(cache_manager, face_id, &face);
desc_sbit_type.face_id = face_id;
desc_sbit_type.flags = FT_LOAD_RENDER | FT_LOAD_TARGET_NORMAL;
desc_sbit_type.height = dsc->height;
desc_sbit_type.width = dsc->height;
FT_UInt charmap_index = FT_Get_Charmap_Index(face->charmap);
FT_UInt glyph_index = FTC_CMapCache_Lookup(cmap_cache, face_id, charmap_index, unicode_letter);
FT_Error error = FTC_SBitCache_Lookup(sbit_cache, &desc_sbit_type, glyph_index, &sbit, NULL);
if(error) {
LV_LOG_ERROR("SBitCache_Lookup error");
}
dsc_out->adv_w = sbit->xadvance;
dsc_out->box_h = sbit->height; /*Height of the bitmap in [px]*/
dsc_out->box_w = sbit->width; /*Width of the bitmap in [px]*/
dsc_out->ofs_x = sbit->left; /*X offset of the bitmap in [pf]*/
dsc_out->ofs_y = sbit->top - sbit->height; /*Y offset of the bitmap measured from the as line*/
dsc_out->bpp = 8; /*Bit per pixel: 1/2/4/8*/
return true;
}
static const uint8_t * get_glyph_bitmap_cb_cache(const lv_font_t * font, uint32_t unicode_letter)
{
LV_UNUSED(font);
LV_UNUSED(unicode_letter);
return (const uint8_t *)sbit->buffer;
}
static bool lv_ft_font_init_cache(lv_ft_info_t * info)
{
lv_font_fmt_ft_dsc_t * dsc = lv_mem_alloc(sizeof(lv_font_fmt_ft_dsc_t));
if(dsc == NULL) return false;
dsc->font = lv_mem_alloc(sizeof(lv_font_t));
if(dsc->font == NULL) {
lv_mem_free(dsc);
return false;
}
lv_face_info_t * face_info = NULL;
face_info = lv_mem_alloc(sizeof(lv_face_info_t) + strlen(info->name) + 1);
if(face_info == NULL) {
goto Fail;
}
face_info->name = ((char *)face_info) + sizeof(lv_face_info_t);
strcpy(face_info->name, info->name);
dsc->face_id = face_info;
dsc->height = info->weight;
dsc->style = info->style;
/* use to get font info */
FT_Size face_size;
struct FTC_ScalerRec_ scaler;
scaler.face_id = (FTC_FaceID)dsc->face_id;
scaler.width = info->weight;
scaler.height = info->weight;
scaler.pixel = 1;
FT_Error error = FTC_Manager_LookupSize(cache_manager, &scaler, &face_size);
if(error) {
lv_mem_free(face_info);
LV_LOG_ERROR("Failed to LookupSize");
goto Fail;
}
lv_font_t * font = dsc->font;
font->dsc = dsc;
font->get_glyph_dsc = get_glyph_dsc_cb_cache;
font->get_glyph_bitmap = get_glyph_bitmap_cb_cache;
font->subpx = LV_FONT_SUBPX_NONE;
font->line_height = (face_size->face->size->metrics.height >> 6);
font->base_line = -(face_size->face->size->metrics.descender >> 6);
font->underline_position = face_size->face->underline_position;
font->underline_thickness = face_size->face->underline_thickness;
/* return to user */
info->font = font;
return true;
Fail:
lv_mem_free(dsc->font);
lv_mem_free(dsc);
return false;
}
void lv_ft_font_destroy_cache(lv_font_t * font)
{
if(font == NULL) {
return;
}
lv_font_fmt_ft_dsc_t * dsc = (lv_font_fmt_ft_dsc_t *)(font->dsc);
if(dsc) {
lv_mem_free(dsc->face_id);
lv_mem_free(dsc->font);
lv_mem_free(dsc);
}
}
#else/* LV_FREETYPE_CACHE_SIZE */
static FT_Face face_find_in_list(lv_ft_info_t * info)
{
lv_face_info_t * face_info;
FT_Face * pface = _lv_ll_get_head(&face_control.face_ll);
while(pface) {
face_info = (lv_face_info_t *)(*pface)->generic.data;
if(strcmp(face_info->name, info->name) == 0) {
return *pface;
}
pface = _lv_ll_get_next(&face_control.face_ll, pface);
}
return NULL;
}
static void face_add_to_list(FT_Face face)
{
FT_Face * pface;
pface = (FT_Face *)_lv_ll_ins_tail(&face_control.face_ll);
*pface = face;
}
static void face_remove_from_list(FT_Face face)
{
FT_Face * pface = _lv_ll_get_head(&face_control.face_ll);
while(pface) {
if(*pface == face) {
_lv_ll_remove(&face_control.face_ll, pface);
lv_mem_free(pface);
break;
}
pface = _lv_ll_get_next(&face_control.face_ll, pface);
}
}
static void face_generic_finalizer(void * object)
{
FT_Face face = (FT_Face)object;
face_remove_from_list(face);
if(face->generic.data) {
lv_face_info_t * face_info = (lv_face_info_t *)face->generic.data;
lv_mem_free(face_info);
}
LV_LOG_INFO("face finalizer(%p)\n", face);
}
static bool get_glyph_dsc_cb_nocache(const lv_font_t * font,
lv_font_glyph_dsc_t * dsc_out, uint32_t unicode_letter, uint32_t unicode_letter_next)
{
LV_UNUSED(unicode_letter_next);
if(unicode_letter < 0x20) {
dsc_out->adv_w = 0;
dsc_out->box_h = 0;
dsc_out->box_w = 0;
dsc_out->ofs_x = 0;
dsc_out->ofs_y = 0;
dsc_out->bpp = 0;
return true;
}
FT_Error error;
lv_font_fmt_ft_dsc_t * dsc = (lv_font_fmt_ft_dsc_t *)(font->dsc);
FT_Face face = dsc->size->face;
FT_UInt glyph_index = FT_Get_Char_Index(face, unicode_letter);
if(face->size != dsc->size) {
FT_Activate_Size(dsc->size);
}
error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
if(error) {
return false;
}
error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
if(error) {
return false;
}
dsc_out->adv_w = (face->glyph->metrics.horiAdvance >> 6);
dsc_out->box_h = face->glyph->bitmap.rows; /*Height of the bitmap in [px]*/
dsc_out->box_w = face->glyph->bitmap.width; /*Width of the bitmap in [px]*/
dsc_out->ofs_x = face->glyph->bitmap_left; /*X offset of the bitmap in [pf]*/
dsc_out->ofs_y = face->glyph->bitmap_top -
face->glyph->bitmap.rows; /*Y offset of the bitmap measured from the as line*/
dsc_out->bpp = 8; /*Bit per pixel: 1/2/4/8*/
return true;
}
static const uint8_t * get_glyph_bitmap_cb_nocache(const lv_font_t * font, uint32_t unicode_letter)
{
LV_UNUSED(unicode_letter);
lv_font_fmt_ft_dsc_t * dsc = (lv_font_fmt_ft_dsc_t *)(font->dsc);
FT_Face face = dsc->size->face;
return (const uint8_t *)(face->glyph->bitmap.buffer);
}
static bool lv_ft_font_init_nocache(lv_ft_info_t * info)
{
lv_font_fmt_ft_dsc_t * dsc = lv_mem_alloc(sizeof(lv_font_fmt_ft_dsc_t));
if(dsc == NULL) return false;
dsc->font = lv_mem_alloc(sizeof(lv_font_t));
if(dsc->font == NULL) {
lv_mem_free(dsc);
return false;
}
lv_face_info_t * face_info = NULL;
FT_Face face = face_find_in_list(info);
if(face == NULL) {
face_info = lv_mem_alloc(sizeof(lv_face_info_t) + strlen(info->name) + 1);
if(face_info == NULL) {
goto Fail;
}
FT_Error error = FT_New_Face(library, info->name, 0, &face);
if(error) {
lv_mem_free(face_info);
LV_LOG_WARN("create face error(%d)", error);
goto Fail;
}
/* link face and face info */
face_info->name = ((char *)face_info) + sizeof(lv_face_info_t);
strcpy(face_info->name, info->name);
face->generic.data = face_info;
face->generic.finalizer = face_generic_finalizer;
face_add_to_list(face);
}
else {
FT_Size size;
FT_Error error = FT_New_Size(face, &size);
if(error) {
goto Fail;
}
FT_Activate_Size(size);
FT_Reference_Face(face);
}
FT_Set_Pixel_Sizes(face, 0, info->weight);
dsc->size = face->size;
dsc->height = info->weight;
dsc->style = info->style;
lv_font_t * font = dsc->font;
font->dsc = dsc;
font->get_glyph_dsc = get_glyph_dsc_cb_nocache;
font->get_glyph_bitmap = get_glyph_bitmap_cb_nocache;
font->line_height = (face->size->metrics.height >> 6);
font->base_line = -(face->size->metrics.descender >> 6);
font->underline_position = face->underline_position;
font->underline_thickness = face->underline_thickness;
font->subpx = LV_FONT_SUBPX_NONE;
info->font = font;
return true;
Fail:
lv_mem_free(dsc->font);
lv_mem_free(dsc);
return false;
}
static void lv_ft_font_destroy_nocache(lv_font_t * font)
{
if(font == NULL) {
return;
}
lv_font_fmt_ft_dsc_t * dsc = (lv_font_fmt_ft_dsc_t *)(font->dsc);
if(dsc) {
FT_Face face = dsc->size->face;
FT_Done_Size(dsc->size);
FT_Done_Face(face);
lv_mem_free(dsc->font);
lv_mem_free(dsc);
}
}
#endif/* LV_FREETYPE_CACHE_SIZE */
#endif /*LV_USE_FREETYPE*/

View File

@@ -0,0 +1,81 @@
/**
* @file lv_freetype.h
*
*/
#ifndef LV_FREETYPE_H
#define LV_FREETYPE_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../../lvgl.h"
#if LV_USE_FREETYPE
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef enum {
FT_FONT_STYLE_NORMAL = 0,
FT_FONT_STYLE_ITALIC = 1 << 0,
FT_FONT_STYLE_BOLD = 1 << 1
} LV_FT_FONT_STYLE;
typedef struct {
const char * name; /* The name of the font file */
lv_font_t * font; /* point to lvgl font */
uint16_t weight; /* font size */
uint16_t style; /* font style */
} lv_ft_info_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* init freetype library
* @param max_faces Maximum number of opened FT_Face objects managed by this cache instance. Use 0 for defaults.
* @param max_sizes Maximum number of opened FT_Size objects managed by this cache instance. Use 0 for defaults.
* @param max_bytes Maximum number of bytes to use for cached data nodes. Use 0 for defaults.
* Note that this value does not account for managed FT_Face and FT_Size objects.
* @return true on success, otherwise false.
*/
bool lv_freetype_init(uint16_t max_faces, uint16_t max_sizes, uint32_t max_bytes);
/**
* Destroy freetype library
*/
void lv_freetype_destroy(void);
/**
* Creates a font with info parameter specified.
* @param info See lv_ft_info_t for details.
* when success, lv_ft_info_t->font point to the font you created.
* @return true on success, otherwise false.
*/
bool lv_ft_font_init(lv_ft_info_t * info);
/**
* Destroy a font that has been created.
* @param font pointer to font.
*/
void lv_ft_font_destroy(lv_font_t * font);
/**********************
* MACROS
**********************/
#endif /*LV_USE_FREETYPE*/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* LV_FREETYPE_H */

View File

@@ -0,0 +1,258 @@
/**
* @file lv_fs_fatfs.c
*
*/
/*********************
* INCLUDES
*********************/
#include "../../../lvgl.h"
#if LV_USE_FS_FATFS != '\0'
#include "ff.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void fs_init(void);
static void * fs_open (lv_fs_drv_t * drv, const char * path, lv_fs_mode_t mode);
static lv_fs_res_t fs_close (lv_fs_drv_t * drv, void * file_p);
static lv_fs_res_t fs_read (lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br);
static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw);
static lv_fs_res_t fs_seek (lv_fs_drv_t * drv, void * file_p, uint32_t pos, lv_fs_whence_t whence);
static lv_fs_res_t fs_tell (lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p);
static void * fs_dir_open (lv_fs_drv_t * drv, const char *path);
static lv_fs_res_t fs_dir_read (lv_fs_drv_t * drv, void * dir_p, char *fn);
static lv_fs_res_t fs_dir_close (lv_fs_drv_t * drv, void * dir_p);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_fs_if_fatfs_init(void)
{
/*----------------------------------------------------
* Initialize your storage device and File System
* -------------------------------------------------*/
fs_init();
/*---------------------------------------------------
* Register the file system interface in LittlevGL
*--------------------------------------------------*/
/* Add a simple drive to open images */
static lv_fs_drv_t fs_drv; /*A driver descriptor*/
lv_fs_drv_init(&fs_drv);
/*Set up fields...*/
fs_drv.letter = LV_USE_FS_FATFS;
fs_drv.open_cb = fs_open;
fs_drv.close_cb = fs_close;
fs_drv.read_cb = fs_read;
fs_drv.write_cb = fs_write;
fs_drv.seek_cb = fs_seek;
fs_drv.tell_cb = fs_tell;
fs_drv.dir_close_cb = fs_dir_close;
fs_drv.dir_open_cb = fs_dir_open;
fs_drv.dir_read_cb = fs_dir_read;
lv_fs_drv_register(&fs_drv);
}
/**********************
* STATIC FUNCTIONS
**********************/
/* Initialize your Storage device and File system. */
static void fs_init(void)
{
/* Initialize the SD card and FatFS itself.
* Better to do it in your code to keep this library utouched for easy updating*/
}
/**
* Open a file
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable
* @param path path to the file beginning with the driver letter (e.g. S:/folder/file.txt)
* @param mode read: FS_MODE_RD, write: FS_MODE_WR, both: FS_MODE_RD | FS_MODE_WR
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static void * fs_open (lv_fs_drv_t * drv, const char * path, lv_fs_mode_t mode)
{
uint8_t flags = 0;
if(mode == LV_FS_MODE_WR) flags = FA_WRITE | FA_OPEN_ALWAYS;
else if(mode == LV_FS_MODE_RD) flags = FA_READ;
else if(mode == (LV_FS_MODE_WR | LV_FS_MODE_RD)) flags = FA_READ | FA_WRITE | FA_OPEN_ALWAYS;
FIL * f = lv_mem_alloc(sizeof(FIL));
if(f == NULL) return NULL;
FRESULT res = f_open(f, path, flags);
if(res == FR_OK) {
f_lseek(f, 0);
return f;
} else {
return NULL;
}
}
/**
* Close an opened file
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable. (opened with lv_ufs_open)
* @return LV_FS_RES_OK: no error, the file is read
* any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_close (lv_fs_drv_t * drv, void * file_p)
{
f_close(file_p);
return LV_FS_RES_OK;
}
/**
* Read data from an opened file
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable.
* @param buf pointer to a memory block where to store the read data
* @param btr number of Bytes To Read
* @param br the real number of read bytes (Byte Read)
* @return LV_FS_RES_OK: no error, the file is read
* any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_read (lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br)
{
FRESULT res = f_read(file_p, buf, btr, (UINT*)br);
if(res == FR_OK) return LV_FS_RES_OK;
else return LV_FS_RES_UNKNOWN;
}
/**
* Write into a file
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable
* @param buf pointer to a buffer with the bytes to write
* @param btr Bytes To Write
* @param br the number of real written bytes (Bytes Written). NULL if unused.
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw)
{
FRESULT res = f_write(file_p, buf, btw, (UINT*)bw);
if(res == FR_OK) return LV_FS_RES_OK;
else return LV_FS_RES_UNKNOWN;
}
/**
* Set the read write pointer. Also expand the file size if necessary.
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable. (opened with lv_ufs_open )
* @param pos the new position of read write pointer
* @param whence only LV_SEEK_SET is supported
* @return LV_FS_RES_OK: no error, the file is read
* any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_seek (lv_fs_drv_t * drv, void * file_p, uint32_t pos, lv_fs_whence_t whence)
{
LV_UNUSED(whence);
f_lseek(file_p, pos);
return LV_FS_RES_OK;
}
/**
* Give the position of the read write pointer
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable.
* @param pos_p pointer to to store the result
* @return LV_FS_RES_OK: no error, the file is read
* any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_tell (lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p)
{
*pos_p = f_tell(((FIL *)file_p));
return LV_FS_RES_OK;
}
/**
* Initialize a 'fs_read_dir_t' variable for directory reading
* @param drv pointer to a driver where this function belongs
* @param dir_p pointer to a 'fs_read_dir_t' variable
* @param path path to a directory
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static void * fs_dir_open (lv_fs_drv_t * drv, const char *path)
{
DIR * d = lv_mem_alloc(sizeof(DIR));
if(d == NULL) return NULL;
FRESULT res = f_opendir(d, path);
if(res != FR_OK) {
lv_mem_free(d);
d = NULL;
}
return d;
}
/**
* Read the next filename form a directory.
* The name of the directories will begin with '/'
* @param drv pointer to a driver where this function belongs
* @param dir_p pointer to an initialized 'fs_read_dir_t' variable
* @param fn pointer to a buffer to store the filename
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_dir_read (lv_fs_drv_t * drv, void * dir_p, char *fn)
{
FRESULT res;
FILINFO fno;
fn[0] = '\0';
do {
res = f_readdir(dir_p, &fno);
if(res != FR_OK) return LV_FS_RES_UNKNOWN;
if(fno.fattrib & AM_DIR) {
fn[0] = '/';
strcpy(&fn[1], fno.fname);
}
else strcpy(fn, fno.fname);
} while(strcmp(fn, "/.") == 0 || strcmp(fn, "/..") == 0);
return LV_FS_RES_OK;
}
/**
* Close the directory reading
* @param drv pointer to a driver where this function belongs
* @param dir_p pointer to an initialized 'fs_read_dir_t' variable
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_dir_close (lv_fs_drv_t * drv, void * dir_p)
{
f_closedir(dir_p);
return LV_FS_RES_OK;
}
#endif /*LV_USE_FS_FATFS*/

View File

@@ -0,0 +1,50 @@
/**
* @file lv_fs_libs.h
*
*/
#ifndef LV_FS_LIBS_H
#define LV_FS_LIBS_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
#if LV_USE_FS_FATFS != '\0'
void lv_fs_fatfs_init(void);
#endif
#if LV_USE_FS_STDIO != '\0'
void lv_fs_stdio_init(void);
#endif
#if LV_USE_FS_POSIX != '\0'
void lv_fs_posix_init(void);
#endif
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*LV_FS_LIBS_H*/

View File

@@ -0,0 +1,334 @@
/**
* @file lv_fs_posix.c
*
*/
/*********************
* INCLUDES
*********************/
#include "../../../lvgl.h"
#if LV_USE_FS_POSIX != '\0'
#include <fcntl.h>
#include <errno.h>
#include <dirent.h>
#include <unistd.h>
#include <stdio.h>
#ifdef WIN32
#include <windows.h>
#endif
/*********************
* DEFINES
*********************/
#ifndef LV_FS_POSIX_PATH
# ifndef WIN32
# define LV_FS_POSIX_PATH "./" /*Project root*/
# else
# define LV_FS_POSIX_PATH ".\\" /*Project root*/
# endif
#endif /*LV_FS_PATH*/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void * fs_open (lv_fs_drv_t * drv, const char * path, lv_fs_mode_t mode);
static lv_fs_res_t fs_close (lv_fs_drv_t * drv, void * file_p);
static lv_fs_res_t fs_read (lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br);
static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw);
static lv_fs_res_t fs_seek (lv_fs_drv_t * drv, void * file_p, uint32_t pos, lv_fs_whence_t whence);
static lv_fs_res_t fs_tell (lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p);
static void * fs_dir_open (lv_fs_drv_t * drv, const char *path);
static lv_fs_res_t fs_dir_read (lv_fs_drv_t * drv, void * dir_p, char *fn);
static lv_fs_res_t fs_dir_close (lv_fs_drv_t * drv, void * dir_p);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Register a driver for the File system interface
*/
void lv_fs_posix_init(void)
{
/*---------------------------------------------------
* Register the file system interface in LittlevGL
*--------------------------------------------------*/
/* Add a simple drive to open images */
static lv_fs_drv_t fs_drv; /*A driver descriptor*/
lv_fs_drv_init(&fs_drv);
/*Set up fields...*/
fs_drv.letter = LV_USE_FS_POSIX;
fs_drv.open_cb = fs_open;
fs_drv.close_cb = fs_close;
fs_drv.read_cb = fs_read;
fs_drv.write_cb = fs_write;
fs_drv.seek_cb = fs_seek;
fs_drv.tell_cb = fs_tell;
fs_drv.dir_close_cb = fs_dir_close;
fs_drv.dir_open_cb = fs_dir_open;
fs_drv.dir_read_cb = fs_dir_read;
lv_fs_drv_register(&fs_drv);
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Open a file
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable
* @param path path to the file beginning with the driver letter (e.g. S:/folder/file.txt)
* @param mode read: FS_MODE_RD, write: FS_MODE_WR, both: FS_MODE_RD | FS_MODE_WR
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static void * fs_open (lv_fs_drv_t * drv, const char * path, lv_fs_mode_t mode)
{
(void) drv; /*Unused*/
errno = 0;
uint32_t flags = 0;
if(mode == LV_FS_MODE_WR) flags = O_WRONLY;
else if(mode == LV_FS_MODE_RD) flags = O_RDONLY;
else if(mode == (LV_FS_MODE_WR | LV_FS_MODE_RD)) flags = O_RDWR;
/*Make the path relative to the current directory (the projects root folder)*/
char buf[256];
sprintf(buf, LV_FS_POSIX_PATH "%s", path);
int f = open(buf, flags);
if(f < 0) return NULL;
/*Be sure we are the beginning of the file*/
lseek(f, 0, SEEK_SET);
int * fp = lv_mem_alloc(sizeof(int));
if(fp == NULL) return NULL;
*fp = f;
return fp;
}
/**
* Close an opened file
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable. (opened with lv_ufs_open)
* @return LV_FS_RES_OK: no error, the file is read
* any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_close (lv_fs_drv_t * drv, void * file_p)
{
(void) drv; /*Unused*/
int * fp = file_p;
close(*fp);
lv_mem_free(file_p);
return LV_FS_RES_OK;
}
/**
* Read data from an opened file
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable.
* @param buf pointer to a memory block where to store the read data
* @param btr number of Bytes To Read
* @param br the real number of read bytes (Byte Read)
* @return LV_FS_RES_OK: no error, the file is read
* any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_read (lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br)
{
(void) drv; /*Unused*/
int * fp = file_p;
*br = read(*fp, buf, btr);
return LV_FS_RES_OK;
}
/**
* Write into a file
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable
* @param buf pointer to a buffer with the bytes to write
* @param btr Bytes To Write
* @param br the number of real written bytes (Bytes Written). NULL if unused.
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw)
{
(void) drv; /*Unused*/
int * fp = file_p;
*bw = write(*fp, buf, btw);
return LV_FS_RES_OK;
}
/**
* Set the read write pointer. Also expand the file size if necessary.
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable. (opened with lv_ufs_open )
* @param pos the new position of read write pointer
* @return LV_FS_RES_OK: no error, the file is read
* any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_seek (lv_fs_drv_t * drv, void * file_p, uint32_t pos, lv_fs_whence_t whence)
{
(void) drv; /*Unused*/
int * fp = file_p;
lseek(*fp, pos, whence);
return LV_FS_RES_OK;
}
/**
* Give the position of the read write pointer
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable.
* @param pos_p pointer to to store the result
* @return LV_FS_RES_OK: no error, the file is read
* any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_tell (lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p)
{
(void) drv; /*Unused*/
int * fp = file_p;
*pos_p = lseek(*fp, 0, SEEK_CUR);
return LV_FS_RES_OK;
}
#ifdef WIN32
static char next_fn[256];
#endif
/**
* Initialize a 'fs_read_dir_t' variable for directory reading
* @param drv pointer to a driver where this function belongs
* @param dir_p pointer to a 'fs_read_dir_t' variable
* @param path path to a directory
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static void * fs_dir_open (lv_fs_drv_t * drv, const char *path)
{
LV_UNUSED(drv);
#ifndef WIN32
/*Make the path relative to the current directory (the projects root folder)*/
char buf[256];
sprintf(buf, LV_FS_POSIX_PATH "/%s", path);
return opendir(buf);
#else
HANDLE d = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA fdata;
/*Make the path relative to the current directory (the projects root folder)*/
char buf[256];
sprintf(buf, LV_FS_PC_PATH "\\%s\\*", path);
strcpy(next_fn, "");
d = FindFirstFile(buf, &fdata);
do {
if (strcmp(fdata.cFileName, ".") == 0 || strcmp(fdata.cFileName, "..") == 0) {
continue;
} else {
if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
sprintf(next_fn, "/%s", fdata.cFileName);
} else {
sprintf(next_fn, "%s", fdata.cFileName);
}
break;
}
} while(FindNextFileA(d, &fdata));
return d;
#endif
}
/**
* Read the next filename form a directory.
* The name of the directories will begin with '/'
* @param drv pointer to a driver where this function belongs
* @param dir_p pointer to an initialized 'fs_read_dir_t' variable
* @param fn pointer to a buffer to store the filename
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_dir_read (lv_fs_drv_t * drv, void * dir_p, char *fn)
{
LV_UNUSED(drv);
LV_UNUSED(dir_p);
LV_UNUSED(fn);
// #ifndef WIN32
// struct dirent *entry;
// do {
// entry = readdir(dir_p);
// if(entry) {
// if(entry->d_type == DT_DIR) sprintf(fn, "/%s", entry->d_name);
// else strcpy(fn, entry->d_name);
// } else {
// strcpy(fn, "");
// }
// } while(strcmp(fn, "/.") == 0 || strcmp(fn, "/..") == 0);
// #else
// strcpy(fn, next_fn);
// strcpy(next_fn, "");
// WIN32_FIND_DATA fdata;
// if(FindNextFile(dir_p, &fdata) == false) return LV_FS_RES_OK;
// do {
// if (strcmp(fdata.cFileName, ".") == 0 || strcmp(fdata.cFileName, "..") == 0) {
// continue;
// } else {
// if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
// {
// sprintf(next_fn, "/%s", fdata.cFileName);
// } else {
// sprintf(next_fn, "%s", fdata.cFileName);
// }
// break;
// }
// } while(FindNextFile(dir_p, &fdata));
// #endif
return LV_FS_RES_OK;
}
/**
* Close the directory reading
* @param drv pointer to a driver where this function belongs
* @param dir_p pointer to an initialized 'fs_read_dir_t' variable
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_dir_close (lv_fs_drv_t * drv, void * dir_p)
{
LV_UNUSED(drv);
#ifndef WIN32
closedir(dir_p);
#else
FindClose(dir_p);
#endif
return LV_FS_RES_OK;
}
#endif /*LV_USE_FS_POSIX*/

View File

@@ -0,0 +1,330 @@
/**
* @file lv_fs_stdio.c
*
*/
/*********************
* INCLUDES
*********************/
#include "../../../lvgl.h"
#if LV_USE_FS_STDIO != '\0'
#include <stdio.h>
#include <errno.h>
#include <dirent.h>
#include <unistd.h>
#ifdef WIN32
#include <windows.h>
#endif
/*********************
* DEFINES
*********************/
#ifndef LV_FS_STDIO_PATH
# ifndef WIN32
# define LV_FS_STDIO_PATH "./" /*Project root*/
# else
# define LV_FS_STDIO_PATH ".\\" /*Project root*/
# endif
#endif /*LV_FS_STDIO_PATH*/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void * fs_open (lv_fs_drv_t * drv, const char * path, lv_fs_mode_t mode);
static lv_fs_res_t fs_close (lv_fs_drv_t * drv, void * file_p);
static lv_fs_res_t fs_read (lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br);
static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw);
static lv_fs_res_t fs_seek (lv_fs_drv_t * drv, void * file_p, uint32_t pos, lv_fs_whence_t whence);
static lv_fs_res_t fs_tell (lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p);
static void * fs_dir_open (lv_fs_drv_t * drv, const char *path);
static lv_fs_res_t fs_dir_read (lv_fs_drv_t * drv, void * dir_p, char *fn);
static lv_fs_res_t fs_dir_close (lv_fs_drv_t * drv, void * dir_p);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Register a driver for the File system interface
*/
void lv_fs_stdio_init(void)
{
/*---------------------------------------------------
* Register the file system interface in LittlevGL
*--------------------------------------------------*/
/* Add a simple drive to open images */
static lv_fs_drv_t fs_drv; /*A driver descriptor*/
lv_fs_drv_init(&fs_drv);
/*Set up fields...*/
fs_drv.letter = LV_USE_FS_STDIO;
fs_drv.open_cb = fs_open;
fs_drv.close_cb = fs_close;
fs_drv.read_cb = fs_read;
fs_drv.write_cb = fs_write;
fs_drv.seek_cb = fs_seek;
fs_drv.tell_cb = fs_tell;
fs_drv.dir_close_cb = fs_dir_close;
fs_drv.dir_open_cb = fs_dir_open;
fs_drv.dir_read_cb = fs_dir_read;
lv_fs_drv_register(&fs_drv);
char cur_path[512];
getcwd(cur_path, sizeof(cur_path));
LV_LOG_INFO("STDIO file system is initialized with %s root directory.", cur_path);
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Open a file
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable
* @param path path to the file beginning with the driver letter (e.g. S:/folder/file.txt)
* @param mode read: FS_MODE_RD, write: FS_MODE_WR, both: FS_MODE_RD | FS_MODE_WR
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static void * fs_open (lv_fs_drv_t * drv, const char * path, lv_fs_mode_t mode)
{
(void) drv; /*Unused*/
errno = 0;
const char * flags = "";
if(mode == LV_FS_MODE_WR) flags = "wb";
else if(mode == LV_FS_MODE_RD) flags = "rb";
else if(mode == (LV_FS_MODE_WR | LV_FS_MODE_RD)) flags = "rb+";
/*Make the path relative to the current directory (the projects root folder)*/
#ifndef WIN32
char buf[256];
sprintf(buf, LV_FS_STDIO_PATH "%s", path);
#else
char buf[256];
sprintf(buf, LV_FS_STDIO_PATH "%s", path);
#endif
FILE * f = fopen(buf, flags);
if(f == NULL) return NULL;
/*Be sure we are the beginning of the file*/
fseek(f, 0, SEEK_SET);
return f;
}
/**
* Close an opened file
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable. (opened with lv_ufs_open)
* @return LV_FS_RES_OK: no error, the file is read
* any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_close (lv_fs_drv_t * drv, void * file_p)
{
(void) drv; /*Unused*/
fclose(file_p);
return LV_FS_RES_OK;
}
/**
* Read data from an opened file
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable.
* @param buf pointer to a memory block where to store the read data
* @param btr number of Bytes To Read
* @param br the real number of read bytes (Byte Read)
* @return LV_FS_RES_OK: no error, the file is read
* any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_read (lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br)
{
(void) drv; /*Unused*/
*br = fread(buf, 1, btr, file_p);
return LV_FS_RES_OK;
}
/**
* Write into a file
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable
* @param buf pointer to a buffer with the bytes to write
* @param btr Bytes To Write
* @param br the number of real written bytes (Bytes Written). NULL if unused.
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw)
{
(void) drv; /*Unused*/
*bw = fwrite(buf, 1, btw, file_p);
return LV_FS_RES_OK;
}
/**
* Set the read write pointer. Also expand the file size if necessary.
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable. (opened with lv_ufs_open )
* @param pos the new position of read write pointer
* @return LV_FS_RES_OK: no error, the file is read
* any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_seek (lv_fs_drv_t * drv, void * file_p, uint32_t pos, lv_fs_whence_t whence)
{
(void) drv; /*Unused*/
fseek(file_p, pos, whence);
return LV_FS_RES_OK;
}
/**
* Give the position of the read write pointer
* @param drv pointer to a driver where this function belongs
* @param file_p pointer to a file_t variable.
* @param pos_p pointer to to store the result
* @return LV_FS_RES_OK: no error, the file is read
* any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_tell (lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p)
{
(void) drv; /*Unused*/
*pos_p = ftell(file_p);
return LV_FS_RES_OK;
}
#ifdef WIN32
static char next_fn[256];
#endif
/**
* Initialize a 'fs_read_dir_t' variable for directory reading
* @param drv pointer to a driver where this function belongs
* @param dir_p pointer to a 'fs_read_dir_t' variable
* @param path path to a directory
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static void * fs_dir_open (lv_fs_drv_t * drv, const char *path)
{
(void) drv; /*Unused*/
#ifndef WIN32
/*Make the path relative to the current directory (the projects root folder)*/
char buf[256];
sprintf(buf, LV_FS_STDIO_PATH "/%s", path);
return opendir(buf);
#else
HANDLE d = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA fdata;
/*Make the path relative to the current directory (the projects root folder)*/
char buf[256];
sprintf(buf, LV_FS_PC_PATH "\\%s\\*", path);
strcpy(next_fn, "");
d = FindFirstFile(buf, &fdata);
do {
if (strcmp(fdata.cFileName, ".") == 0 || strcmp(fdata.cFileName, "..") == 0) {
continue;
} else {
if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
sprintf(next_fn, "/%s", fdata.cFileName);
} else {
sprintf(next_fn, "%s", fdata.cFileName);
}
break;
}
} while(FindNextFileA(d, &fdata));
return d;
#endif
}
/**
* Read the next filename form a directory.
* The name of the directories will begin with '/'
* @param drv pointer to a driver where this function belongs
* @param dir_p pointer to an initialized 'fs_read_dir_t' variable
* @param fn pointer to a buffer to store the filename
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_dir_read (lv_fs_drv_t * drv, void * dir_p, char *fn)
{
(void) drv; /*Unused*/
#ifndef WIN32
struct dirent *entry;
do {
entry = readdir(dir_p);
if(entry) {
if(entry->d_type == DT_DIR) sprintf(fn, "/%s", entry->d_name);
else strcpy(fn, entry->d_name);
} else {
strcpy(fn, "");
}
} while(strcmp(fn, "/.") == 0 || strcmp(fn, "/..") == 0);
#else
strcpy(fn, next_fn);
strcpy(next_fn, "");
WIN32_FIND_DATA fdata;
if(FindNextFile(dir_p, &fdata) == false) return LV_FS_RES_OK;
do {
if (strcmp(fdata.cFileName, ".") == 0 || strcmp(fdata.cFileName, "..") == 0) {
continue;
} else {
if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
sprintf(next_fn, "/%s", fdata.cFileName);
} else {
sprintf(next_fn, "%s", fdata.cFileName);
}
break;
}
} while(FindNextFile(dir_p, &fdata));
#endif
return LV_FS_RES_OK;
}
/**
* Close the directory reading
* @param drv pointer to a driver where this function belongs
* @param dir_p pointer to an initialized 'fs_read_dir_t' variable
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/
static lv_fs_res_t fs_dir_close (lv_fs_drv_t * drv, void * dir_p)
{
(void) drv; /*Unused*/
#ifndef WIN32
closedir(dir_p);
#else
FindClose(dir_p);
#endif
return LV_FS_RES_OK;
}
#endif /*LV_FS_FATFS*/

649
src/extra/libs/gif/gifdec.c Normal file
View File

@@ -0,0 +1,649 @@
#include "gifdec.h"
#include "../../../misc/lv_log.h"
#include "../../../misc/lv_mem.h"
#if LV_USE_GIF
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define MIN(A, B) ((A) < (B) ? (A) : (B))
#define MAX(A, B) ((A) > (B) ? (A) : (B))
typedef struct Entry {
uint16_t length;
uint16_t prefix;
uint8_t suffix;
} Entry;
typedef struct Table {
int bulk;
int nentries;
Entry *entries;
} Table;
static gd_GIF * gif_open(gd_GIF * gif);
static bool f_gif_open(gd_GIF * gif, const void * path, bool is_file);
static void f_gif_read(gd_GIF * gif, void * buf, size_t len);
static int f_gif_seek(gd_GIF * gif, size_t pos, int k);
static void f_gif_close(gd_GIF * gif);
static uint16_t
read_num(gd_GIF * gif)
{
uint8_t bytes[2];
f_gif_read(gif, bytes, 2);
return bytes[0] + (((uint16_t) bytes[1]) << 8);
}
gd_GIF *
gd_open_gif_file(const char *fname)
{
gd_GIF gif_base;
memset(&gif_base, 0, sizeof(gif_base));
bool res = f_gif_open(&gif_base, fname, true);
if(!res) return NULL;
return gif_open(&gif_base);
}
gd_GIF *
gd_open_gif_data(const void *data)
{
gd_GIF gif_base;
memset(&gif_base, 0, sizeof(gif_base));
bool res = f_gif_open(&gif_base, data, false);
if(!res) return NULL;
return gif_open(&gif_base);
}
static gd_GIF * gif_open(gd_GIF * gif_base)
{
uint8_t sigver[3];
uint16_t width, height, depth;
uint8_t fdsz, bgidx, aspect;
int i;
uint8_t *bgcolor;
int gct_sz;
gd_GIF *gif;
/* Header */
f_gif_read(gif_base, sigver, 3);
if (memcmp(sigver, "GIF", 3) != 0) {
fprintf(stderr, "invalid signature\n");
goto fail;
}
/* Version */
f_gif_read(gif_base, sigver, 3);
if (memcmp(sigver, "89a", 3) != 0) {
LV_LOG_WARN("invalid version\n");
goto fail;
}
/* Width x Height */
width = read_num(gif_base);
height = read_num(gif_base);
/* FDSZ */
f_gif_read(gif_base, &fdsz, 1);
/* Presence of GCT */
if (!(fdsz & 0x80)) {
LV_LOG_WARN("no global color table\n");
goto fail;
}
/* Color Space's Depth */
depth = ((fdsz >> 4) & 7) + 1;
/* Ignore Sort Flag. */
/* GCT Size */
gct_sz = 1 << ((fdsz & 0x07) + 1);
/* Background Color Index */
f_gif_read(gif_base, &bgidx, 1);
/* Aspect Ratio */
f_gif_read(gif_base, &aspect, 1);
/* Create gd_GIF Structure. */
#if LV_COLOR_DEPTH == 32
gif = lv_mem_alloc(sizeof(gd_GIF) + 5 * width * height);
#elif LV_COLOR_DEPTH == 16
gif = lv_mem_alloc(sizeof(gd_GIF) + 4 * width * height);
#elif LV_COLOR_DEPTH == 8
gif = lv_mem_alloc(sizeof(gd_GIF) + 3 * width * height);
#endif
if (!gif) goto fail;
memcpy(gif, gif_base, sizeof(gd_GIF));
gif->width = width;
gif->height = height;
gif->depth = depth;
/* Read GCT */
gif->gct.size = gct_sz;
f_gif_read(gif, gif->gct.colors, 3 * gif->gct.size);
gif->palette = &gif->gct;
gif->bgindex = bgidx;
gif->canvas = (uint8_t *) &gif[1];
#if LV_COLOR_DEPTH == 32
gif->frame = &gif->canvas[4 * width * height];
#elif LV_COLOR_DEPTH == 16
gif->frame = &gif->canvas[3 * width * height];
#elif LV_COLOR_DEPTH == 8
gif->frame = &gif->canvas[2 * width * height];
#endif
if (gif->bgindex)
memset(gif->frame, gif->bgindex, gif->width * gif->height);
bgcolor = &gif->palette->colors[gif->bgindex*3];
if (bgcolor[0] || bgcolor[1] || bgcolor [2])
for (i = 0; i < gif->width * gif->height; i++) {
#if LV_COLOR_DEPTH == 32
gif->canvas[i*4 + 0] = *(bgcolor + 2);
gif->canvas[i*4 + 1] = *(bgcolor + 1);
gif->canvas[i*4 + 2] = *(bgcolor + 0);
gif->canvas[i*4 + 3] = 0xff;
#elif LV_COLOR_DEPTH == 16
lv_color_t c = lv_color_make(*(bgcolor + 0), *(bgcolor + 1), *(bgcolor + 2));
gif->canvas[i*3 + 0] = c.full & 0xff;
gif->canvas[i*3 + 1] = (c.full >> 8) & 0xff;
gif->canvas[i*3 + 2] = 0xff;
#elif LV_COLOR_DEPTH == 8
lv_color_t c = lv_color_make(*(bgcolor + 0), *(bgcolor + 1), *(bgcolor + 2));
gif->canvas[i*2 + 0] = c.full;
gif->canvas[i*2 + 1] = 0xff;
#endif
}
gif->anim_start = f_gif_seek(gif, 0, SEEK_CUR);
goto ok;
fail:
f_gif_close(gif_base);
ok:
return gif;
}
static void
discard_sub_blocks(gd_GIF *gif)
{
uint8_t size;
do {
f_gif_read(gif, &size, 1);
f_gif_seek(gif, size, SEEK_CUR);
} while (size);
}
static void
read_plain_text_ext(gd_GIF *gif)
{
if (gif->plain_text) {
uint16_t tx, ty, tw, th;
uint8_t cw, ch, fg, bg;
off_t sub_block;
f_gif_seek(gif, 1, SEEK_CUR); /* block size = 12 */
tx = read_num(gif);
ty = read_num(gif);
tw = read_num(gif);
th = read_num(gif);
f_gif_read(gif, &cw, 1);
f_gif_read(gif, &ch, 1);
f_gif_read(gif, &fg, 1);
f_gif_read(gif, &bg, 1);
sub_block = f_gif_seek(gif, 0, SEEK_CUR);
gif->plain_text(gif, tx, ty, tw, th, cw, ch, fg, bg);
f_gif_seek(gif, sub_block, SEEK_SET);
} else {
/* Discard plain text metadata. */
f_gif_seek(gif, 13, SEEK_CUR);
}
/* Discard plain text sub-blocks. */
discard_sub_blocks(gif);
}
static void
read_graphic_control_ext(gd_GIF *gif)
{
uint8_t rdit;
/* Discard block size (always 0x04). */
f_gif_seek(gif, 1, SEEK_CUR);
f_gif_read(gif, &rdit, 1);
gif->gce.disposal = (rdit >> 2) & 3;
gif->gce.input = rdit & 2;
gif->gce.transparency = rdit & 1;
gif->gce.delay = read_num(gif);
f_gif_read(gif, &gif->gce.tindex, 1);
/* Skip block terminator. */
f_gif_seek(gif, 1, SEEK_CUR);
}
static void
read_comment_ext(gd_GIF *gif)
{
if (gif->comment) {
off_t sub_block = f_gif_seek(gif, 0, SEEK_CUR);
gif->comment(gif);
f_gif_seek(gif, sub_block, SEEK_SET);
}
/* Discard comment sub-blocks. */
discard_sub_blocks(gif);
}
static void
read_application_ext(gd_GIF *gif)
{
char app_id[8];
char app_auth_code[3];
/* Discard block size (always 0x0B). */
f_gif_seek(gif, 1, SEEK_CUR);
/* Application Identifier. */
f_gif_read(gif, app_id, 8);
/* Application Authentication Code. */
f_gif_read(gif, app_auth_code, 3);
if (!strncmp(app_id, "NETSCAPE", sizeof(app_id))) {
/* Discard block size (0x03) and constant byte (0x01). */
f_gif_seek(gif, 2, SEEK_CUR);
gif->loop_count = read_num(gif);
/* Skip block terminator. */
f_gif_seek(gif, 1, SEEK_CUR);
} else if (gif->application) {
off_t sub_block = f_gif_seek(gif, 0, SEEK_CUR);
gif->application(gif, app_id, app_auth_code);
f_gif_seek(gif, sub_block, SEEK_SET);
discard_sub_blocks(gif);
} else {
discard_sub_blocks(gif);
}
}
static void
read_ext(gd_GIF *gif)
{
uint8_t label;
f_gif_read(gif, &label, 1);
switch (label) {
case 0x01:
read_plain_text_ext(gif);
break;
case 0xF9:
read_graphic_control_ext(gif);
break;
case 0xFE:
read_comment_ext(gif);
break;
case 0xFF:
read_application_ext(gif);
break;
default:
LV_LOG_WARN("unknown extension: %02X\n", label);
}
}
static Table *
new_table(int key_size)
{
int key;
int init_bulk = MAX(1 << (key_size + 1), 0x100);
Table *table = lv_mem_alloc(sizeof(*table) + sizeof(Entry) * init_bulk);
if (table) {
table->bulk = init_bulk;
table->nentries = (1 << key_size) + 2;
table->entries = (Entry *) &table[1];
for (key = 0; key < (1 << key_size); key++)
table->entries[key] = (Entry) {1, 0xFFF, key};
}
return table;
}
/* Add table entry. Return value:
* 0 on success
* +1 if key size must be incremented after this addition
* -1 if could not realloc table */
static int
add_entry(Table **tablep, uint16_t length, uint16_t prefix, uint8_t suffix)
{
Table *table = *tablep;
if (table->nentries == table->bulk) {
table->bulk *= 2;
table = lv_mem_realloc(table, sizeof(*table) + sizeof(Entry) * table->bulk);
if (!table) return -1;
table->entries = (Entry *) &table[1];
*tablep = table;
}
table->entries[table->nentries] = (Entry) {length, prefix, suffix};
table->nentries++;
if ((table->nentries & (table->nentries - 1)) == 0)
return 1;
return 0;
}
static uint16_t
get_key(gd_GIF *gif, int key_size, uint8_t *sub_len, uint8_t *shift, uint8_t *byte)
{
int bits_read;
int rpad;
int frag_size;
uint16_t key;
key = 0;
for (bits_read = 0; bits_read < key_size; bits_read += frag_size) {
rpad = (*shift + bits_read) % 8;
if (rpad == 0) {
/* Update byte. */
if (*sub_len == 0) {
f_gif_read(gif, sub_len, 1); /* Must be nonzero! */
if (*sub_len == 0) return 0x1000;
}
f_gif_read(gif, byte, 1);
(*sub_len)--;
}
frag_size = MIN(key_size - bits_read, 8 - rpad);
key |= ((uint16_t) ((*byte) >> rpad)) << bits_read;
}
/* Clear extra bits to the left. */
key &= (1 << key_size) - 1;
*shift = (*shift + key_size) % 8;
return key;
}
/* Compute output index of y-th input line, in frame of height h. */
static int
interlaced_line_index(int h, int y)
{
int p; /* number of lines in current pass */
p = (h - 1) / 8 + 1;
if (y < p) /* pass 1 */
return y * 8;
y -= p;
p = (h - 5) / 8 + 1;
if (y < p) /* pass 2 */
return y * 8 + 4;
y -= p;
p = (h - 3) / 4 + 1;
if (y < p) /* pass 3 */
return y * 4 + 2;
y -= p;
/* pass 4 */
return y * 2 + 1;
}
/* Decompress image pixels.
* Return 0 on success or -1 on out-of-memory (w.r.t. LZW code table). */
static int
read_image_data(gd_GIF *gif, int interlace)
{
uint8_t sub_len, shift, byte;
int init_key_size, key_size, table_is_full;
int frm_off, frm_size, str_len, i, p, x, y;
uint16_t key, clear, stop;
int ret;
Table *table;
Entry entry;
off_t start, end;
f_gif_read(gif, &byte, 1);
key_size = (int) byte;
start = f_gif_seek(gif, 0, SEEK_CUR);
discard_sub_blocks(gif);
end = f_gif_seek(gif, 0, SEEK_CUR);
f_gif_seek(gif, start, SEEK_SET);
clear = 1 << key_size;
stop = clear + 1;
table = new_table(key_size);
key_size++;
init_key_size = key_size;
sub_len = shift = 0;
key = get_key(gif, key_size, &sub_len, &shift, &byte); /* clear code */
frm_off = 0;
ret = 0;
frm_size = gif->fw*gif->fh;
while (frm_off < frm_size) {
if (key == clear) {
key_size = init_key_size;
table->nentries = (1 << (key_size - 1)) + 2;
table_is_full = 0;
} else if (!table_is_full) {
ret = add_entry(&table, str_len + 1, key, entry.suffix);
if (ret == -1) {
lv_mem_free(table);
return -1;
}
if (table->nentries == 0x1000) {
ret = 0;
table_is_full = 1;
}
}
key = get_key(gif, key_size, &sub_len, &shift, &byte);
if (key == clear) continue;
if (key == stop || key == 0x1000) break;
if (ret == 1) key_size++;
entry = table->entries[key];
str_len = entry.length;
for (i = 0; i < str_len; i++) {
p = frm_off + entry.length - 1;
x = p % gif->fw;
y = p / gif->fw;
if (interlace)
y = interlaced_line_index((int) gif->fh, y);
gif->frame[(gif->fy + y) * gif->width + gif->fx + x] = entry.suffix;
if (entry.prefix == 0xFFF)
break;
else
entry = table->entries[entry.prefix];
}
frm_off += str_len;
if (key < table->nentries - 1 && !table_is_full)
table->entries[table->nentries - 1].suffix = entry.suffix;
}
lv_mem_free(table);
if (key == stop) f_gif_read(gif, &sub_len, 1); /* Must be zero! */
f_gif_seek(gif, end, SEEK_SET);
return 0;
}
/* Read image.
* Return 0 on success or -1 on out-of-memory (w.r.t. LZW code table). */
static int
read_image(gd_GIF *gif)
{
uint8_t fisrz;
int interlace;
/* Image Descriptor. */
gif->fx = read_num(gif);
gif->fy = read_num(gif);
gif->fw = read_num(gif);
gif->fh = read_num(gif);
f_gif_read(gif, &fisrz, 1);
interlace = fisrz & 0x40;
/* Ignore Sort Flag. */
/* Local Color Table? */
if (fisrz & 0x80) {
/* Read LCT */
gif->lct.size = 1 << ((fisrz & 0x07) + 1);
f_gif_read(gif, gif->lct.colors, 3 * gif->lct.size);
gif->palette = &gif->lct;
} else
gif->palette = &gif->gct;
/* Image Data. */
return read_image_data(gif, interlace);
}
static void
render_frame_rect(gd_GIF *gif, uint8_t *buffer)
{
int i, j, k;
uint8_t index, *color;
i = gif->fy * gif->width + gif->fx;
for (j = 0; j < gif->fh; j++) {
for (k = 0; k < gif->fw; k++) {
index = gif->frame[(gif->fy + j) * gif->width + gif->fx + k];
color = &gif->palette->colors[index*3];
if (!gif->gce.transparency || index != gif->gce.tindex) {
#if LV_COLOR_DEPTH == 32
buffer[(i+k)*4 + 0] = *(color + 2);
buffer[(i+k)*4 + 1] = *(color + 1);
buffer[(i+k)*4 + 2] = *(color + 0);
buffer[(i+k)*4 + 3] = 0xFF;
#elif LV_COLOR_DEPTH == 16
lv_color_t c = lv_color_make(*(color + 0), *(color + 1), *(color + 2));
buffer[(i+k)*3 + 0] = c.full & 0xff;
buffer[(i+k)*3 + 1] = (c.full >> 8) & 0xff;
buffer[(i+k)*3 + 2] = 0xff;
#elif LV_COLOR_DEPTH == 8
lv_color_t c = lv_color_make(*(color + 0), *(color + 1), *(color + 2));
buffer[(i+k)*2 + 0] = c.full;
buffer[(i+k)*2 + 1] = 0xff;
#endif
}
}
i += gif->width;
}
}
static void
dispose(gd_GIF *gif)
{
int i, j, k;
uint8_t *bgcolor;
switch (gif->gce.disposal) {
case 2: /* Restore to background color. */
bgcolor = &gif->palette->colors[gif->bgindex*3];
uint8_t opa = 0xff;
if(gif->gce.transparency) opa = 0x00;
i = gif->fy * gif->width + gif->fx;
for (j = 0; j < gif->fh; j++) {
for (k = 0; k < gif->fw; k++) {
#if LV_COLOR_DEPTH == 32
gif->canvas[(i+k)*4 + 0] = *(bgcolor + 2);
gif->canvas[(i+k)*4 + 1] = *(bgcolor + 1);
gif->canvas[(i+k)*4 + 2] = *(bgcolor + 0);
gif->canvas[(i+k)*4 + 3] = opa;
#elif LV_COLOR_DEPTH == 16
lv_color_t c = lv_color_make(*(bgcolor + 0), *(bgcolor + 1), *(bgcolor + 2));
gif->canvas[(i+k)*3 + 0] = c.full & 0xff;
gif->canvas[(i+k)*3 + 1] = (c.full >> 8) & 0xff;
gif->canvas[(i+k)*3 + 2] = opa;
#elif LV_COLOR_DEPTH == 8
lv_color_t c = lv_color_make(*(bgcolor + 0), *(bgcolor + 1), *(bgcolor + 2));
gif->canvas[(i+k)*2 + 0] = c.full;
gif->canvas[(i+k)*2 + 1] = opa;
#endif
}
i += gif->width;
}
break;
case 3: /* Restore to previous, i.e., don't update canvas.*/
break;
default:
/* Add frame non-transparent pixels to canvas. */
render_frame_rect(gif, gif->canvas);
}
}
/* Return 1 if got a frame; 0 if got GIF trailer; -1 if error. */
int
gd_get_frame(gd_GIF *gif)
{
char sep;
dispose(gif);
f_gif_read(gif, &sep, 1);
while (sep != ',') {
if (sep == ';')
return 0;
if (sep == '!')
read_ext(gif);
else return -1;
f_gif_read(gif, &sep, 1);
}
if (read_image(gif) == -1)
return -1;
return 1;
}
void
gd_render_frame(gd_GIF *gif, uint8_t *buffer)
{
// uint32_t i;
// uint32_t j;
// for(i = 0, j = 0; i < gif->width * gif->height * 3; i+= 3, j+=4) {
// buffer[j + 0] = gif->canvas[i + 2];
// buffer[j + 1] = gif->canvas[i + 1];
// buffer[j + 2] = gif->canvas[i + 0];
// buffer[j + 3] = 0xFF;
// }
// memcpy(buffer, gif->canvas, gif->width * gif->height * 3);
render_frame_rect(gif, buffer);
}
void
gd_rewind(gd_GIF *gif)
{
f_gif_seek(gif, gif->anim_start, SEEK_SET);
}
void
gd_close_gif(gd_GIF *gif)
{
f_gif_close(gif);
lv_mem_free(gif);
}
static bool f_gif_open(gd_GIF * gif, const void * path, bool is_file)
{
gif->f_rw_p = 0;
gif->data = NULL;
gif->is_file = is_file;
if(is_file) {
lv_fs_res_t res = lv_fs_open(&gif->fd, path, LV_FS_MODE_RD);
if(res != LV_FS_RES_OK) return false;
else return true;
} else {
gif->data = path;
return true;
}
}
static void f_gif_read(gd_GIF * gif, void * buf, size_t len)
{
if(gif->is_file) {
lv_fs_read(&gif->fd, buf, len, NULL);
} else
{
memcpy(buf, &gif->data[gif->f_rw_p], len);
gif->f_rw_p += len;
}
}
static int f_gif_seek(gd_GIF * gif, size_t pos, int k)
{
if(k == SEEK_CUR) k = LV_FS_SEEK_CUR;
else if(k == SEEK_SET) k = LV_FS_SEEK_SET;
if(gif->is_file) {
lv_fs_seek(&gif->fd, pos, k);
uint32_t x;
lv_fs_tell(&gif->fd, &x);
return x;
} else {
if(k == LV_FS_SEEK_CUR) gif->f_rw_p += pos;
else if(k == LV_FS_SEEK_SET) gif->f_rw_p = pos;
return gif->f_rw_p;
}
}
static void f_gif_close(gd_GIF * gif)
{
if(gif->is_file) {
lv_fs_close(&gif->fd);
}
}
#endif /*LV_USE_GIF*/

View File

@@ -0,0 +1,60 @@
#ifndef GIFDEC_H
#define GIFDEC_H
#include <stdint.h>
#include "../../../misc/lv_fs.h"
#if LV_USE_GIF
typedef struct gd_Palette {
int size;
uint8_t colors[0x100 * 3];
} gd_Palette;
typedef struct gd_GCE {
uint16_t delay;
uint8_t tindex;
uint8_t disposal;
int input;
int transparency;
} gd_GCE;
typedef struct gd_GIF {
lv_fs_file_t fd;
const char * data;
uint8_t is_file;
uint32_t f_rw_p;
int32_t anim_start;
uint16_t width, height;
uint16_t depth;
uint16_t loop_count;
gd_GCE gce;
gd_Palette *palette;
gd_Palette lct, gct;
void (*plain_text)(
struct gd_GIF *gif, uint16_t tx, uint16_t ty,
uint16_t tw, uint16_t th, uint8_t cw, uint8_t ch,
uint8_t fg, uint8_t bg
);
void (*comment)(struct gd_GIF *gif);
void (*application)(struct gd_GIF *gif, char id[8], char auth[3]);
uint16_t fx, fy, fw, fh;
uint8_t bgindex;
uint8_t *canvas, *frame;
} gd_GIF;
gd_GIF * gd_open_gif_file(const char *fname);
gd_GIF * gd_open_gif_data(const void *data);
void gd_render_frame(gd_GIF *gif, uint8_t *buffer);
int gd_get_frame(gd_GIF *gif);
void gd_rewind(gd_GIF *gif);
void gd_close_gif(gd_GIF *gif);
#endif /*LV_USE_GIF*/
#endif /* GIFDEC_H */

154
src/extra/libs/gif/lv_gif.c Normal file
View File

@@ -0,0 +1,154 @@
/**
* @file lv_gifenc.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_gif.h"
#if LV_USE_GIF
#include "gifdec.h"
/*********************
* DEFINES
*********************/
#define MY_CLASS &lv_gif_class
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void lv_gif_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
static void lv_gif_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
static void next_frame_task_cb(lv_timer_t * t);
/**********************
* STATIC VARIABLES
**********************/
const lv_obj_class_t lv_gif_class = {
.constructor_cb = lv_gif_constructor,
.destructor_cb = lv_gif_destructor,
.instance_size = sizeof(lv_gif_t),
.base_class = &lv_img_class
};
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_obj_t * lv_gif_create(lv_obj_t * parent)
{
LV_LOG_INFO("begin");
lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
lv_obj_class_init_obj(obj);
return obj;
}
void lv_gif_set_src(lv_obj_t * obj, const void * src)
{
lv_gif_t * gifobj = (lv_gif_t *) obj;
/*Close previous gif if any*/
if(gifobj->gif) {
lv_img_cache_invalidate_src(&gifobj->imgdsc);
gd_close_gif(gifobj->gif);
gifobj->gif = NULL;
gifobj->imgdsc.data = NULL;
}
if(lv_img_src_get_type(src) == LV_IMG_SRC_VARIABLE) {
const lv_img_dsc_t * img_dsc = src;
gifobj->gif = gd_open_gif_data(img_dsc->data);
}
else if(lv_img_src_get_type(src) == LV_IMG_SRC_FILE) {
gifobj->gif = gd_open_gif_file(src);
}
if(gifobj->gif == NULL) {
LV_LOG_WARN("Could't load the source");
return;
}
gifobj->imgdsc.data = gifobj->gif->canvas;
gifobj->imgdsc.header.always_zero = 0;
gifobj->imgdsc.header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA;
gifobj->imgdsc.header.h = gifobj->gif->height;
gifobj->imgdsc.header.w = gifobj->gif->width;
gifobj->last_call = lv_tick_get();
lv_img_set_src(obj, &gifobj->imgdsc);
lv_timer_resume(gifobj->timer);
lv_timer_reset(gifobj->timer);
next_frame_task_cb(gifobj->timer);
}
void lv_gif_restart(lv_obj_t * obj)
{
lv_gif_t * gifobj = (lv_gif_t *) obj;
gd_rewind(gifobj->gif);
}
/**********************
* STATIC FUNCTIONS
**********************/
static void lv_gif_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
{
LV_UNUSED(class_p);
lv_gif_t * gifobj = (lv_gif_t *) obj;
gifobj->timer = lv_timer_create(next_frame_task_cb, 10, obj);
lv_timer_pause(gifobj->timer);
}
static void lv_gif_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
{
LV_UNUSED(class_p);
lv_gif_t * gifobj = (lv_gif_t *) obj;
lv_img_cache_invalidate_src(&gifobj->imgdsc);
gd_close_gif(gifobj->gif);
lv_timer_del(gifobj->timer);
}
static void next_frame_task_cb(lv_timer_t * t)
{
lv_obj_t * obj = t->user_data;
lv_gif_t * gifobj = (lv_gif_t *) obj;
uint32_t elaps = lv_tick_elaps(gifobj->last_call);
if(elaps < gifobj->gif->gce.delay * 10) return;
gifobj->last_call = lv_tick_get();
int has_next = gd_get_frame(gifobj->gif);
if(has_next == 0) {
/*It was the last repeat*/
if(gifobj->gif->loop_count == 1) {
lv_res_t res = lv_event_send(obj, LV_EVENT_READY, NULL);
if(res != LV_FS_RES_OK) return;
} else {
if(gifobj->gif->loop_count > 1) gifobj->gif->loop_count--;
gd_rewind(gifobj->gif);
}
}
gd_render_frame(gifobj->gif, gifobj->imgdsc.data);
lv_img_cache_invalidate_src(lv_img_get_src(obj));
lv_obj_invalidate(obj);
}
#endif /*LV_USE_GIF*/

View File

@@ -0,0 +1,58 @@
/**
* @file lv_gif.h
*
*/
#ifndef LV_GIF_H
#define LV_GIF_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../../lvgl.h"
#if LV_USE_GIF
#include "gifdec.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef struct {
lv_img_t img;
gd_GIF *gif;
lv_timer_t * timer;
lv_img_dsc_t imgdsc;
uint32_t last_call;
}lv_gif_t;
extern const lv_obj_class_t lv_gif_class;
/**********************
* GLOBAL PROTOTYPES
**********************/
lv_obj_t * lv_gif_create(lv_obj_t * parent);
void lv_gif_set_src(lv_obj_t * obj, const void * src);
void lv_gif_restart(lv_obj_t * gif);
/**********************
* MACROS
**********************/
#endif /*LV_USE_GIF*/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*LV_GIF_H*/

49
src/extra/libs/lv_libs.h Normal file
View File

@@ -0,0 +1,49 @@
/**
* @file lv_libs.h
*
*/
#ifndef LV_LIBS_H
#define LV_LIBS_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "bmp/lv_bmp.h"
#include "fs/lv_fs_libs.h"
#include "png/lv_png.h"
#include "gif/lv_gif.h"
#include "qrcode/lv_qrcode.h"
#include "sjpg/lv_sjpg.h"
#include "freetype/lv_freetype.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**********************
* MACROS
**********************/
#if LV_USE_LOG && LV_LOG_TRACE_LAYOUT
# define LV_TRACE_LAYOUT(...) LV_LOG_TRACE( __VA_ARGS__)
#else
# define LV_TRACE_LAYOUT(...)
#endif
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_LAYOUTS_H*/

6466
src/extra/libs/png/lodepng.c Normal file

File diff suppressed because it is too large Load Diff

1981
src/extra/libs/png/lodepng.h Normal file

File diff suppressed because it is too large Load Diff

237
src/extra/libs/png/lv_png.c Normal file
View File

@@ -0,0 +1,237 @@
/**
* @file lv_png.c
*
*/
/*********************
* INCLUDES
*********************/
#include "../../../lvgl.h"
#if LV_USE_PNG
#include "lv_png.h"
#include "lodepng.h"
#include <stdlib.h>
#include <stdio.h>
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static lv_res_t decoder_info(struct _lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header);
static lv_res_t decoder_open(lv_img_decoder_t * dec, lv_img_decoder_dsc_t * dsc);
static void decoder_close(lv_img_decoder_t * dec, lv_img_decoder_dsc_t * dsc);
static void convert_color_depth(uint8_t * img, uint32_t px_cnt);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Register the PNG decoder functions in LittlevGL
*/
void lv_png_init(void)
{
lv_img_decoder_t * dec = lv_img_decoder_create();
lv_img_decoder_set_info_cb(dec, decoder_info);
lv_img_decoder_set_open_cb(dec, decoder_open);
lv_img_decoder_set_close_cb(dec, decoder_close);
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Get info about a PNG image
* @param src can be file name or pointer to a C array
* @param header store the info here
* @return LV_RES_OK: no error; LV_RES_INV: can't get the info
*/
static lv_res_t decoder_info(struct _lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header)
{
(void) decoder; /*Unused*/
lv_img_src_t src_type = lv_img_src_get_type(src); /*Get the source type*/
/*If it's a PNG file...*/
if(src_type == LV_IMG_SRC_FILE) {
const char * fn = src;
if(!strcmp(&fn[strlen(fn) - 3], "png")) { /*Check the extension*/
/* Read the width and height from the file. They have a constant location:
* [16..23]: width
* [24..27]: height
*/
uint32_t size[2];
lv_fs_file_t f;
lv_fs_res_t res = lv_fs_open(&f, fn, LV_FS_MODE_RD);
if(res != LV_FS_RES_OK) return LV_RES_INV;
lv_fs_seek(&f, 16, LV_FS_SEEK_SET);
uint32_t rn;
lv_fs_read(&f, &size, 8, &rn);
if(rn != 8) return LV_RES_INV;
lv_fs_close(&f);
/*Save the data in the header*/
header->always_zero = 0;
header->cf = LV_IMG_CF_RAW_ALPHA;
/*The width and height are stored in Big endian format so convert them to little endian*/
header->w = (lv_coord_t) ((size[0] & 0xff000000) >> 24) + ((size[0] & 0x00ff0000) >> 8);
header->h = (lv_coord_t) ((size[1] & 0xff000000) >> 24) + ((size[1] & 0x00ff0000) >> 8);
return LV_RES_OK;
}
}
/*If it's a PNG file in a C array...*/
else if(src_type == LV_IMG_SRC_VARIABLE) {
const lv_img_dsc_t * img_dsc = src;
header->always_zero = 0;
header->cf = img_dsc->header.cf; /*Save the color format*/
header->w = img_dsc->header.w; /*Save the color width*/
header->h = img_dsc->header.h; /*Save the color height*/
return LV_RES_OK;
}
return LV_RES_INV; /*If didn't succeeded earlier then it's an error*/
}
/**
* Open a PNG image and return the decided image
* @param src can be file name or pointer to a C array
* @param style style of the image object (unused now but certain formats might use it)
* @return pointer to the decoded image or `LV_IMG_DECODER_OPEN_FAIL` if failed
*/
static lv_res_t decoder_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
{
(void) decoder; /*Unused*/
uint32_t error; /*For the return values of PNG decoder functions*/
uint8_t * img_data = NULL;
/*If it's a PNG file...*/
if(dsc->src_type == LV_IMG_SRC_FILE) {
const char * fn = dsc->src;
if(!strcmp(&fn[strlen(fn) - 3], "png")) { /*Check the extension*/
/*Load the PNG file into buffer. It's still compressed (not decoded)*/
unsigned char * png_data; /*Pointer to the loaded data. Same as the original file just loaded into the RAM*/
size_t png_data_size; /*Size of `png_data` in bytes*/
error = lodepng_load_file(&png_data, &png_data_size, fn); /*Load the file*/
if(error) {
printf("error %u: %s\n", error, lodepng_error_text(error));
return LV_RES_INV;
}
/*Decode the PNG image*/
uint32_t png_width; /*Will be the width of the decoded image*/
uint32_t png_height; /*Will be the width of the decoded image*/
/*Decode the loaded image in ARGB8888 */
error = lodepng_decode32(&img_data, &png_width, &png_height, png_data, png_data_size);
free(png_data); /*Free the loaded file*/
if(error) {
printf("error %u: %s\n", error, lodepng_error_text(error));
return LV_RES_INV;
}
/*Convert the image to the system's color depth*/
convert_color_depth(img_data, png_width * png_height);
dsc->img_data = img_data;
return LV_RES_OK; /*The image is fully decoded. Return with its pointer*/
}
}
/*If it's a PNG file in a C array...*/
else if(dsc->src_type == LV_IMG_SRC_VARIABLE) {
const lv_img_dsc_t * img_dsc = dsc->src;
uint32_t png_width; /*No used, just required by he decoder*/
uint32_t png_height; /*No used, just required by he decoder*/
/*Decode the image in ARGB8888 */
error = lodepng_decode32(&img_data, &png_width, &png_height, img_dsc->data, img_dsc->data_size);
if(error) {
return LV_RES_INV;
}
/*Convert the image to the system's color depth*/
convert_color_depth(img_data, png_width * png_height);
dsc->img_data = img_data;
return LV_RES_OK; /*Return with its pointer*/
}
return LV_RES_INV; /*If not returned earlier then it failed*/
}
/**
* Free the allocated resources
*/
static void decoder_close(lv_img_decoder_t *decoder, lv_img_decoder_dsc_t *dsc)
{
(void)decoder; /*Unused*/
if (dsc->img_data) {
free((uint8_t *)dsc->img_data);
dsc->img_data = NULL;
}
}
/**
* If the display is not in 32 bit format (ARGB888) then covert the image to the current color depth
* @param img the ARGB888 image
* @param px_cnt number of pixels in `img`
*/
static void convert_color_depth(uint8_t * img, uint32_t px_cnt)
{
#if LV_COLOR_DEPTH == 32
lv_color32_t * img_argb = (lv_color32_t*)img;
lv_color_t c;
lv_color_t * img_c = (lv_color_t *) img;
uint32_t i;
for(i = 0; i < px_cnt; i++) {
c = lv_color_make(img_argb[i].ch.red, img_argb[i].ch.green, img_argb[i].ch.blue);
img_c[i].ch.red = c.ch.blue;
img_c[i].ch.blue = c.ch.red;
}
#elif LV_COLOR_DEPTH == 16
lv_color32_t * img_argb = (lv_color32_t*)img;
lv_color_t c;
uint32_t i;
for(i = 0; i < px_cnt; i++) {
c = lv_color_make(img_argb[i].ch.blue, img_argb[i].ch.green, img_argb[i].ch.red);
img[i*3 + 2] = img_argb[i].ch.alpha;
img[i*3 + 1] = c.full >> 8;
img[i*3 + 0] = c.full & 0xFF;
}
#elif LV_COLOR_DEPTH == 8
lv_color32_t * img_argb = (lv_color32_t*)img;
lv_color_t c;
uint32_t i;
for(i = 0; i < px_cnt; i++) {
c = lv_color_make(img_argb[i].red, img_argb[i].green, img_argb[i].blue);
img[i*2 + 1] = img_argb[i].alpha;
img[i*2 + 0] = c.full
}
#endif
}
#endif /*LV_USE_PNG*/

View File

@@ -0,0 +1,46 @@
/**
* @file lv_png.h
*
*/
#ifndef LV_PNG_H
#define LV_PNG_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../../lv_conf_internal.h"
#if LV_USE_PNG
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Register the PNG decoder functions in LittlevGL
*/
void lv_png_init(void);
/**********************
* MACROS
**********************/
#endif /*LV_USE_PNG*/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*LV_PNG_H*/

View File

@@ -0,0 +1,174 @@
/**
* @file lv_qrcode.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_qrcode.h"
#if LV_USE_QRCODE
#include "qrcodegen.h"
/*********************
* DEFINES
*********************/
#define QR_SIZE 140
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Create an empty QR code (an `lv_canvas`) object.
* @param parent point to an object where to create the QR code
* @param size width and height of the QR code
* @param dark_color dark color of the QR code
* @param light_color light color of the QR code
* @return pointer to the created QR code object
*/
lv_obj_t * lv_qrcode_create(lv_obj_t * parent, lv_coord_t size, lv_color_t dark_color, lv_color_t light_color)
{
uint32_t buf_size = LV_CANVAS_BUF_SIZE_INDEXED_1BIT(size, size);
uint8_t * buf = lv_mem_alloc(buf_size);
LV_ASSERT_MALLOC(buf);
if(buf == NULL) return NULL;
lv_obj_t * canvas = lv_canvas_create(parent);
if(canvas == NULL) return NULL;
lv_canvas_set_buffer(canvas, buf, size, size, LV_IMG_CF_INDEXED_1BIT);
lv_canvas_set_palette(canvas, 0, dark_color);
lv_canvas_set_palette(canvas, 1, light_color);
return canvas;
}
/**
* Set the data of a QR code object
* @param qrcode pointer to aQ code object
* @param data data to display
* @param data_len length of data in bytes
* @return LV_RES_OK: if no error; LV_RES_INV: on error
*/
lv_res_t lv_qrcode_update(lv_obj_t * qrcode, const void * data, uint32_t data_len)
{
lv_color_t c;
c.full = 1;
lv_canvas_fill_bg(qrcode, c, LV_OPA_COVER);
if(data_len > qrcodegen_BUFFER_LEN_MAX) return LV_RES_INV;
uint8_t * qr0 = lv_mem_alloc(qrcodegen_BUFFER_LEN_MAX);
LV_ASSERT_MALLOC(qr0);
uint8_t * data_tmp = lv_mem_alloc(qrcodegen_BUFFER_LEN_MAX);
LV_ASSERT_MALLOC(data_tmp);
memcpy(data_tmp, data, data_len);
bool ok = qrcodegen_encodeBinary(data_tmp, data_len,
qr0, qrcodegen_Ecc_MEDIUM,
qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX,
qrcodegen_Mask_AUTO, true);
if (!ok) {
lv_mem_free(qr0);
lv_mem_free(data_tmp);
return LV_RES_INV;
}
lv_img_dsc_t * imgdsc = lv_canvas_get_img(qrcode);
lv_coord_t obj_w = imgdsc->header.w;
int qr_size = qrcodegen_getSize(qr0);
int scale = obj_w / qr_size;
int scaled = qr_size * scale;
int margin = (obj_w - scaled) / 2;
uint8_t * buf_u8 = (uint8_t *)imgdsc->data + 8; /*+8 skip the palette*/
/* Copy the qr code canvas:
* A simple `lv_canvas_set_px` would work but it's slow for so many pixels.
* So buffer 1 byte (8 px) from the qr code and set it in the canvas image */
uint32_t row_byte_cnt = (imgdsc->header.w + 7) >> 3;
int y;
for (y = margin; y < scaled + margin; y+=scale) {
uint8_t b = 0;
uint8_t p = 0;
bool aligned = false;
int x;
for (x = margin; x < scaled + margin; x++) {
bool a = qrcodegen_getModule(qr0, (x - margin) / scale, (y - margin) / scale);
if(aligned == false && (x & 0x7) == 0) aligned = true;
if(aligned == false) {
c.full = a ? 0 : 1;
lv_canvas_set_px(qrcode, x, y, c);
} else {
if(!a) b |= (1 << (7 - p));
p++;
if(p == 8) {
uint32_t px = row_byte_cnt * y + (x >> 3);
buf_u8[px] = b;
b = 0;
p = 0;
}
}
}
/*Process the last byte of the row*/
if(p) {
/*Make the rest of the bits white*/
b |= (1 << (8 - p)) - 1;
uint32_t px = row_byte_cnt * y + (x >> 3);
buf_u8[px] = b;
}
/*The Qr is probably scaled so simply to the repeated rows*/
int s;
const uint8_t * row_ori = buf_u8 + row_byte_cnt * y;
for(s = 1; s < scale; s++) {
memcpy((uint8_t*)buf_u8 + row_byte_cnt * (y + s), row_ori, row_byte_cnt);
}
}
lv_mem_free(qr0);
lv_mem_free(data_tmp);
return LV_RES_OK;
}
/**
* Delete a QR code object
* @param qrcode pointer to a QR code obejct
*/
void lv_qrcode_delete(lv_obj_t * qrcode)
{
lv_img_dsc_t * img = lv_canvas_get_img(qrcode);
lv_img_cache_invalidate_src(img);
lv_mem_free((void*)img->data);
lv_obj_del(qrcode);
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_QRCODE*/

View File

@@ -0,0 +1,66 @@
/**
* @file lv_qrcode
*
*/
#ifndef LV_QRCODE_H
#define LV_QRCODE_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../../lvgl.h"
#if LV_USE_QRCODE
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Create an empty QR code (an `lv_canvas`) object.
* @param parent point to an object where to create the QR code
* @param size width and height of the QR code
* @param dark_color dark color of the QR code
* @param light_color light color of the QR code
* @return pointer to the created QR code object
*/
lv_obj_t * lv_qrcode_create(lv_obj_t * parent, lv_coord_t size, lv_color_t dark_color, lv_color_t light_color);
/**
* Set the data of a QR code object
* @param qrcode pointer to aQ code object
* @param data data to display
* @param data_len length of data in bytes
* @return LV_RES_OK: if no error; LV_RES_INV: on error
*/
lv_res_t lv_qrcode_update(lv_obj_t * qrcode, const void * data, uint32_t data_len);
/**
* Delete a QR code object
* @param qrcode pointer to a QR code object
*/
void lv_qrcode_delete(lv_obj_t * qrcode);
/**********************
* MACROS
**********************/
#endif /*LV_USE_QRCODE*/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*LV_QRCODE_H*/

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,311 @@
/*
* QR Code generator library (C)
*
* Copyright (c) Project Nayuki. (MIT License)
* https://www.nayuki.io/page/qr-code-generator-library
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
* - The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* - The Software is provided "as is", without warranty of any kind, express or
* implied, including but not limited to the warranties of merchantability,
* fitness for a particular purpose and noninfringement. In no event shall the
* authors or copyright holders be liable for any claim, damages or other
* liability, whether in an action of contract, tort or otherwise, arising from,
* out of or in connection with the Software or the use or other dealings in the
* Software.
*/
#pragma once
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* This library creates QR Code symbols, which is a type of two-dimension barcode.
* Invented by Denso Wave and described in the ISO/IEC 18004 standard.
* A QR Code structure is an immutable square grid of black and white cells.
* The library provides functions to create a QR Code from text or binary data.
* The library covers the QR Code Model 2 specification, supporting all versions (sizes)
* from 1 to 40, all 4 error correction levels, and 4 character encoding modes.
*
* Ways to create a QR Code object:
* - High level: Take the payload data and call qrcodegen_encodeText() or qrcodegen_encodeBinary().
* - Low level: Custom-make the list of segments and call
* qrcodegen_encodeSegments() or qrcodegen_encodeSegmentsAdvanced().
* (Note that all ways require supplying the desired error correction level and various byte buffers.)
*/
/*---- Enum and struct types----*/
/*
* The error correction level in a QR Code symbol.
*/
enum qrcodegen_Ecc {
// Must be declared in ascending order of error protection
// so that an internal qrcodegen function works properly
qrcodegen_Ecc_LOW = 0 , // The QR Code can tolerate about 7% erroneous codewords
qrcodegen_Ecc_MEDIUM , // The QR Code can tolerate about 15% erroneous codewords
qrcodegen_Ecc_QUARTILE, // The QR Code can tolerate about 25% erroneous codewords
qrcodegen_Ecc_HIGH , // The QR Code can tolerate about 30% erroneous codewords
};
/*
* The mask pattern used in a QR Code symbol.
*/
enum qrcodegen_Mask {
// A special value to tell the QR Code encoder to
// automatically select an appropriate mask pattern
qrcodegen_Mask_AUTO = -1,
// The eight actual mask patterns
qrcodegen_Mask_0 = 0,
qrcodegen_Mask_1,
qrcodegen_Mask_2,
qrcodegen_Mask_3,
qrcodegen_Mask_4,
qrcodegen_Mask_5,
qrcodegen_Mask_6,
qrcodegen_Mask_7,
};
/*
* Describes how a segment's data bits are interpreted.
*/
enum qrcodegen_Mode {
qrcodegen_Mode_NUMERIC = 0x1,
qrcodegen_Mode_ALPHANUMERIC = 0x2,
qrcodegen_Mode_BYTE = 0x4,
qrcodegen_Mode_KANJI = 0x8,
qrcodegen_Mode_ECI = 0x7,
};
/*
* A segment of character/binary/control data in a QR Code symbol.
* The mid-level way to create a segment is to take the payload data
* and call a factory function such as qrcodegen_makeNumeric().
* The low-level way to create a segment is to custom-make the bit buffer
* and initialize a qrcodegen_Segment struct with appropriate values.
* Even in the most favorable conditions, a QR Code can only hold 7089 characters of data.
* Any segment longer than this is meaningless for the purpose of generating QR Codes.
* Moreover, the maximum allowed bit length is 32767 because
* the largest QR Code (version 40) has 31329 modules.
*/
struct qrcodegen_Segment {
// The mode indicator of this segment.
enum qrcodegen_Mode mode;
// The length of this segment's unencoded data. Measured in characters for
// numeric/alphanumeric/kanji mode, bytes for byte mode, and 0 for ECI mode.
// Always zero or positive. Not the same as the data's bit length.
int numChars;
// The data bits of this segment, packed in bitwise big endian.
// Can be null if the bit length is zero.
uint8_t *data;
// The number of valid data bits used in the buffer. Requires
// 0 <= bitLength <= 32767, and bitLength <= (capacity of data array) * 8.
// The character count (numChars) must agree with the mode and the bit buffer length.
int bitLength;
};
/*---- Macro constants and functions ----*/
#define qrcodegen_VERSION_MIN 1 // The minimum version number supported in the QR Code Model 2 standard
#define qrcodegen_VERSION_MAX 40 // The maximum version number supported in the QR Code Model 2 standard
// Calculates the number of bytes needed to store any QR Code up to and including the given version number,
// as a compile-time constant. For example, 'uint8_t buffer[qrcodegen_BUFFER_LEN_FOR_VERSION(25)];'
// can store any single QR Code from version 1 to 25 (inclusive). The result fits in an int (or int16).
// Requires qrcodegen_VERSION_MIN <= n <= qrcodegen_VERSION_MAX.
#define qrcodegen_BUFFER_LEN_FOR_VERSION(n) ((((n) * 4 + 17) * ((n) * 4 + 17) + 7) / 8 + 1)
// The worst-case number of bytes needed to store one QR Code, up to and including
// version 40. This value equals 3918, which is just under 4 kilobytes.
// Use this more convenient value to avoid calculating tighter memory bounds for buffers.
#define qrcodegen_BUFFER_LEN_MAX qrcodegen_BUFFER_LEN_FOR_VERSION(qrcodegen_VERSION_MAX)
/*---- Functions (high level) to generate QR Codes ----*/
/*
* Encodes the given text string to a QR Code, returning true if encoding succeeded.
* If the data is too long to fit in any version in the given range
* at the given ECC level, then false is returned.
* - The input text must be encoded in UTF-8 and contain no NULs.
* - The variables ecl and mask must correspond to enum constant values.
* - Requires 1 <= minVersion <= maxVersion <= 40.
* - The arrays tempBuffer and qrcode must each have a length
* of at least qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion).
* - After the function returns, tempBuffer contains no useful data.
* - If successful, the resulting QR Code may use numeric,
* alphanumeric, or byte mode to encode the text.
* - In the most optimistic case, a QR Code at version 40 with low ECC
* can hold any UTF-8 string up to 2953 bytes, or any alphanumeric string
* up to 4296 characters, or any digit string up to 7089 characters.
* These numbers represent the hard upper limit of the QR Code standard.
* - Please consult the QR Code specification for information on
* data capacities per version, ECC level, and text encoding mode.
*/
bool qrcodegen_encodeText(const char *text, uint8_t tempBuffer[], uint8_t qrcode[],
enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl);
/*
* Encodes the given binary data to a QR Code, returning true if encoding succeeded.
* If the data is too long to fit in any version in the given range
* at the given ECC level, then false is returned.
* - The input array range dataAndTemp[0 : dataLen] should normally be
* valid UTF-8 text, but is not required by the QR Code standard.
* - The variables ecl and mask must correspond to enum constant values.
* - Requires 1 <= minVersion <= maxVersion <= 40.
* - The arrays dataAndTemp and qrcode must each have a length
* of at least qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion).
* - After the function returns, the contents of dataAndTemp may have changed,
* and does not represent useful data anymore.
* - If successful, the resulting QR Code will use byte mode to encode the data.
* - In the most optimistic case, a QR Code at version 40 with low ECC can hold any byte
* sequence up to length 2953. This is the hard upper limit of the QR Code standard.
* - Please consult the QR Code specification for information on
* data capacities per version, ECC level, and text encoding mode.
*/
bool qrcodegen_encodeBinary(uint8_t dataAndTemp[], size_t dataLen, uint8_t qrcode[],
enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl);
/*---- Functions (low level) to generate QR Codes ----*/
/*
* Renders a QR Code representing the given segments at the given error correction level.
* The smallest possible QR Code version is automatically chosen for the output. Returns true if
* QR Code creation succeeded, or false if the data is too long to fit in any version. The ECC level
* of the result may be higher than the ecl argument if it can be done without increasing the version.
* This function allows the user to create a custom sequence of segments that switches
* between modes (such as alphanumeric and byte) to encode text in less space.
* This is a low-level API; the high-level API is qrcodegen_encodeText() and qrcodegen_encodeBinary().
* To save memory, the segments' data buffers can alias/overlap tempBuffer, and will
* result in them being clobbered, but the QR Code output will still be correct.
* But the qrcode array must not overlap tempBuffer or any segment's data buffer.
*/
bool qrcodegen_encodeSegments(const struct qrcodegen_Segment segs[], size_t len,
enum qrcodegen_Ecc ecl, uint8_t tempBuffer[], uint8_t qrcode[]);
/*
* Renders a QR Code representing the given segments with the given encoding parameters.
* Returns true if QR Code creation succeeded, or false if the data is too long to fit in the range of versions.
* The smallest possible QR Code version within the given range is automatically
* chosen for the output. Iff boostEcl is true, then the ECC level of the result
* may be higher than the ecl argument if it can be done without increasing the
* version. The mask number is either between 0 to 7 (inclusive) to force that
* mask, or -1 to automatically choose an appropriate mask (which may be slow).
* This function allows the user to create a custom sequence of segments that switches
* between modes (such as alphanumeric and byte) to encode text in less space.
* This is a low-level API; the high-level API is qrcodegen_encodeText() and qrcodegen_encodeBinary().
* To save memory, the segments' data buffers can alias/overlap tempBuffer, and will
* result in them being clobbered, but the QR Code output will still be correct.
* But the qrcode array must not overlap tempBuffer or any segment's data buffer.
*/
bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], size_t len, enum qrcodegen_Ecc ecl,
int minVersion, int maxVersion, int mask, bool boostEcl, uint8_t tempBuffer[], uint8_t qrcode[]);
/*
* Tests whether the given string can be encoded as a segment in alphanumeric mode.
* A string is encodable iff each character is in the following set: 0 to 9, A to Z
* (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon.
*/
bool qrcodegen_isAlphanumeric(const char *text);
/*
* Tests whether the given string can be encoded as a segment in numeric mode.
* A string is encodable iff each character is in the range 0 to 9.
*/
bool qrcodegen_isNumeric(const char *text);
/*
* Returns the number of bytes (uint8_t) needed for the data buffer of a segment
* containing the given number of characters using the given mode. Notes:
* - Returns SIZE_MAX on failure, i.e. numChars > INT16_MAX or
* the number of needed bits exceeds INT16_MAX (i.e. 32767).
* - Otherwise, all valid results are in the range [0, ceil(INT16_MAX / 8)], i.e. at most 4096.
* - It is okay for the user to allocate more bytes for the buffer than needed.
* - For byte mode, numChars measures the number of bytes, not Unicode code points.
* - For ECI mode, numChars must be 0, and the worst-case number of bytes is returned.
* An actual ECI segment can have shorter data. For non-ECI modes, the result is exact.
*/
size_t qrcodegen_calcSegmentBufferSize(enum qrcodegen_Mode mode, size_t numChars);
/*
* Returns a segment representing the given binary data encoded in
* byte mode. All input byte arrays are acceptable. Any text string
* can be converted to UTF-8 bytes and encoded as a byte mode segment.
*/
struct qrcodegen_Segment qrcodegen_makeBytes(const uint8_t data[], size_t len, uint8_t buf[]);
/*
* Returns a segment representing the given string of decimal digits encoded in numeric mode.
*/
struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[]);
/*
* Returns a segment representing the given text string encoded in alphanumeric mode.
* The characters allowed are: 0 to 9, A to Z (uppercase only), space,
* dollar, percent, asterisk, plus, hyphen, period, slash, colon.
*/
struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, uint8_t buf[]);
/*
* Returns a segment representing an Extended Channel Interpretation
* (ECI) designator with the given assignment value.
*/
struct qrcodegen_Segment qrcodegen_makeEci(long assignVal, uint8_t buf[]);
/*---- Functions to extract raw data from QR Codes ----*/
/*
* Returns the side length of the given QR Code, assuming that encoding succeeded.
* The result is in the range [21, 177]. Note that the length of the array buffer
* is related to the side length - every 'uint8_t qrcode[]' must have length at least
* qrcodegen_BUFFER_LEN_FOR_VERSION(version), which equals ceil(size^2 / 8 + 1).
*/
int qrcodegen_getSize(const uint8_t qrcode[]);
/*
* Returns the color of the module (pixel) at the given coordinates, which is false
* for white or true for black. The top left corner has the coordinates (x=0, y=0).
* If the given coordinates are out of bounds, then false (white) is returned.
*/
bool qrcodegen_getModule(const uint8_t qrcode[], int x, int y);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,871 @@
/**
* @file lv_sjpg.c
*
*/
/*----------------------------------------------------------------------------------------------------------------------------------
/ Added normal JPG support [7/10/2020]
/ ----------
/ SJPEG is a custom created modified JPEG file format for small embedded platforms.
/ It will contain multiple JPEG fragments all embedded into a single file with a custom header.
/ This makes JPEG decoding easier using any JPEG library. Overall file size will be almost
/ similar to the parent jpeg file. We can generate sjpeg from any jpeg using a python script
/ provided along with this project.
/ (by vinodstanur | 2020 )
/ SJPEG FILE STRUCTURE
/ --------------------------------------------------------------------------------------------------------------------------------
/ Bytes | Value |
/ --------------------------------------------------------------------------------------------------------------------------------
/
/ 0 - 7 | "_SJPG__" followed by '\0'
/
/ 8 - 13 | "V1.00" followed by '\0' [VERSION OF SJPG FILE for future compatibiliby]
/
/ 14 - 15 | X_RESOLUTION (width) [little endian]
/
/ 16 - 17 | Y_RESOLUTION (height) [little endian]
/
/ 18 - 19 | TOTAL_FRAMES inside sjpeg [little endian]
/
/ 20 - 21 | JPEG BLOCK WIDTH (16 normally) [little endian]
/
/ 22 - [(TOTAL_FRAMES*2 )] | SIZE OF EACH JPEG SPLIT FRAGMENTS (FRAME_INFO_ARRAY)
/
/ SJPEG data | Each JPEG frame can be extracted from SJPEG data by parsing the FRAME_INFO_ARRAY one time.
/
/----------------------------------------------------------------------------------------------------------------------------------
/ JPEG DECODER
/ ------------
/ We are using TJpgDec - Tiny JPEG Decompressor library from ELM-CHAN for decoding each split-jpeg fragments.
/ The tjpgd.c and tjpgd.h is not modified and those are used as it is. So if any update comes for the tiny-jpeg,
/ just replace those files with updated files.
/---------------------------------------------------------------------------------------------------------------------------------*/
/*********************
* INCLUDES
*********************/
#include "../../../lvgl.h"
#if LV_USE_SJPG
#include "tjpgd.h"
#include "lv_sjpg.h"
/*********************
* DEFINES
*********************/
#define TJPGD_WORKBUFF_SIZE 4096 //Recommended by TJPGD libray
//NEVER EDIT THESE OFFSET VALUES
#define SJPEG_VERSION_OFFSET 8
#define SJPEG_X_RES_OFFSET 14
#define SJPEG_y_RES_OFFSET 16
#define SJPEG_TOTAL_FRAMES_OFFSET 18
#define SJPEG_BLOCK_WIDTH_OFFSET 20
#define SJPEG_FRAME_INFO_ARRAY_OFFSET 22
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static lv_res_t decoder_info( lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header );
static lv_res_t decoder_open( lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc );
static lv_res_t decoder_read_line( lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc, lv_coord_t x,lv_coord_t y, lv_coord_t len, uint8_t * buf );
static void decoder_close( lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc );
static size_t input_func ( JDEC* jd, uint8_t* buff, size_t ndata );
static int is_jpg( const uint8_t *raw_data );
static void lv_sjpg_cleanup( SJPEG* sjpeg );
static void lv_sjpg_free( SJPEG* sjpeg );
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_split_jpeg_init( void )
{
lv_img_decoder_t* dec = lv_img_decoder_create( );
lv_img_decoder_set_info_cb( dec, decoder_info );
lv_img_decoder_set_open_cb( dec, decoder_open );
lv_img_decoder_set_close_cb( dec, decoder_close );
lv_img_decoder_set_read_line_cb( dec, decoder_read_line );
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Get info about an SJPG / JPG image
* @param decoder pointer to the decoder where this function belongs
* @param src can be file name or pointer to a C array
* @param header store the info here
* @return LV_RES_OK: no error; LV_RES_INV: can't get the info
*/
static lv_res_t decoder_info( lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header )
{
LV_UNUSED(decoder);
/*Check whether the type `src` is known by the decoder*/
/* Read the SJPG/JPG header and find `width` and `height` */
lv_img_src_t src_type = lv_img_src_get_type(src); /*Get the source type*/
lv_res_t ret = LV_RES_OK;
if(src_type == LV_IMG_SRC_VARIABLE) {
uint8_t *raw_sjpeg_data = (uint8_t *)((lv_img_dsc_t * )src)->data;
const uint32_t raw_sjpeg_data_size = ((lv_img_dsc_t *)src)->data_size;
if(!strncmp((char *)raw_sjpeg_data, "_SJPG__", strlen("_SJPG__") )) {
raw_sjpeg_data += 14; //seek to res info ... refer sjpeg format
header->always_zero = 0;
header->cf = LV_IMG_CF_RAW;
header->w = *raw_sjpeg_data++;
header->w |= *raw_sjpeg_data++ << 8;
header->h = *raw_sjpeg_data++;
header->h |= *raw_sjpeg_data++ << 8;
return ret;
} else if( is_jpg( raw_sjpeg_data ) == true ) {
header->always_zero = 0;
header->cf = LV_IMG_CF_RAW;
uint8_t *workb_temp = lv_mem_alloc( TJPGD_WORKBUFF_SIZE );
if(!workb_temp) return LV_RES_INV;
io_source_t io_source_temp;
io_source_temp.type = SJPEG_IO_SOURCE_C_ARRAY;
io_source_temp.raw_sjpg_data = raw_sjpeg_data;
io_source_temp.raw_sjpg_data_size = raw_sjpeg_data_size;
io_source_temp.raw_sjpg_data_next_read_pos = 0;
JDEC jd_tmp;
JRESULT rc = jd_prepare( &jd_tmp, input_func, workb_temp, (size_t)TJPGD_WORKBUFF_SIZE, &io_source_temp);
if(rc == JDR_OK ) {
header->w = jd_tmp.width;
header->h = jd_tmp.height;
} else {
ret = LV_RES_INV;
goto end;
}
end:
lv_mem_free(workb_temp);
return ret;
}
}
else if( src_type == LV_IMG_SRC_FILE ) {
const char * fn = src;
if(!strcmp(&fn[strlen(fn) - 5], ".sjpg")) {
uint8_t buff[22];
memset(buff, 0, sizeof(buff));
lv_fs_file_t file;
lv_fs_res_t res = lv_fs_open(&file , fn, LV_FS_MODE_RD);
if(res != LV_FS_RES_OK) return 78;
uint32_t rn;
res = lv_fs_read(&file, buff, 8, &rn);
if(res != LV_FS_RES_OK || rn != 8) {
lv_fs_close(&file);
return LV_RES_INV;
}
if(strcmp((char *)buff, "_SJPG__") == 0 ) {
lv_fs_seek(&file, 14, LV_FS_SEEK_SET);
res = lv_fs_read(&file, buff, 4, &rn);
if(res != LV_FS_RES_OK || rn != 4 ) {
lv_fs_close(&file);
return LV_RES_INV;
}
header->always_zero = 0;
header->cf = LV_IMG_CF_RAW;
uint8_t *raw_sjpeg_data = buff;
header->w = *raw_sjpeg_data++;
header->w |= *raw_sjpeg_data++ << 8;
header->h = *raw_sjpeg_data++;
header->h |= *raw_sjpeg_data++ << 8;
lv_fs_close(&file);
return LV_RES_OK;
}
} else if(!strcmp(&fn[strlen(fn) - 4], ".jpg")) {
lv_fs_file_t file;
lv_fs_res_t res = lv_fs_open(&file , fn, LV_FS_MODE_RD);
if(res != LV_FS_RES_OK) return 78;
uint8_t *workb_temp = lv_mem_alloc( TJPGD_WORKBUFF_SIZE );
if(!workb_temp) {
lv_fs_close(&file);
return LV_RES_INV;
}
io_source_t io_source_temp;
io_source_temp.type = SJPEG_IO_SOURCE_DISK;
io_source_temp.raw_sjpg_data_next_read_pos = 0;
io_source_temp.img_cache_buff = NULL;
io_source_temp.lv_file = file;
JDEC jd_tmp;
JRESULT rc = jd_prepare( &jd_tmp, input_func, workb_temp, (size_t)TJPGD_WORKBUFF_SIZE, &io_source_temp);
lv_mem_free(workb_temp);
lv_fs_close(&file);
if(rc == JDR_OK ) {
header->always_zero = 0;
header->cf = LV_IMG_CF_RAW;
header->w = jd_tmp.width;
header->h = jd_tmp.height;
return LV_RES_OK;
}
}
}
return LV_RES_INV;
}
static int img_data_cb( JDEC* jd, void* data, JRECT* rect )
{
io_source_t *io = jd->device;
uint8_t *cache = io->img_cache_buff;
const int xres = io->img_cache_x_res;
uint8_t *buf = data;
const int INPUT_PIXEL_SIZE = 3;
const int row_width = rect->right - rect->left + 1; // Row width in pixels.
const int row_size = row_width * INPUT_PIXEL_SIZE; // Row size (bytes).
for( int y = rect->top; y <= rect->bottom; y++ ) {
int row_offset = y * xres * INPUT_PIXEL_SIZE + rect->left * INPUT_PIXEL_SIZE;
memcpy( cache + row_offset, buf, row_size );
buf += row_size;
}
return 1;
}
static size_t input_func ( JDEC* jd, uint8_t* buff, size_t ndata )
{
io_source_t *io = jd->device;
if(!io) return 0;
if(io->type == SJPEG_IO_SOURCE_C_ARRAY) {
const uint32_t bytes_left = io->raw_sjpg_data_size - io->raw_sjpg_data_next_read_pos;
const uint32_t to_read = ndata <= bytes_left ? (uint32_t)ndata : bytes_left;
if (to_read == 0)
return 0;
if(buff) {
memcpy(buff, io->raw_sjpg_data + io->raw_sjpg_data_next_read_pos, to_read);
}
io->raw_sjpg_data_next_read_pos += to_read;
return to_read;
}
else if(io->type == SJPEG_IO_SOURCE_DISK) {
lv_fs_file_t* lv_file_p = &(io->lv_file);
if( buff ) {
uint32_t rn = 0;
lv_fs_read(lv_file_p, buff, (uint32_t)ndata, &rn);
return rn;
} else {
uint32_t pos;
lv_fs_tell(lv_file_p, &pos);
lv_fs_seek(lv_file_p, (uint32_t)(ndata + pos), LV_FS_SEEK_SET);
return ndata;
}
}
return 0;
}
/**
* Open SJPG image and return the decided image
* @param decoder pointer to the decoder where this function belongs
* @param dsc pointer to a descriptor which describes this decoding session
* @return LV_RES_OK: no error; LV_RES_INV: can't get the info
*/
static lv_res_t decoder_open( lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc )
{
LV_UNUSED(decoder);
lv_res_t lv_ret = LV_RES_OK;
if(dsc->src_type == LV_IMG_SRC_VARIABLE) {
uint8_t *data;
SJPEG* sjpeg = ( SJPEG* ) dsc->user_data;
if( sjpeg == NULL ) {
sjpeg = lv_mem_alloc( sizeof( SJPEG ) );
if( !sjpeg ) return LV_RES_INV;
memset(sjpeg, 0, sizeof(SJPEG));
dsc->user_data = sjpeg;
sjpeg->sjpeg_data = (uint8_t *)( ( lv_img_dsc_t* )(dsc->src) )->data;
sjpeg->sjpeg_data_size = ( ( lv_img_dsc_t* )(dsc->src) )->data_size;
}
if( !strncmp( ( char * ) sjpeg->sjpeg_data, "_SJPG__", strlen("_SJPG__") ) ) {
data = sjpeg->sjpeg_data;
data += 14;
sjpeg->sjpeg_x_res = *data++;
sjpeg->sjpeg_x_res |= *data++ << 8;
sjpeg->sjpeg_y_res = *data++;
sjpeg->sjpeg_y_res |= *data++ << 8;
sjpeg->sjpeg_total_frames = *data++;
sjpeg->sjpeg_total_frames |= *data++ << 8;
sjpeg->sjpeg_single_frame_height = *data++;
sjpeg->sjpeg_single_frame_height |= *data++ << 8;
sjpeg->frame_base_array = lv_mem_alloc( sizeof(uint8_t *) * sjpeg->sjpeg_total_frames );
if( ! sjpeg->frame_base_array ) {
lv_sjpg_cleanup( sjpeg );
sjpeg = NULL;
return LV_RES_INV;
}
sjpeg->frame_base_offset = NULL;
uint8_t *img_frame_base = data + sjpeg->sjpeg_total_frames *2;
sjpeg->frame_base_array[0] = img_frame_base;
for( int i = 1; i < sjpeg->sjpeg_total_frames; i++ ) {
int offset = *data++;
offset |= *data++ <<8;
sjpeg->frame_base_array[i] = sjpeg->frame_base_array[i-1] + offset;
}
sjpeg->sjpeg_cache_frame_index = -1;
sjpeg->frame_cache = (void *)lv_mem_alloc( sjpeg->sjpeg_x_res * sjpeg->sjpeg_single_frame_height * 3/*2*/ );
if( ! sjpeg->frame_cache ) {
lv_sjpg_cleanup( sjpeg );
sjpeg = NULL;
return LV_RES_INV;
}
sjpeg->io.img_cache_buff = sjpeg->frame_cache;
sjpeg->io.img_cache_x_res = sjpeg->sjpeg_x_res;
sjpeg->workb = lv_mem_alloc( TJPGD_WORKBUFF_SIZE );
if( ! sjpeg->workb ) {
lv_sjpg_cleanup( sjpeg );
sjpeg = NULL;
return LV_RES_INV;
}
sjpeg->tjpeg_jd = lv_mem_alloc( sizeof( JDEC ) );
if( ! sjpeg->tjpeg_jd ) {
lv_sjpg_cleanup( sjpeg );
sjpeg = NULL;
return LV_RES_INV;
}
sjpeg->io.type = SJPEG_IO_SOURCE_C_ARRAY;
sjpeg->io.lv_file.file_d = NULL;
dsc->img_data = NULL;
return lv_ret;
}
else if( is_jpg( sjpeg->sjpeg_data ) == true ) {
uint8_t *workb_temp = lv_mem_alloc( TJPGD_WORKBUFF_SIZE );
if( ! workb_temp ) {
lv_sjpg_cleanup( sjpeg );
sjpeg = NULL;
return LV_RES_INV;
}
io_source_t io_source_temp;
io_source_temp.type = SJPEG_IO_SOURCE_C_ARRAY;
io_source_temp.raw_sjpg_data = sjpeg->sjpeg_data;
io_source_temp.raw_sjpg_data_size = sjpeg->sjpeg_data_size;
io_source_temp.raw_sjpg_data_next_read_pos = 0;
JDEC jd_tmp;
JRESULT rc = jd_prepare( &jd_tmp, input_func, workb_temp, (size_t)TJPGD_WORKBUFF_SIZE, &io_source_temp);
lv_mem_free(workb_temp);
if(rc == JDR_OK ) {
sjpeg->sjpeg_x_res = jd_tmp.width;
sjpeg->sjpeg_y_res = jd_tmp.height;
sjpeg->sjpeg_total_frames = 1;
sjpeg->sjpeg_single_frame_height = jd_tmp.height;
sjpeg->frame_base_array = lv_mem_alloc( sizeof(uint8_t *) * sjpeg->sjpeg_total_frames );
if( ! sjpeg->frame_base_array ) {
lv_sjpg_cleanup( sjpeg );
sjpeg = NULL;
return LV_RES_INV;
}
sjpeg->frame_base_offset = NULL;
uint8_t *img_frame_base = sjpeg->sjpeg_data;
sjpeg->frame_base_array[0] = img_frame_base;
sjpeg->sjpeg_cache_frame_index = -1;
sjpeg->frame_cache = (void *)lv_mem_alloc( sjpeg->sjpeg_x_res * sjpeg->sjpeg_single_frame_height * 3 );
if( ! sjpeg->frame_cache ) {
lv_sjpg_cleanup( sjpeg );
sjpeg = NULL;
return LV_RES_INV;
}
sjpeg->io.img_cache_buff = sjpeg->frame_cache;
sjpeg->io.img_cache_x_res = sjpeg->sjpeg_x_res;
sjpeg->workb = lv_mem_alloc( TJPGD_WORKBUFF_SIZE );
if( ! sjpeg->workb ) {
lv_sjpg_cleanup( sjpeg );
sjpeg = NULL;
return LV_RES_INV;
}
sjpeg->tjpeg_jd = lv_mem_alloc( sizeof( JDEC ) );
if( ! sjpeg->tjpeg_jd ) {
lv_sjpg_cleanup( sjpeg );
sjpeg = NULL;
return LV_RES_INV;
}
sjpeg->io.type = SJPEG_IO_SOURCE_C_ARRAY;
sjpeg->io.lv_file.file_d = NULL;
dsc->img_data = NULL;
return lv_ret;
} else {
lv_ret = LV_RES_INV;
goto end;
}
end:
lv_mem_free(workb_temp);
return lv_ret;
}
}
else if(dsc->src_type == LV_IMG_SRC_FILE) {
/* If all fine, then the file will be kept open */
const char * fn = dsc->src;
uint8_t *data;
if(!strcmp(&fn[strlen(fn) - 5], ".sjpg")) {
uint8_t buff[22];
memset(buff, 0, sizeof(buff));
lv_fs_file_t lv_file;
lv_fs_res_t res = lv_fs_open(&lv_file , fn, LV_FS_MODE_RD);
if(res != LV_FS_RES_OK) {
return 78;
}
uint32_t rn;
res = lv_fs_read(&lv_file, buff, 22, &rn);
if(res != LV_FS_RES_OK || rn != 22 ) {
lv_fs_close(&lv_file);
return LV_RES_INV;
}
if(strcmp((char *)buff, "_SJPG__") == 0 ) {
SJPEG* sjpeg = ( SJPEG* ) dsc->user_data;
if(sjpeg == NULL) {
sjpeg = lv_mem_alloc(sizeof(SJPEG));
if( ! sjpeg ) {
lv_fs_close(&lv_file);
return LV_RES_INV;
}
memset(sjpeg, 0, sizeof(SJPEG));
dsc->user_data = sjpeg;
sjpeg->sjpeg_data = (uint8_t *)( (lv_img_dsc_t* )(dsc->src) )->data;
sjpeg->sjpeg_data_size = ( (lv_img_dsc_t* )(dsc->src) )->data_size;
}
data = buff;
data += 14;
sjpeg->sjpeg_x_res = *data++;
sjpeg->sjpeg_x_res |= *data++ << 8;
sjpeg->sjpeg_y_res = *data++;
sjpeg->sjpeg_y_res |= *data++ << 8;
sjpeg->sjpeg_total_frames = *data++;
sjpeg->sjpeg_total_frames |= *data++ << 8;
sjpeg->sjpeg_single_frame_height = *data++;
sjpeg->sjpeg_single_frame_height |= *data++ << 8;
sjpeg->frame_base_array = NULL;//lv_mem_alloc( sizeof(uint8_t *) * sjpeg->sjpeg_total_frames );
sjpeg->frame_base_offset = lv_mem_alloc( sizeof(int) * sjpeg->sjpeg_total_frames );
if( ! sjpeg->frame_base_offset ) {
lv_fs_close(&lv_file);
lv_sjpg_cleanup(sjpeg);
return LV_RES_INV;
}
int img_frame_start_offset = (SJPEG_FRAME_INFO_ARRAY_OFFSET + sjpeg->sjpeg_total_frames *2);
sjpeg->frame_base_offset[0] = img_frame_start_offset; //pointer used to save integer for now...
for( int i = 1; i < sjpeg->sjpeg_total_frames; i++ ) {
res = lv_fs_read(&lv_file, buff, 2, &rn);
if(res != LV_FS_RES_OK || rn != 2 ) {
lv_fs_close(&lv_file);
return LV_RES_INV;
}
data = buff;
int offset = *data++;
offset |= *data++ <<8;
sjpeg->frame_base_offset[i] = sjpeg->frame_base_offset[i-1] + offset;
}
sjpeg->sjpeg_cache_frame_index = -1; //INVALID AT BEGINNING for a forced compare mismatch at first time.
sjpeg->frame_cache = (void *)lv_mem_alloc( sjpeg->sjpeg_x_res * sjpeg->sjpeg_single_frame_height * 3 );
if( ! sjpeg->frame_cache ) {
lv_fs_close(&lv_file);
lv_sjpg_cleanup(sjpeg);
return LV_RES_INV;
}
sjpeg->io.img_cache_buff = sjpeg->frame_cache;
sjpeg->io.img_cache_x_res = sjpeg->sjpeg_x_res;
sjpeg->workb = lv_mem_alloc( TJPGD_WORKBUFF_SIZE );
if( ! sjpeg->workb ) {
lv_fs_close(&lv_file);
lv_sjpg_cleanup(sjpeg);
return LV_RES_INV;
}
sjpeg->tjpeg_jd = lv_mem_alloc( sizeof( JDEC ) );
if( ! sjpeg->tjpeg_jd ) {
lv_fs_close(&lv_file);
lv_sjpg_cleanup(sjpeg);
return LV_RES_INV;
}
sjpeg->io.type = SJPEG_IO_SOURCE_DISK;
sjpeg->io.lv_file = lv_file;
dsc->img_data = NULL;
return LV_RES_OK;
}
}
else if( !strcmp(&fn[strlen(fn) - 4], ".jpg" ) ) {
lv_fs_file_t lv_file;
lv_fs_res_t res = lv_fs_open( &lv_file , fn, LV_FS_MODE_RD );
if(res != LV_FS_RES_OK) {
return LV_RES_INV;
}
SJPEG* sjpeg = ( SJPEG* ) dsc->user_data;
if(sjpeg == NULL) {
sjpeg = lv_mem_alloc( sizeof( SJPEG ) );
if( ! sjpeg ) {
lv_fs_close( &lv_file );
return LV_RES_INV;
}
memset(sjpeg, 0, sizeof(SJPEG));
dsc->user_data = sjpeg;
sjpeg->sjpeg_data = (uint8_t *)( (lv_img_dsc_t* )(dsc->src) )->data;
sjpeg->sjpeg_data_size = ( (lv_img_dsc_t *)(dsc->src) )->data_size;
}
uint8_t *workb_temp = lv_mem_alloc( TJPGD_WORKBUFF_SIZE );
if( ! workb_temp ) {
lv_fs_close(&lv_file);
lv_sjpg_cleanup(sjpeg);
return LV_RES_INV;
}
io_source_t io_source_temp;
io_source_temp.type = SJPEG_IO_SOURCE_DISK;
io_source_temp.raw_sjpg_data_next_read_pos = 0;
io_source_temp.img_cache_buff = NULL;
io_source_temp.lv_file = lv_file;
JDEC jd_tmp;
JRESULT rc = jd_prepare( &jd_tmp, input_func, workb_temp, (size_t)TJPGD_WORKBUFF_SIZE, &io_source_temp);
lv_mem_free(workb_temp);
if(rc == JDR_OK ) {
sjpeg->sjpeg_x_res = jd_tmp.width;
sjpeg->sjpeg_y_res = jd_tmp.height;
sjpeg->sjpeg_total_frames = 1;
sjpeg->sjpeg_single_frame_height = jd_tmp.height;
sjpeg->frame_base_array = NULL;
sjpeg->frame_base_offset = lv_mem_alloc( sizeof(uint8_t *) * sjpeg->sjpeg_total_frames );
if( ! sjpeg->frame_base_offset ) {
lv_fs_close(&lv_file);
lv_sjpg_cleanup(sjpeg);
return LV_RES_INV;
}
int img_frame_start_offset = 0;
sjpeg->frame_base_offset[0] = img_frame_start_offset;
sjpeg->sjpeg_cache_frame_index = -1;
sjpeg->frame_cache = (void *)lv_mem_alloc( sjpeg->sjpeg_x_res * sjpeg->sjpeg_single_frame_height * 3 );
if( ! sjpeg->frame_cache ) {
lv_fs_close(&lv_file);
lv_sjpg_cleanup(sjpeg);
return LV_RES_INV;
}
sjpeg->io.img_cache_buff = sjpeg->frame_cache;
sjpeg->io.img_cache_x_res = sjpeg->sjpeg_x_res;
sjpeg->workb = lv_mem_alloc( TJPGD_WORKBUFF_SIZE );
if( ! sjpeg->workb ) {
lv_fs_close(&lv_file);
lv_sjpg_cleanup(sjpeg);
return LV_RES_INV;
}
sjpeg->tjpeg_jd = lv_mem_alloc( sizeof( JDEC ) );
if( ! sjpeg->tjpeg_jd ) {
lv_fs_close(&lv_file);
lv_sjpg_cleanup(sjpeg);
return LV_RES_INV;
}
sjpeg->io.type = SJPEG_IO_SOURCE_DISK;
sjpeg->io.lv_file = lv_file;
dsc->img_data = NULL;
return LV_RES_OK;
} else {
if(dsc->user_data) lv_mem_free(dsc->user_data);
lv_fs_close(&lv_file);
return LV_RES_INV;
}
}
}
return LV_RES_INV;
}
/**
* Decode `len` pixels starting from the given `x`, `y` coordinates and store them in `buf`.
* Required only if the "open" function can't open the whole decoded pixel array. (dsc->img_data == NULL)
* @param decoder pointer to the decoder the function associated with
* @param dsc pointer to decoder descriptor
* @param x start x coordinate
* @param y start y coordinate
* @param len number of pixels to decode
* @param buf a buffer to store the decoded pixels
* @return LV_RES_OK: ok; LV_RES_INV: failed
*/
static lv_res_t decoder_read_line( lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf )
{
LV_UNUSED(decoder);
if(dsc->src_type == LV_IMG_SRC_VARIABLE) {
SJPEG* sjpeg = ( SJPEG* ) dsc->user_data;
JRESULT rc;
int sjpeg_req_frame_index = y / sjpeg->sjpeg_single_frame_height;
/*If line not from cache, refresh cache */
if(sjpeg_req_frame_index != sjpeg->sjpeg_cache_frame_index) {
sjpeg->io.raw_sjpg_data = sjpeg->frame_base_array[ sjpeg_req_frame_index ];
if (sjpeg_req_frame_index == (sjpeg->sjpeg_total_frames - 1)) {
/*This is the last frame. */
const uint32_t frame_offset = (uint32_t)(sjpeg->io.raw_sjpg_data - sjpeg->sjpeg_data);
sjpeg->io.raw_sjpg_data_size = sjpeg->sjpeg_data_size - frame_offset;
} else {
sjpeg->io.raw_sjpg_data_size =
(uint32_t)(sjpeg->frame_base_array[sjpeg_req_frame_index + 1] - sjpeg->io.raw_sjpg_data);
}
sjpeg->io.raw_sjpg_data_next_read_pos = 0;
rc = jd_prepare( sjpeg->tjpeg_jd, input_func, sjpeg->workb, (size_t)TJPGD_WORKBUFF_SIZE, &(sjpeg->io));
if(rc != JDR_OK ) return LV_RES_INV;
rc = jd_decomp ( sjpeg->tjpeg_jd, img_data_cb, 0);
if(rc != JDR_OK ) return LV_RES_INV;
sjpeg->sjpeg_cache_frame_index = sjpeg_req_frame_index;
}
int offset = 0;
uint8_t *cache = (uint8_t *)sjpeg->frame_cache + x*3 + ( y % sjpeg->sjpeg_single_frame_height ) * sjpeg->sjpeg_x_res*3;
#if LV_COLOR_DEPTH == 32
for( int i = 0; i < len; i++ ) {
buf[offset + 3] = 0xff;
buf[offset + 2] = *cache++;
buf[offset + 1] = *cache++;
buf[offset + 0] = *cache++;
offset += 4;
}
#elif LV_COLOR_DEPTH == 16
for( int i = 0; i < len; i++ ) {
uint16_t col_16bit = (*cache++ & 0xf8) << 8;
col_16bit |= (*cache++ & 0xFC) << 3;
col_16bit |= (*cache++ >> 3);
#if LV_BIG_ENDIAN_SYSTEM == 1
buf[offset++] = col_16bit >> 8;
buf[offset++] = col_16bit & 0xff;
#else
buf[offset++] = col_16bit & 0xff;
buf[offset++] = col_16bit >> 8;
#endif // LV_BIG_ENDIAN_SYSTEM
}
#elif LV_COLOR_DEPTH == 8
for( int i = 0; i < len; i++ ) {
uint8_t col_8bit = (*cache++ & 0xC0);
col_8bit |= (*cache++ & 0xe0) >> 2;
col_8bit |= (*cache++ & 0xe0) >> 5;
buf[offset++] = col_8bit;
}
#else
#error Unsupported LV_COLOR_DEPTH
#endif // LV_COLOR_DEPTH
return LV_RES_OK;
}
else if(dsc->src_type == LV_IMG_SRC_FILE) {
SJPEG* sjpeg = ( SJPEG* ) dsc->user_data;
JRESULT rc;
int sjpeg_req_frame_index = y / sjpeg->sjpeg_single_frame_height;
lv_fs_file_t* lv_file_p = &(sjpeg->io.lv_file);
if(!lv_file_p) goto end;
/*If line not from cache, refresh cache */
if(sjpeg_req_frame_index != sjpeg->sjpeg_cache_frame_index) {
sjpeg->io.raw_sjpg_data_next_read_pos = (int)(sjpeg->frame_base_offset [ sjpeg_req_frame_index ]);
lv_fs_seek( &(sjpeg->io.lv_file), sjpeg->io.raw_sjpg_data_next_read_pos, LV_FS_SEEK_SET);
rc = jd_prepare( sjpeg->tjpeg_jd, input_func, sjpeg->workb, (size_t)TJPGD_WORKBUFF_SIZE, &(sjpeg->io));
if(rc != JDR_OK ) return LV_RES_INV;
rc = jd_decomp ( sjpeg->tjpeg_jd, img_data_cb, 0);
if(rc != JDR_OK ) return LV_RES_INV;
sjpeg->sjpeg_cache_frame_index = sjpeg_req_frame_index;
}
int offset = 0;
uint8_t *cache = (uint8_t *)sjpeg->frame_cache + x*3 + ( y % sjpeg->sjpeg_single_frame_height ) * sjpeg->sjpeg_x_res*3;
#if LV_COLOR_DEPTH == 32
for( int i = 0; i < len; i++ ) {
buf[offset + 3] = 0xff;
buf[offset + 2] = *cache++;
buf[offset + 1] = *cache++;
buf[offset + 0] = *cache++;
offset += 4;
}
#elif LV_COLOR_DEPTH == 16
for( int i = 0; i < len; i++ ) {
uint16_t col_8bit = (*cache++ & 0xf8) << 8;
col_8bit |= (*cache++ & 0xFC) << 3;
col_8bit |= (*cache++ >> 3);
#if LV_BIG_ENDIAN_SYSTEM == 1
buf[offset++] = col_8bit >> 8;
buf[offset++] = col_8bit & 0xff;
#else
buf[offset++] = col_8bit & 0xff;
buf[offset++] = col_8bit >> 8;
#endif // LV_BIG_ENDIAN_SYSTEM
}
#elif LV_COLOR_DEPTH == 8
for( int i = 0; i < len; i++ ) {
uint8_t col_8bit = (*cache++ & 0xC0);
col_8bit |= (*cache++ & 0xe0) >> 2;
col_8bit |= (*cache++ & 0xe0) >> 5;
buf[offset++] = col_8bit;
}
#else
#error Unsupported LV_COLOR_DEPTH
#endif // LV_COLOR_DEPTH
return LV_RES_OK;
}
end:
return LV_RES_INV;
}
/**
* Free the allocated resources
* @param decoder pointer to the decoder where this function belongs
* @param dsc pointer to a descriptor which describes this decoding session
*/
static void decoder_close( lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc )
{
LV_UNUSED(decoder);
/*Free all allocated data*/
SJPEG* sjpeg = ( SJPEG* ) dsc->user_data;
if(!sjpeg) return;
switch(dsc->src_type) {
case LV_IMG_SRC_FILE:
if(sjpeg->io.lv_file.file_d) {
lv_fs_close(&(sjpeg->io.lv_file));
}
lv_sjpg_free(sjpeg);
break;
case LV_IMG_SRC_VARIABLE:
lv_sjpg_free(sjpeg);
break;
default:
;
}
}
static int is_jpg( const uint8_t *raw_data )
{
const uint8_t jpg_signature[] = {0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46};//ÿØÿà<C3BF>JFIF
return memcmp( jpg_signature, raw_data, sizeof( jpg_signature ) ) == 0;
}
static void lv_sjpg_free( SJPEG* sjpeg )
{
if(sjpeg->frame_cache) lv_mem_free(sjpeg->frame_cache);
if(sjpeg->frame_base_array) lv_mem_free(sjpeg->frame_base_array);
if(sjpeg->frame_base_offset) lv_mem_free(sjpeg->frame_base_offset);
if(sjpeg->tjpeg_jd) lv_mem_free(sjpeg->tjpeg_jd);
if(sjpeg->workb) lv_mem_free(sjpeg->workb);
}
static void lv_sjpg_cleanup( SJPEG* sjpeg )
{
if(! sjpeg ) return;
lv_sjpg_free( sjpeg );
lv_mem_free( sjpeg );
}
#endif /*LV_USE_SJPG*/

View File

@@ -0,0 +1,81 @@
/**
* @file lv_sjpg.h
*
*/
#ifndef LV_SJPEG_H
#define LV_SJPEG_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include <stdio.h>
#include "tjpgd.h"
#include "../../../misc/lv_fs.h"
#if LV_USE_SJPG
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
enum io_source_type {
SJPEG_IO_SOURCE_C_ARRAY,
SJPEG_IO_SOURCE_DISK,
};
typedef struct {
enum io_source_type type;
lv_fs_file_t lv_file;
uint8_t* img_cache_buff;
int img_cache_x_res;
int img_cache_y_res;
uint8_t *raw_sjpg_data; //Used when type==SJPEG_IO_SOURCE_C_ARRAY.
uint32_t raw_sjpg_data_size; //Num bytes pointed to by raw_sjpg_data.
uint32_t raw_sjpg_data_next_read_pos; //Used for all types.
} io_source_t;
typedef struct {
uint8_t *sjpeg_data;
uint32_t sjpeg_data_size;
int sjpeg_x_res;
int sjpeg_y_res;
int sjpeg_total_frames;
int sjpeg_single_frame_height;
int sjpeg_cache_frame_index;
uint8_t **frame_base_array; //to save base address of each split frames upto sjpeg_total_frames.
int *frame_base_offset; //to save base offset for fseek
uint8_t *frame_cache;
uint8_t* workb; //JPG work buffer for jpeg library
JDEC *tjpeg_jd;
io_source_t io;
} SJPEG;
/**********************
* GLOBAL PROTOTYPES
**********************/
void lv_split_jpeg_init(void);
/**********************
* MACROS
**********************/
#endif /*LV_USE_SJPG*/
#ifdef __cplusplus
}
#endif
#endif /* LV_SJPEG_H */

1155
src/extra/libs/sjpg/tjpgd.c Normal file

File diff suppressed because it is too large Load Diff

102
src/extra/libs/sjpg/tjpgd.h Normal file
View File

@@ -0,0 +1,102 @@
/*----------------------------------------------------------------------------/
/ TJpgDec - Tiny JPEG Decompressor R0.03 include file (C)ChaN, 2021
/----------------------------------------------------------------------------*/
#ifndef DEF_TJPGDEC
#define DEF_TJPGDEC
#ifdef __cplusplus
extern "C" {
#endif
#include "../../../lv_conf_internal.h"
#if LV_USE_SJPG
#include "tjpgdcnf.h"
#include <string.h>
#if defined(_WIN32) /* VC++ or some compiler without stdint.h */
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef short int16_t;
typedef unsigned long uint32_t;
typedef long int32_t;
#else /* Embedded platform */
#include <stdint.h>
#endif
#if JD_FASTDECODE >= 1
typedef int16_t jd_yuv_t;
#else
typedef uint8_t jd_yuv_t;
#endif
/* Error code */
typedef enum {
JDR_OK = 0, /* 0: Succeeded */
JDR_INTR, /* 1: Interrupted by output function */
JDR_INP, /* 2: Device error or wrong termination of input stream */
JDR_MEM1, /* 3: Insufficient memory pool for the image */
JDR_MEM2, /* 4: Insufficient stream input buffer */
JDR_PAR, /* 5: Parameter error */
JDR_FMT1, /* 6: Data format error (may be broken data) */
JDR_FMT2, /* 7: Right format but not supported */
JDR_FMT3 /* 8: Not supported JPEG standard */
} JRESULT;
/* Rectangular region in the output image */
typedef struct {
uint16_t left; /* Left end */
uint16_t right; /* Right end */
uint16_t top; /* Top end */
uint16_t bottom; /* Bottom end */
} JRECT;
/* Decompressor object structure */
typedef struct JDEC JDEC;
struct JDEC {
size_t dctr; /* Number of bytes available in the input buffer */
uint8_t* dptr; /* Current data read ptr */
uint8_t* inbuf; /* Bit stream input buffer */
uint8_t dbit; /* Number of bits availavble in wreg or reading bit mask */
uint8_t scale; /* Output scaling ratio */
uint8_t msx, msy; /* MCU size in unit of block (width, height) */
uint8_t qtid[3]; /* Quantization table ID of each component, Y, Cb, Cr */
uint8_t ncomp; /* Number of color components 1:grayscale, 3:color */
int16_t dcv[3]; /* Previous DC element of each component */
uint16_t nrst; /* Restart inverval */
uint16_t width, height; /* Size of the input image (pixel) */
uint8_t* huffbits[2][2]; /* Huffman bit distribution tables [id][dcac] */
uint16_t* huffcode[2][2]; /* Huffman code word tables [id][dcac] */
uint8_t* huffdata[2][2]; /* Huffman decoded data tables [id][dcac] */
int32_t* qttbl[4]; /* Dequantizer tables [id] */
#if JD_FASTDECODE >= 1
uint32_t wreg; /* Working shift register */
uint8_t marker; /* Detected marker (0:None) */
#if JD_FASTDECODE == 2
uint8_t longofs[2][2]; /* Table offset of long code [id][dcac] */
uint16_t* hufflut_ac[2]; /* Fast huffman decode tables for AC short code [id] */
uint8_t* hufflut_dc[2]; /* Fast huffman decode tables for DC short code [id] */
#endif
#endif
void* workbuf; /* Working buffer for IDCT and RGB output */
jd_yuv_t* mcubuf; /* Working buffer for the MCU */
void* pool; /* Pointer to available memory pool */
size_t sz_pool; /* Size of momory pool (bytes available) */
size_t (*infunc)(JDEC*, uint8_t*, size_t); /* Pointer to jpeg stream input function */
void* device; /* Pointer to I/O device identifiler for the session */
};
/* TJpgDec API functions */
JRESULT jd_prepare (JDEC* jd, size_t (*infunc)(JDEC*,uint8_t*,size_t), void* pool, size_t sz_pool, void* dev);
JRESULT jd_decomp (JDEC* jd, int (*outfunc)(JDEC*,void*,JRECT*), uint8_t scale);
#endif /*LV_USE_SJPG*/
#ifdef __cplusplus
}
#endif
#endif /* _TJPGDEC */

View File

@@ -0,0 +1,33 @@
/*----------------------------------------------*/
/* TJpgDec System Configurations R0.03 */
/*----------------------------------------------*/
#define JD_SZBUF 512
/* Specifies size of stream input buffer */
#define JD_FORMAT 0
/* Specifies output pixel format.
/ 0: RGB888 (24-bit/pix)
/ 1: RGB565 (16-bit/pix)
/ 2: Grayscale (8-bit/pix)
*/
#define JD_USE_SCALE 1
/* Switches output descaling feature.
/ 0: Disable
/ 1: Enable
*/
#define JD_TBLCLIP 1
/* Use table conversion for saturation arithmetic. A bit faster, but increases 1 KB of code size.
/ 0: Disable
/ 1: Enable
*/
#define JD_FASTDECODE 0
/* Optimization level
/ 0: Basic optimization. Suitable for 8/16-bit MCUs.
/ 1: + 32-bit barrel shifter. Suitable for 32-bit MCUs.
/ 2: + Table conversion for huffman decoding (wants 6 << HUFF_BIT bytes of RAM)
*/

View File

@@ -41,6 +41,38 @@ void lv_extra_init(void)
#if LV_USE_GRID
lv_grid_init();
#endif
#if LV_USE_FS_FATFS != '\0'
lv_fs_fatfs_init();
#endif
#if LV_USE_FS_STDIO != '\0'
lv_fs_stdio_init();
#endif
#if LV_USE_FS_POSIX != '\0'
lv_fs_posix_init();
#endif
#if LV_USE_PNG
lv_png_init();
#endif
#if LV_USE_SJPG
lv_split_jpeg_init();
#endif
#if LV_USE_BMP
lv_bmp_init();
#endif
#if LV_USE_FREETYPE
/*Init freetype library
*Cache max 64 faces and 1 size*/
lv_freetype_init(0, 0, LV_FREETYPE_CACHE_SIZE);
#endif
}
/**********************

View File

@@ -1563,6 +1563,104 @@ e.g. "stm32f769xx.h" or "stm32f429xx.h"*/
# endif
#endif
/*---------------------
* 3rd party libraries
*--------------------*/
/*File system interfaces for common APIs
*To enable set a driver letter for that API*/
#ifndef LV_USE_FS_STDIO
# ifdef CONFIG_LV_USE_FS_STDIO
# define LV_USE_FS_STDIO CONFIG_LV_USE_FS_STDIO
# else
# define LV_USE_FS_STDIO '\0' /*Uses fopen, fread, etc*/
# endif
#endif
//#define LV_FS_STDIO_PATH "/home/john/" /*Set the working directory. If commented it will be "./" */
#ifndef LV_USE_FS_POSIX
# ifdef CONFIG_LV_USE_FS_POSIX
# define LV_USE_FS_POSIX CONFIG_LV_USE_FS_POSIX
# else
# define LV_USE_FS_POSIX '\0' /*Uses open, read, etc*/
# endif
#endif
//#define LV_FS_POSIX_PATH "/home/john/" /*Set the working directory. If commented it will be "./" */
#ifndef LV_USE_FS_FATFS
# ifdef CONFIG_LV_USE_FS_FATFS
# define LV_USE_FS_FATFS CONFIG_LV_USE_FS_FATFS
# else
# define LV_USE_FS_FATFS '\0' /*Uses f_open, f_read, etc*/
# endif
#endif
/*PNG decoder library*/
#ifndef LV_USE_PNG
# ifdef CONFIG_LV_USE_PNG
# define LV_USE_PNG CONFIG_LV_USE_PNG
# else
# define LV_USE_PNG 0
# endif
#endif
/*BMP decoder library*/
#ifndef LV_USE_BMP
# ifdef CONFIG_LV_USE_BMP
# define LV_USE_BMP CONFIG_LV_USE_BMP
# else
# define LV_USE_BMP 0
# endif
#endif
/* JPG + split JPG decoder library.
* Split JPG is a custom format optimized for embedded systems. */
#ifndef LV_USE_SJPG
# ifdef CONFIG_LV_USE_SJPG
# define LV_USE_SJPG CONFIG_LV_USE_SJPG
# else
# define LV_USE_SJPG 0
# endif
#endif
/*GIF decoder library*/
#ifndef LV_USE_GIF
# ifdef CONFIG_LV_USE_GIF
# define LV_USE_GIF CONFIG_LV_USE_GIF
# else
# define LV_USE_GIF 0
# endif
#endif
/*QR code library*/
#ifndef LV_USE_QRCODE
# ifdef CONFIG_LV_USE_QRCODE
# define LV_USE_QRCODE CONFIG_LV_USE_QRCODE
# else
# define LV_USE_QRCODE 0
# endif
#endif
/*FreeType library*/
#ifndef LV_USE_FREETYPE
# ifdef CONFIG_LV_USE_FREETYPE
# define LV_USE_FREETYPE CONFIG_LV_USE_FREETYPE
# else
# define LV_USE_FREETYPE 0
# endif
#endif
#if LV_USE_FREETYPE
/*Memory used by FreeType to cache characters [bytes]*/
#ifndef LV_FREETYPE_CACHE_SIZE
# ifdef CONFIG_LV_FREETYPE_CACHE_SIZE
# define LV_FREETYPE_CACHE_SIZE CONFIG_LV_FREETYPE_CACHE_SIZE
# else
# define LV_FREETYPE_CACHE_SIZE (16 * 1024)
# endif
#endif
#endif
/*==================
* EXAMPLES
*==================*/

View File

@@ -151,6 +151,13 @@ set(LVGL_TEST_OPTIONS_FULL_32BIT
-DLV_LABEL_TEXT_SELECTION=1
-DLV_BUILD_EXAMPLES=1
-DLV_FONT_DEFAULT=&lv_font_montserrat_24
-DLV_USE_FS_STDIO='A'
-DLV_USE_FS_POSIX='B'
-DLV_USE_PNG=1
-DLV_USE_BMP=1
-DLV_USE_SJPG=1
-DLV_USE_GIF=1
-DLV_USE_QRCODE=1
)
set(LVGL_TEST_OPTIONS_TEST