mirror of
https://github.com/lvgl/lvgl.git
synced 2026-05-31 07:56:23 +08:00
perf(GIF): Faster GIF library drop-in replacement (#8743)
Co-authored-by: André <andre_miguel_costa@hotmail.com>
This commit is contained in:
+4
-4
@@ -14,10 +14,6 @@ For the licenses, see the corresponding `LICENSE.txt` file in each library’s f
|
||||
- Source: https://github.com/freetype/freetype
|
||||
- Note: Only the interfaces are used; FreeType itself is not part of LVGL.
|
||||
|
||||
**GifDec (GIF decoder library)**
|
||||
- Path: src/libs/gifdec
|
||||
- Source: https://github.com/lecram/gifdec
|
||||
|
||||
**LodePNG (PNG decoder)**
|
||||
- Path: src/libs/lodepng
|
||||
- Source: https://github.com/lvandeve/lodepng
|
||||
@@ -61,3 +57,7 @@ For the licenses, see the corresponding `LICENSE.txt` file in each library’s f
|
||||
**FT800-FT813 (EVE GPU driver)**
|
||||
- Path src/libs/FT800-FT813
|
||||
- Source: https://github.com/RudolphRiedel/FT800-FT813
|
||||
|
||||
**AnimatedGIF (GIF decoder library)**
|
||||
- Path: src/libs/gif/AnimatedGIF
|
||||
- Source: https://github.com/bitbank2/AnimatedGIF
|
||||
|
||||
@@ -6,8 +6,8 @@ GIF Decoder
|
||||
|
||||
**GIF Decoder** is an LVGL extension that enables you to use GIF images in your LVGL UI.
|
||||
|
||||
For a detailed introduction, see: https://github.com/lecram/gifdec .
|
||||
|
||||
The implementation uses the `AnimatedGIF <https://github.com/bitbank2/AnimatedGIF/tree/master>`__
|
||||
library.
|
||||
|
||||
|
||||
Usage
|
||||
@@ -16,6 +16,22 @@ Usage
|
||||
Once enabled in ``lv_conf.h`` by setting :c:macro:`LV_USE_GIF` to ``1``,
|
||||
:cpp:expr:`lv_gif_create(parent)` can be used to create a gif widget.
|
||||
|
||||
Set the color format of the gif framebuffer with :cpp:expr:`lv_gif_set_color_format(widget, color_format)`.
|
||||
Use :cpp:enumerator:`LV_COLOR_FORMAT_ARGB8888` for gifs with transparency.
|
||||
It is set to :cpp:enumerator:`LV_COLOR_FORMAT_ARGB8888` by default.
|
||||
Significant RAM can be saved by using a smaller color format.
|
||||
A color format conversion can be saved during rendering if the color format matches the display
|
||||
color format.
|
||||
This function can be called before :cpp:func:`lv_gif_set_src` to prevent the initial default ARGB8888
|
||||
framebuffer from being allocated.
|
||||
|
||||
The supported color formats are:
|
||||
|
||||
- :cpp:enumerator:`LV_COLOR_FORMAT_RGB565`
|
||||
- :cpp:enumerator:`LV_COLOR_FORMAT_RGB565_SWAPPED`
|
||||
- :cpp:enumerator:`LV_COLOR_FORMAT_RGB888`
|
||||
- :cpp:enumerator:`LV_COLOR_FORMAT_ARGB8888`
|
||||
|
||||
:cpp:expr:`lv_gif_set_src(widget, src)` works very similarly to :cpp:func:`lv_image_set_src`.
|
||||
As source, it also accepts images as variables (:c:struct:`lv_image_dsc_t`) or files.
|
||||
|
||||
@@ -43,15 +59,12 @@ from files. To do so, follow the instructions in :ref:`file_system`.
|
||||
Memory Requirements
|
||||
*******************
|
||||
|
||||
To decode and display a GIF animation the following amount of RAM (in bytes) is
|
||||
required for each of the following color depths:
|
||||
|
||||
.. |times| unicode:: U+000D7 .. MULTIPLICATION SIGN
|
||||
|
||||
- :c:macro:`LV_COLOR_DEPTH` ``8``: 3 |times| image width |times| image height
|
||||
- :c:macro:`LV_COLOR_DEPTH` ``16``: 4 |times| image width |times| image height
|
||||
- :c:macro:`LV_COLOR_DEPTH` ``32``: 5 |times| image width |times| image height
|
||||
|
||||
To decode and display a GIF animation ~25 kB of RAM is needed plus
|
||||
(color format pixel size + 1) |times| image width |times| image height.
|
||||
RGB565 has a pixel size of 2, RGB888 has a pixel size of 3, and
|
||||
ARGB8888 has a pixel size of 4.
|
||||
|
||||
|
||||
.. _gif_example:
|
||||
|
||||
@@ -10,10 +10,12 @@ void lv_example_gif_1(void)
|
||||
lv_obj_t * img;
|
||||
|
||||
img = lv_gif_create(lv_screen_active());
|
||||
lv_gif_set_color_format(img, LV_COLOR_FORMAT_ARGB8888);
|
||||
lv_gif_set_src(img, &img_bulb_gif);
|
||||
lv_obj_align(img, LV_ALIGN_LEFT_MID, 20, 0);
|
||||
|
||||
img = lv_gif_create(lv_screen_active());
|
||||
lv_gif_set_color_format(img, LV_COLOR_FORMAT_ARGB8888);
|
||||
/* 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");
|
||||
|
||||
@@ -32,7 +32,6 @@ extern "C" {
|
||||
#include "src/others/xml/lv_xml_private.h"
|
||||
#include "src/libs/qrcode/lv_qrcode_private.h"
|
||||
#include "src/libs/barcode/lv_barcode_private.h"
|
||||
#include "src/libs/gif/lv_gif_private.h"
|
||||
#include "src/draw/lv_draw_triangle_private.h"
|
||||
#include "src/draw/lv_draw_private.h"
|
||||
#include "src/draw/lv_draw_rect_private.h"
|
||||
|
||||
@@ -37,8 +37,7 @@
|
||||
--exclude=../src/lv_conf_internal.h
|
||||
--exclude=../src/core/lv_obj_style_gen.c
|
||||
--exclude=../src/core/lv_obj_style_gen.h
|
||||
--exclude=../src/libs/gif/gifdec.c
|
||||
--exclude=../src/libs/gif/gifdec.h
|
||||
--exclude=../src/libs/gif/AnimatedGIF
|
||||
--exclude=../src/libs/lodepng/lodepng.c
|
||||
--exclude=../src/libs/lodepng/lodepng.h
|
||||
--exclude=../src/libs/qrcode/qrcodegen.c
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
Copyright 2020 BitBank Software, Inc. All rights reserved.
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
// Copyright 2020 BitBank Software, Inc. All Rights Reserved.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//===========================================================================
|
||||
|
||||
#ifndef __ANIMATEDGIF__
|
||||
#define __ANIMATEDGIF__
|
||||
|
||||
#include "../../../../misc/lv_fs.h"
|
||||
#include "../../../../lv_conf_internal.h"
|
||||
#include LV_STDINT_INCLUDE
|
||||
#include LV_LIMITS_INCLUDE
|
||||
#include "../../../../stdlib/lv_string.h"
|
||||
|
||||
//
|
||||
// GIF Animator
|
||||
// Written by Larry Bank
|
||||
// Copyright (c) 2020 BitBank Software, Inc.
|
||||
// bitbank@pobox.com
|
||||
//
|
||||
// Designed to decode images up to 480x320 on MCUs
|
||||
// using less than 22K of RAM
|
||||
// ...and decode any sized image when more RAM is available
|
||||
//
|
||||
// ** NEW **
|
||||
// Turbo mode added Feb 18, 2024. This option decodes images
|
||||
// up to 30x faster if there is enough RAM (48K + full framebuffer)
|
||||
//
|
||||
|
||||
/* GIF Defines and variables */
|
||||
#define MAX_CHUNK_SIZE 255
|
||||
//
|
||||
// These 2 macros can be changed to limit the amount of RAM
|
||||
// required by the decoder. For example, decoding 1-bit images to
|
||||
// a 128x32 display will not need a max code size of 12 nor a palette
|
||||
// with 256 entries
|
||||
//
|
||||
#define TURBO_BUFFER_SIZE 0x6100
|
||||
|
||||
// If you intend to decode generic GIFs, you want this value to be 12. If you are using GIFs solely for animations in
|
||||
// your own project, and you control the GIFs you intend to play, then you can save additional RAM here:
|
||||
// the decoder must reserve a minimum of 4 byte * (1<<MAX_CODE_SIZE) for the dictionary, but based on implementation
|
||||
// actually reserves 5 byte * (1<<MAX_CODE_SIZE). Small or low colour GIFs may inherently not require a large
|
||||
// dictionary. For larger GIFs, the en(!)coder can "voluntarily" choose not to utilize the entire dictionary. I.e.,
|
||||
// by preparing (specially encoding) the GIFs, you can save >10kB RAM, but you will not be able to decode arbitrary
|
||||
// images anymore. One application to craft such GIFs can be found here (use option -d)
|
||||
// https://create.stephan-brumme.com/flexigif-lossless-gif-lzw-optimization/
|
||||
#define MAX_CODE_SIZE 12
|
||||
|
||||
#define MAX_COLORS 256
|
||||
#define MAX_WIDTH 480
|
||||
#define LZW_BUF_SIZE (6*MAX_CHUNK_SIZE)
|
||||
#define LZW_HIGHWATER (4*MAX_CHUNK_SIZE)
|
||||
// This buffer is used to store the pixel sequence in reverse order
|
||||
// it needs to be large enough to hold the longest possible
|
||||
// sequence (1<<MAX_CODE_SIZE)
|
||||
#define FILE_BUF_SIZE (1<<MAX_CODE_SIZE)
|
||||
|
||||
#define PIXEL_FIRST 0
|
||||
#define PIXEL_LAST (1<<MAX_CODE_SIZE)
|
||||
#define LINK_UNUSED 5911 // 0x1717 to use memset
|
||||
#define LINK_END 5912
|
||||
#define MAX_HASH 5003
|
||||
// expanded LZW buffer for Turbo mode
|
||||
#define LZW_BUF_SIZE_TURBO (LZW_BUF_SIZE + (2<<MAX_CODE_SIZE) + (PIXEL_LAST*2) + MAX_WIDTH)
|
||||
#define LZW_HIGHWATER_TURBO ((LZW_BUF_SIZE_TURBO * 14) / 16)
|
||||
|
||||
//
|
||||
// Pixel types
|
||||
//
|
||||
enum {
|
||||
GIF_PALETTE_RGB565_LE = 0, // little endian (default)
|
||||
GIF_PALETTE_RGB565_BE, // big endian
|
||||
GIF_PALETTE_RGB888, // original 24-bpp entries
|
||||
GIF_PALETTE_RGB8888, // 32-bit (alpha = 0xff or 0x00)
|
||||
GIF_PALETTE_1BPP, // 1-bit per pixel (horizontal, MSB on left)
|
||||
GIF_PALETTE_1BPP_OLED // 1-bit per pixel (vertical, LSB on top)
|
||||
};
|
||||
// for compatibility with older code
|
||||
#define LITTLE_ENDIAN_PIXELS GIF_PALETTE_RGB565_LE
|
||||
#define BIG_ENDIAN_PIXELS GIF_PALETTE_RGB565_BE
|
||||
//
|
||||
// Draw types
|
||||
//
|
||||
// RAW = 8-bit palettized pixels requiring transparent pixel handling and conversion through the palette.
|
||||
// Each line is sent to the GIFDraw callback as 8-bit pixels. If a framebuffer exists, the lines will be
|
||||
// written there too. The GIFDraw callback is optional if there is a framebuffer allocated.
|
||||
//
|
||||
// COOKED = 16/24/32-bpp fully rendered pixels ready for display. This requires a full frame buffer with extra
|
||||
// room for the fully rendered pixels at the end of the 8-bit pixel buffer. For example, a 160x120
|
||||
// canvas size with 24-bit output would require (160*120 + 3*160) bytes.
|
||||
// Each prepared line is sent to the GIFDraw callback as a row of 16/24/32-bit pixels.
|
||||
//
|
||||
enum {
|
||||
GIF_DRAW_RAW = 0,
|
||||
GIF_DRAW_COOKED
|
||||
};
|
||||
|
||||
enum {
|
||||
GIF_SUCCESS = 0,
|
||||
GIF_DECODE_ERROR,
|
||||
GIF_TOO_WIDE,
|
||||
GIF_INVALID_PARAMETER,
|
||||
GIF_UNSUPPORTED_FEATURE,
|
||||
GIF_FILE_NOT_OPEN,
|
||||
GIF_EARLY_EOF,
|
||||
GIF_EMPTY_FRAME,
|
||||
GIF_BAD_FILE,
|
||||
GIF_ERROR_MEMORY
|
||||
};
|
||||
|
||||
typedef struct gif_file_tag
|
||||
{
|
||||
int32_t iPos; // current file position
|
||||
int32_t iSize; // file size
|
||||
uint8_t *pData; // memory file pointer
|
||||
lv_fs_file_t fHandle; // class pointer to File/SdFat or whatever you want
|
||||
} GIFFILE;
|
||||
|
||||
typedef struct gif_info_tag
|
||||
{
|
||||
int32_t iFrameCount; // total frames in file
|
||||
int32_t iDuration; // duration of animation in milliseconds
|
||||
int32_t iMaxDelay; // maximum frame delay
|
||||
int32_t iMinDelay; // minimum frame delay
|
||||
} GIFINFO;
|
||||
|
||||
typedef struct gif_draw_tag
|
||||
{
|
||||
int iX, iY; // Corner offset of this frame on the canvas
|
||||
int y; // current line being drawn (0 = top line of image)
|
||||
int iWidth, iHeight; // size of this frame
|
||||
int iCanvasWidth; // need this to know where to place output in a fully cooked bitmap
|
||||
void *pUser; // user supplied pointer
|
||||
uint8_t *pPixels; // 8-bit source pixels for this line
|
||||
uint16_t *pPalette; // little or big-endian RGB565 palette entries (default)
|
||||
uint8_t *pPalette24; // RGB888 palette (optional)
|
||||
uint8_t ucTransparent; // transparent color
|
||||
uint8_t ucHasTransparency; // flag indicating the transparent color is in use
|
||||
uint8_t ucDisposalMethod; // frame disposal method
|
||||
uint8_t ucBackground; // background color
|
||||
uint8_t ucPaletteType; // type of palette entries
|
||||
uint8_t ucIsGlobalPalette; // Flag to indicate that a global palette, rather than a local palette is being used
|
||||
} GIFDRAW;
|
||||
|
||||
// Callback function prototypes
|
||||
typedef int32_t (GIF_READ_CALLBACK)(GIFFILE *pFile, uint8_t *pBuf, int32_t iLen);
|
||||
typedef int32_t (GIF_SEEK_CALLBACK)(GIFFILE *pFile, int32_t iPosition);
|
||||
typedef void (GIF_DRAW_CALLBACK)(GIFDRAW *pDraw);
|
||||
typedef void * (GIF_OPEN_CALLBACK)(const char *szFilename, int32_t *pFileSize);
|
||||
typedef void (GIF_CLOSE_CALLBACK)(lv_fs_file_t *pHandle);
|
||||
typedef void * (GIF_ALLOC_CALLBACK)(uint32_t iSize);
|
||||
typedef void (GIF_FREE_CALLBACK)(void *buffer);
|
||||
//
|
||||
// our private structure to hold a GIF image decode state
|
||||
//
|
||||
typedef struct gif_image_tag
|
||||
{
|
||||
uint16_t iWidth, iHeight, iCanvasWidth, iCanvasHeight;
|
||||
uint16_t iX, iY; // GIF corner offset
|
||||
uint16_t iBpp;
|
||||
int16_t iError; // last error
|
||||
uint16_t iFrameDelay; // delay in milliseconds for this frame
|
||||
int16_t iRepeatCount; // NETSCAPE animation repeat count. 0=forever
|
||||
uint16_t iXCount, iYCount; // decoding position in image (countdown values)
|
||||
int iLZWOff; // current LZW data offset
|
||||
int iLZWSize; // current quantity of data in the LZW buffer
|
||||
int iCommentPos; // file offset of start of comment data
|
||||
short sCommentLen; // length of comment
|
||||
unsigned char bEndOfFrame;
|
||||
unsigned char ucGIFBits, ucBackground, ucTransparent, ucCodeStart, ucMap, bUseLocalPalette;
|
||||
unsigned char ucPaletteType; // RGB565 or RGB888
|
||||
unsigned char ucDrawType; // RAW or COOKED
|
||||
GIF_READ_CALLBACK *pfnRead;
|
||||
GIF_SEEK_CALLBACK *pfnSeek;
|
||||
GIF_DRAW_CALLBACK *pfnDraw;
|
||||
GIF_OPEN_CALLBACK *pfnOpen;
|
||||
GIF_CLOSE_CALLBACK *pfnClose;
|
||||
GIFFILE GIFFile;
|
||||
void *pUser;
|
||||
unsigned char *pFrameBuffer;
|
||||
unsigned char *pTurboBuffer;
|
||||
unsigned char *pPixels, *pOldPixels;
|
||||
unsigned char ucFileBuf[FILE_BUF_SIZE]; // holds temp data and pixel stack
|
||||
unsigned short pPalette[(MAX_COLORS * 3)/2]; // can hold RGB565 or RGB888 - set in begin()
|
||||
unsigned short pLocalPalette[(MAX_COLORS * 3)/2]; // color palettes for GIF images
|
||||
unsigned char ucLZW[LZW_BUF_SIZE]; // holds de-chunked LZW data
|
||||
// These next 3 are used in Turbo mode to have a larger ucLZW buffer
|
||||
unsigned short usGIFTable[1<<MAX_CODE_SIZE];
|
||||
unsigned char ucGIFPixels[(PIXEL_LAST*2)];
|
||||
unsigned char ucLineBuf[MAX_WIDTH]; // current line
|
||||
} GIFIMAGE;
|
||||
|
||||
// C interface
|
||||
int GIF_openRAM(GIFIMAGE *pGIF, uint8_t *pData, int iDataSize, GIF_DRAW_CALLBACK *pfnDraw);
|
||||
int GIF_openFile(GIFIMAGE *pGIF, const char *szFilename, GIF_DRAW_CALLBACK *pfnDraw);
|
||||
void GIF_close(GIFIMAGE *pGIF);
|
||||
void GIF_begin(GIFIMAGE *pGIF, unsigned char ucPaletteType);
|
||||
void GIF_reset(GIFIMAGE *pGIF);
|
||||
int GIF_playFrame(GIFIMAGE *pGIF, int *delayMilliseconds, void *pUser);
|
||||
int GIF_getCanvasWidth(GIFIMAGE *pGIF);
|
||||
int GIF_getCanvasHeight(GIFIMAGE *pGIF);
|
||||
int GIF_getComment(GIFIMAGE *pGIF, char *destBuffer);
|
||||
int GIF_getInfo(GIFIMAGE *pGIF, GIFINFO *pInfo);
|
||||
int GIF_getLastError(GIFIMAGE *pGIF);
|
||||
int GIF_getLoopCount(GIFIMAGE *pGIF);
|
||||
|
||||
#define REGISTER_WIDTH 32
|
||||
#ifdef ALLOWS_UNALIGNED
|
||||
#define INTELSHORT(p) (*(uint16_t *)p)
|
||||
#define INTELLONG(p) (*(uint32_t *)p)
|
||||
#else
|
||||
// Due to unaligned memory causing an exception, we have to do these macros the slow way
|
||||
#define INTELSHORT(p) ((*p) + (*(p+1)<<8))
|
||||
#define INTELLONG(p) ((*p) + (*(p+1)<<8) + (*(p+2)<<16) + (*(p+3)<<24))
|
||||
#endif // ALLOWS_UNALIGNED
|
||||
#define BIGINT int32_t
|
||||
#define BIGUINT uint32_t
|
||||
|
||||
#endif // __ANIMATEDGIF__
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,2 +0,0 @@
|
||||
All of the source code and documentation for gifdec is released into the
|
||||
public domain and provided without warranty of any kind.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,71 +0,0 @@
|
||||
#ifndef GIFDEC_H
|
||||
#define GIFDEC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../../misc/lv_fs.h"
|
||||
|
||||
#if LV_USE_GIF
|
||||
#include <stdint.h>
|
||||
|
||||
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;
|
||||
int32_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;
|
||||
#if LV_GIF_CACHE_DECODE_DATA
|
||||
uint8_t *lzw_cache;
|
||||
#endif
|
||||
} 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*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* GIFDEC_H */
|
||||
@@ -1,140 +0,0 @@
|
||||
/**
|
||||
* @file gifdec_mve.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GIFDEC_MVE_H
|
||||
#define GIFDEC_MVE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include <stdint.h>
|
||||
#include "../../misc/lv_color.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#define GIFDEC_FILL_BG(dst, w, h, stride, color, opa) \
|
||||
_gifdec_fill_bg_mve(dst, w, h, stride, color, opa)
|
||||
|
||||
#define GIFDEC_RENDER_FRAME(dst, w, h, stride, frame, pattern, tindex) \
|
||||
_gifdec_render_frame_mve(dst, w, h, stride, frame, pattern, tindex)
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static inline void _gifdec_fill_bg_mve(uint8_t * dst, uint16_t w, uint16_t h, uint16_t stride, uint8_t * color,
|
||||
uint8_t opa)
|
||||
{
|
||||
lv_color32_t c = lv_color32_make(*(color + 0), *(color + 1), *(color + 2), opa);
|
||||
uint32_t color_32 = *(uint32_t *)&c;
|
||||
|
||||
__asm volatile(
|
||||
".p2align 2 \n"
|
||||
"vdup.32 q0, %[src] \n"
|
||||
"3: \n"
|
||||
"mov r0, %[dst] \n"
|
||||
|
||||
"wlstp.32 lr, %[w], 1f \n"
|
||||
"2: \n"
|
||||
|
||||
"vstrw.32 q0, [r0], #16 \n"
|
||||
"letp lr, 2b \n"
|
||||
"1: \n"
|
||||
"add %[dst], %[iTargetStride] \n"
|
||||
"subs %[h], #1 \n"
|
||||
"bne 3b \n"
|
||||
: [dst] "+r"(dst),
|
||||
[h] "+r"(h)
|
||||
: [src] "r"(color_32),
|
||||
[w] "r"(w),
|
||||
[iTargetStride] "r"(stride * sizeof(uint32_t))
|
||||
: "r0", "q0", "memory", "r14", "cc");
|
||||
}
|
||||
|
||||
static inline void _gifdec_render_frame_mve(uint8_t * dst, uint16_t w, uint16_t h, uint16_t stride, uint8_t * frame,
|
||||
uint8_t * pattern, uint16_t tindex)
|
||||
{
|
||||
if(w == 0 || h == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
__asm volatile(
|
||||
"vmov.u16 q3, #255 \n"
|
||||
"vshl.u16 q3, q3, #8 \n" /* left shift 8 for a*/
|
||||
|
||||
"mov r0, #2 \n"
|
||||
"vidup.u16 q6, r0, #4 \n" /* [2, 6, 10, 14, 18, 22, 26, 30] */
|
||||
"mov r0, #0 \n"
|
||||
"vidup.u16 q7, r0, #4 \n" /* [0, 4, 8, 12, 16, 20, 24, 28] */
|
||||
|
||||
"3: \n"
|
||||
"mov r1, %[dst] \n"
|
||||
"mov r2, %[frame] \n"
|
||||
|
||||
"wlstp.16 lr, %[w], 1f \n"
|
||||
"2: \n"
|
||||
|
||||
"mov r0, #3 \n"
|
||||
"vldrb.u16 q4, [r2], #8 \n"
|
||||
"vmul.u16 q5, q4, r0 \n"
|
||||
|
||||
"mov r0, #1 \n"
|
||||
"vldrb.u16 q2, [%[pattern], q5] \n" /* load 8 pixel r*/
|
||||
|
||||
"vadd.u16 q5, q5, r0 \n"
|
||||
"vldrb.u16 q1, [%[pattern], q5] \n" /* load 8 pixel g*/
|
||||
|
||||
"vadd.u16 q5, q5, r0 \n"
|
||||
"vldrb.u16 q0, [%[pattern], q5] \n" /* load 8 pixel b*/
|
||||
|
||||
"vshl.u16 q1, q1, #8 \n" /* left shift 8 for g*/
|
||||
|
||||
"vorr.u16 q0, q0, q1 \n" /* make 8 pixel gb*/
|
||||
"vorr.u16 q1, q2, q3 \n" /* make 8 pixel ar*/
|
||||
|
||||
"vcmp.i16 ne, q4, %[tindex] \n"
|
||||
"vpstt \n"
|
||||
"vstrht.16 q0, [r1, q7] \n"
|
||||
"vstrht.16 q1, [r1, q6] \n"
|
||||
"add r1, r1, #32 \n"
|
||||
|
||||
"letp lr, 2b \n"
|
||||
|
||||
"1: \n"
|
||||
"mov r0, %[stride], LSL #2 \n"
|
||||
"add %[dst], r0 \n"
|
||||
"add %[frame], %[stride] \n"
|
||||
"subs %[h], #1 \n"
|
||||
"bne 3b \n"
|
||||
|
||||
: [dst] "+r"(dst),
|
||||
[frame] "+r"(frame),
|
||||
[h] "+r"(h)
|
||||
: [pattern] "r"(pattern),
|
||||
[w] "r"(w),
|
||||
[stride] "r"(stride),
|
||||
[tindex] "r"(tindex)
|
||||
: "r0", "r1", "r2", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "memory", "r14", "cc");
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*GIFDEC_MVE_H*/
|
||||
+154
-57
@@ -6,13 +6,13 @@
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_gif_private.h"
|
||||
#include "lv_gif.h"
|
||||
#if LV_USE_GIF
|
||||
#include "../../misc/lv_timer_private.h"
|
||||
#include "../../misc/cache/lv_cache.h"
|
||||
#include "../../core/lv_obj_class_private.h"
|
||||
|
||||
#include "gifdec.h"
|
||||
#include "../../widgets/image/lv_image_private.h"
|
||||
#include "AnimatedGIF/src/AnimatedGIF.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
@@ -23,11 +23,26 @@
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/* the type of the AnimatedGIF pallete type passed to `GIF_begin` */
|
||||
typedef unsigned char animatedgif_color_format_t;
|
||||
|
||||
typedef struct {
|
||||
lv_image_t img;
|
||||
GIFIMAGE gif;
|
||||
const void * src;
|
||||
lv_color_format_t color_format;
|
||||
lv_timer_t * timer;
|
||||
lv_image_dsc_t imgdsc;
|
||||
int32_t loop_count;
|
||||
uint32_t is_open : 1;
|
||||
} lv_gif_t;
|
||||
|
||||
/**********************
|
||||
* 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 initialize(lv_gif_t * gifobj);
|
||||
static void next_frame_task_cb(lv_timer_t * t);
|
||||
|
||||
/**********************
|
||||
@@ -59,63 +74,52 @@ lv_obj_t * lv_gif_create(lv_obj_t * parent)
|
||||
return obj;
|
||||
}
|
||||
|
||||
void lv_gif_set_src(lv_obj_t * obj, const void * src)
|
||||
void lv_gif_set_color_format(lv_obj_t * obj, lv_color_format_t color_format)
|
||||
{
|
||||
lv_gif_t * gifobj = (lv_gif_t *) obj;
|
||||
gd_GIF * gif = gifobj->gif;
|
||||
|
||||
/*Close previous gif if any*/
|
||||
if(gif != NULL) {
|
||||
lv_image_cache_drop(lv_image_get_src(obj));
|
||||
|
||||
gd_close_gif(gif);
|
||||
gifobj->gif = NULL;
|
||||
gifobj->imgdsc.data = NULL;
|
||||
}
|
||||
|
||||
if(lv_image_src_get_type(src) == LV_IMAGE_SRC_VARIABLE) {
|
||||
const lv_image_dsc_t * img_dsc = src;
|
||||
gif = gd_open_gif_data(img_dsc->data);
|
||||
}
|
||||
else if(lv_image_src_get_type(src) == LV_IMAGE_SRC_FILE) {
|
||||
gif = gd_open_gif_file(src);
|
||||
}
|
||||
if(gif == NULL) {
|
||||
LV_LOG_WARN("Couldn't load the source");
|
||||
if(gifobj->color_format == color_format) {
|
||||
return;
|
||||
}
|
||||
|
||||
gifobj->gif = gif;
|
||||
gifobj->imgdsc.data = gif->canvas;
|
||||
gifobj->imgdsc.header.magic = LV_IMAGE_HEADER_MAGIC;
|
||||
gifobj->imgdsc.header.flags = LV_IMAGE_FLAGS_MODIFIABLE;
|
||||
gifobj->imgdsc.header.cf = LV_COLOR_FORMAT_ARGB8888;
|
||||
gifobj->imgdsc.header.h = gif->height;
|
||||
gifobj->imgdsc.header.w = gif->width;
|
||||
gifobj->imgdsc.header.stride = gif->width * 4;
|
||||
gifobj->imgdsc.data_size = gif->width * gif->height * 4;
|
||||
switch(color_format) {
|
||||
case LV_COLOR_FORMAT_RGB565:
|
||||
case LV_COLOR_FORMAT_RGB565_SWAPPED:
|
||||
case LV_COLOR_FORMAT_RGB888:
|
||||
case LV_COLOR_FORMAT_ARGB8888:
|
||||
break;
|
||||
default:
|
||||
LV_LOG_WARN("gif widget does not support this color format");
|
||||
return;
|
||||
}
|
||||
|
||||
gifobj->last_call = lv_tick_get();
|
||||
gifobj->color_format = color_format;
|
||||
|
||||
lv_image_set_src(obj, &gifobj->imgdsc);
|
||||
if(gifobj->src != NULL) {
|
||||
initialize(gifobj);
|
||||
}
|
||||
}
|
||||
|
||||
lv_timer_resume(gifobj->timer);
|
||||
lv_timer_reset(gifobj->timer);
|
||||
void lv_gif_set_src(lv_obj_t * obj, const void * src)
|
||||
{
|
||||
lv_gif_t * gifobj = (lv_gif_t *) obj;
|
||||
|
||||
next_frame_task_cb(gifobj->timer);
|
||||
gifobj->src = src;
|
||||
|
||||
initialize(gifobj);
|
||||
}
|
||||
|
||||
void lv_gif_restart(lv_obj_t * obj)
|
||||
{
|
||||
lv_gif_t * gifobj = (lv_gif_t *) obj;
|
||||
|
||||
if(gifobj->gif == NULL) {
|
||||
if(!gifobj->is_open) {
|
||||
LV_LOG_WARN("Gif resource not loaded correctly");
|
||||
return;
|
||||
}
|
||||
|
||||
gd_rewind(gifobj->gif);
|
||||
GIF_reset(&gifobj->gif);
|
||||
gifobj->loop_count = -1; /* match the behavior of the old library */
|
||||
lv_timer_resume(gifobj->timer);
|
||||
lv_timer_reset(gifobj->timer);
|
||||
}
|
||||
@@ -130,7 +134,7 @@ void lv_gif_resume(lv_obj_t * obj)
|
||||
{
|
||||
lv_gif_t * gifobj = (lv_gif_t *) obj;
|
||||
|
||||
if(gifobj->gif == NULL) {
|
||||
if(!gifobj->is_open) {
|
||||
LV_LOG_WARN("Gif resource not loaded correctly");
|
||||
return;
|
||||
}
|
||||
@@ -142,30 +146,30 @@ bool lv_gif_is_loaded(lv_obj_t * obj)
|
||||
{
|
||||
lv_gif_t * gifobj = (lv_gif_t *) obj;
|
||||
|
||||
return (gifobj->gif != NULL);
|
||||
return gifobj->is_open;
|
||||
}
|
||||
|
||||
int32_t lv_gif_get_loop_count(lv_obj_t * obj)
|
||||
{
|
||||
lv_gif_t * gifobj = (lv_gif_t *) obj;
|
||||
|
||||
if(gifobj->gif == NULL) {
|
||||
if(!gifobj->is_open) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return gifobj->gif->loop_count;
|
||||
return gifobj->loop_count;
|
||||
}
|
||||
|
||||
void lv_gif_set_loop_count(lv_obj_t * obj, int32_t count)
|
||||
{
|
||||
lv_gif_t * gifobj = (lv_gif_t *) obj;
|
||||
|
||||
if(gifobj->gif == NULL) {
|
||||
if(!gifobj->is_open) {
|
||||
LV_LOG_WARN("Gif resource not loaded correctly");
|
||||
return;
|
||||
}
|
||||
|
||||
gifobj->gif->loop_count = count;
|
||||
gifobj->loop_count = count;
|
||||
}
|
||||
|
||||
/**********************
|
||||
@@ -178,7 +182,8 @@ static void lv_gif_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
|
||||
|
||||
lv_gif_t * gifobj = (lv_gif_t *) obj;
|
||||
|
||||
gifobj->gif = NULL;
|
||||
gifobj->color_format = LV_COLOR_FORMAT_ARGB8888;
|
||||
gifobj->is_open = 0;
|
||||
gifobj->timer = lv_timer_create(next_frame_task_cb, 10, obj);
|
||||
lv_timer_pause(gifobj->timer);
|
||||
}
|
||||
@@ -190,29 +195,121 @@ static void lv_gif_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
|
||||
|
||||
lv_image_cache_drop(lv_image_get_src(obj));
|
||||
|
||||
if(gifobj->gif)
|
||||
gd_close_gif(gifobj->gif);
|
||||
if(gifobj->is_open) {
|
||||
void * framebuffer = gifobj->gif.pFrameBuffer;
|
||||
GIF_close(&gifobj->gif);
|
||||
lv_free(framebuffer);
|
||||
}
|
||||
lv_timer_delete(gifobj->timer);
|
||||
}
|
||||
|
||||
static void initialize(lv_gif_t * gifobj)
|
||||
{
|
||||
GIFIMAGE * gif = &gifobj->gif;
|
||||
|
||||
/*Close previous gif if any*/
|
||||
if(gifobj->is_open) {
|
||||
lv_image_cache_drop(lv_image_get_src((lv_obj_t *) gifobj));
|
||||
|
||||
void * framebuffer = gif->pFrameBuffer;
|
||||
GIF_close(gif);
|
||||
lv_free(framebuffer);
|
||||
gifobj->is_open = 0;
|
||||
gifobj->imgdsc.data = NULL;
|
||||
}
|
||||
|
||||
animatedgif_color_format_t decoder_cf;
|
||||
uint32_t pixel_size_bytes;
|
||||
switch(gifobj->color_format) {
|
||||
case LV_COLOR_FORMAT_RGB565:
|
||||
decoder_cf = GIF_PALETTE_RGB565_LE;
|
||||
pixel_size_bytes = 2;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_RGB565_SWAPPED:
|
||||
decoder_cf = GIF_PALETTE_RGB565_BE;
|
||||
pixel_size_bytes = 2;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_RGB888:
|
||||
decoder_cf = GIF_PALETTE_RGB888;
|
||||
pixel_size_bytes = 3;
|
||||
break;
|
||||
case LV_COLOR_FORMAT_ARGB8888:
|
||||
decoder_cf = GIF_PALETTE_RGB8888;
|
||||
pixel_size_bytes = 4;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
GIF_begin(gif, decoder_cf);
|
||||
|
||||
if(lv_image_src_get_type(gifobj->src) == LV_IMAGE_SRC_VARIABLE) {
|
||||
const lv_image_dsc_t * img_dsc = gifobj->src;
|
||||
gifobj->is_open = GIF_openRAM(gif, (uint8_t *) img_dsc->data, img_dsc->data_size, NULL);
|
||||
}
|
||||
else if(lv_image_src_get_type(gifobj->src) == LV_IMAGE_SRC_FILE) {
|
||||
gifobj->is_open = GIF_openFile(gif, gifobj->src, NULL);
|
||||
}
|
||||
if(gifobj->is_open == 0) {
|
||||
LV_LOG_WARN("Couldn't load the source");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t width = GIF_getCanvasWidth(gif);
|
||||
uint32_t height = GIF_getCanvasHeight(gif);
|
||||
gif->pFrameBuffer = lv_malloc(width * height * (pixel_size_bytes + 1));
|
||||
gif->ucDrawType = GIF_DRAW_COOKED;
|
||||
LV_ASSERT_MALLOC(gif->pFrameBuffer);
|
||||
if(gif->pFrameBuffer == NULL) {
|
||||
LV_LOG_WARN("Couldn't allocate a buffer for a GIF");
|
||||
GIF_close(gif);
|
||||
gifobj->is_open = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
gifobj->imgdsc.data = gif->pFrameBuffer + width * height;
|
||||
gifobj->imgdsc.header.magic = LV_IMAGE_HEADER_MAGIC;
|
||||
gifobj->imgdsc.header.flags = LV_IMAGE_FLAGS_MODIFIABLE;
|
||||
gifobj->imgdsc.header.cf = gifobj->color_format;
|
||||
gifobj->imgdsc.header.h = height;
|
||||
gifobj->imgdsc.header.w = width;
|
||||
gifobj->imgdsc.header.stride = width * pixel_size_bytes;
|
||||
gifobj->imgdsc.data_size = width * height * pixel_size_bytes;
|
||||
|
||||
lv_image_set_src((lv_obj_t *) gifobj, &gifobj->imgdsc);
|
||||
|
||||
gifobj->loop_count = GIF_getLoopCount(&gifobj->gif);
|
||||
|
||||
lv_timer_resume(gifobj->timer);
|
||||
lv_timer_reset(gifobj->timer);
|
||||
|
||||
next_frame_task_cb(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) {
|
||||
int ms_delay_next;
|
||||
int has_next = GIF_playFrame(&gifobj->gif, &ms_delay_next, gifobj);
|
||||
if(has_next <= 0) {
|
||||
/*It was the last repeat*/
|
||||
lv_result_t res = lv_obj_send_event(obj, LV_EVENT_READY, NULL);
|
||||
lv_timer_pause(t);
|
||||
if(gifobj->loop_count > 0) {
|
||||
if(gifobj->loop_count == 1) {
|
||||
lv_timer_pause(t);
|
||||
}
|
||||
else {
|
||||
gifobj->loop_count--;
|
||||
}
|
||||
}
|
||||
if(res != LV_RESULT_OK) return;
|
||||
}
|
||||
|
||||
gd_render_frame(gifobj->gif, (uint8_t *)gifobj->imgdsc.data);
|
||||
else {
|
||||
lv_timer_set_period(gifobj->timer, ms_delay_next);
|
||||
}
|
||||
|
||||
lv_image_cache_drop(lv_image_get_src(obj));
|
||||
lv_obj_invalidate(obj);
|
||||
|
||||
+10
-4
@@ -16,14 +16,11 @@ extern "C" {
|
||||
|
||||
#include "../../lv_conf_internal.h"
|
||||
#include "../../misc/lv_types.h"
|
||||
#include "../../draw/lv_draw_buf.h"
|
||||
#include "../../widgets/image/lv_image.h"
|
||||
#include "../../core/lv_obj_class.h"
|
||||
#include LV_STDBOOL_INCLUDE
|
||||
#include LV_STDINT_INCLUDE
|
||||
#if LV_USE_GIF
|
||||
|
||||
#include "gifdec.h"
|
||||
#include "../../misc/lv_color.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
@@ -46,6 +43,15 @@ LV_ATTRIBUTE_EXTERN_DATA extern const lv_obj_class_t lv_gif_class;
|
||||
*/
|
||||
lv_obj_t * lv_gif_create(lv_obj_t * parent);
|
||||
|
||||
/**
|
||||
* Set the color format of the internally allocated framebuffer that the gif
|
||||
* will be decoded to. The default is LV_COLOR_FORMAT_ARGB8888.
|
||||
* Call this before `lv_gif_set_src` to avoid reallocating the framebuffer.
|
||||
* @param obj pointer to a gif object
|
||||
* @param color_format the color format of the gif framebuffer
|
||||
*/
|
||||
void lv_gif_set_color_format(lv_obj_t * obj, lv_color_format_t color_format);
|
||||
|
||||
/**
|
||||
* Set the gif data to display on the object
|
||||
* @param obj pointer to a gif object
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
/**
|
||||
* @file lv_gif_private.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_GIF_PRIVATE_H
|
||||
#define LV_GIF_PRIVATE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../widgets/image/lv_image_private.h"
|
||||
#include "lv_gif.h"
|
||||
|
||||
#if LV_USE_GIF
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
struct _lv_gif_t {
|
||||
lv_image_t img;
|
||||
gd_GIF * gif;
|
||||
lv_timer_t * timer;
|
||||
lv_image_dsc_t imgdsc;
|
||||
uint32_t last_call;
|
||||
};
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /* LV_USE_GIF */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_GIF_PRIVATE_H*/
|
||||
@@ -292,8 +292,6 @@ typedef struct _lv_file_explorer_t lv_file_explorer_t;
|
||||
|
||||
typedef struct _lv_barcode_t lv_barcode_t;
|
||||
|
||||
typedef struct _lv_gif_t lv_gif_t;
|
||||
|
||||
typedef struct _lv_qrcode_t lv_qrcode_t;
|
||||
|
||||
typedef struct _lv_freetype_outline_vector_t lv_freetype_outline_vector_t;
|
||||
|
||||
@@ -522,6 +522,7 @@ def run_tests(
|
||||
lvgl_src_dir = os.path.join(lvgl_test_dir, "..", "src")
|
||||
lv_conf_path = os.path.join(lvgl_test_dir, "src", lv_conf_name)
|
||||
lvgl_h_path = os.path.join(lvgl_test_dir, "..", "lvgl.h")
|
||||
lvgl_private_h_path = os.path.join(lvgl_test_dir, "..", "lvgl_private.h")
|
||||
commands_ini_path = os.path.join(build_dir, "commands.ini")
|
||||
docker_image_name = perf_test_options[options_name]["image_name"]
|
||||
|
||||
@@ -533,6 +534,7 @@ def run_tests(
|
||||
volume(lvgl_src_dir, so3_usr_lib("lvgl/src")),
|
||||
volume(lv_conf_path, so3_usr_lib("lv_conf.h")),
|
||||
volume(lvgl_h_path, so3_usr_lib("lvgl/lvgl.h")),
|
||||
volume(lvgl_private_h_path, so3_usr_lib("lvgl/lvgl_private.h")),
|
||||
# We also need to add the current "lvgl.h" and mount it in the correct path
|
||||
# As there's a `#include "../../lvgl.h"` in the `unity_support.h` file
|
||||
volume(lvgl_h_path, "/so3/usr/lvgl.h"),
|
||||
|
||||
Reference in New Issue
Block a user