From a8df7f04f5ffab5bb3ea8fd36c11086dbdac5b58 Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Sun, 4 Oct 2026 13:28:52 +0200 Subject: [PATCH 1/5] On-device icon font generation --- CMakeLists.txt | 1 + .../fonts/MaterialSymbolsRounded.codepoints | 69 + Data/system/fonts/MaterialSymbolsRounded.ttf | Bin 0 -> 15972 bytes Modules/binfont-module/CMakeLists.txt | 17 + Modules/binfont-module/LICENSE-Apache-2.0.md | 195 + Modules/binfont-module/README.md | 14 + .../binfont-module/include/binfont/binfont.h | 104 + .../include/binfont/generator.h | 40 + .../binfont-module/include/binfont/module.h | 14 + .../binfont-module/include/binfont/render.h | 57 + Modules/binfont-module/private/stb_truetype.h | 5079 +++++++++++++++++ Modules/binfont-module/source/binfont.cpp | 718 +++ Modules/binfont-module/source/generator.cpp | 443 ++ Modules/binfont-module/source/module.c | 31 + Modules/binfont-module/source/render.cpp | 121 + Modules/binfont-module/tests/CMakeLists.txt | 22 + .../tests/fixtures/icons_raw_2.bin | Bin 0 -> 548 bytes .../tests/fixtures/icons_raw_4.bin | Bin 0 -> 960 bytes .../tests/fixtures/icons_rle_2.bin | Bin 0 -> 468 bytes .../tests/fixtures/icons_rle_4.bin | Bin 0 -> 704 bytes .../tests/fixtures/icons_rlepf_2.bin | Bin 0 -> 464 bytes .../tests/fixtures/icons_rlepf_4.bin | Bin 0 -> 720 bytes .../tests/fixtures/text_kern_classes.bin | Bin 0 -> 3600 bytes .../tests/fixtures/text_kern_pairs.bin | Bin 0 -> 3460 bytes .../tests/source/binfont_test.cpp | 286 + Modules/binfont-module/tests/source/main.cpp | 64 + Modules/lvgl-module/CMakeLists.txt | 10 +- Modules/lvgl-module/README.md | 4 +- Modules/lvgl-module/generate-icons.py | 138 +- Modules/lvgl-module/include/lvgl/binfont.h | 24 + Modules/lvgl-module/include/lvgl/fonts.h | 13 + .../lvgl-module/include/lvgl/icons/names.h | 26 + .../material_symbols_launcher_30.c | 176 - .../material_symbols_launcher_36.c | 194 - .../material_symbols_launcher_42.c | 220 - .../material_symbols_launcher_48.c | 246 - .../material_symbols_launcher_64.c | 348 -- .../material_symbols_launcher_72.c | 397 -- .../source-fonts/material_symbols_shared_12.c | 415 -- .../source-fonts/material_symbols_shared_16.c | 521 -- .../source-fonts/material_symbols_shared_20.c | 644 --- .../source-fonts/material_symbols_shared_24.c | 748 --- .../source-fonts/material_symbols_shared_32.c | 1158 ---- .../source-fonts/material_symbols_shared_40.c | 1632 ------ .../source-fonts/material_symbols_shared_48.c | 2130 ------- .../source-fonts/material_symbols_shared_64.c | 3653 ------------ .../material_symbols_statusbar_12.c | 280 - .../material_symbols_statusbar_16.c | 326 -- .../material_symbols_statusbar_20.c | 394 -- .../material_symbols_statusbar_30.c | 612 -- Modules/lvgl-module/source/binfont.c | 72 + Modules/lvgl-module/source/fonts.c | 22 +- Modules/lvgl-module/source/icon_names.c | 95 + Modules/lvgl-module/source/symbols.c | 4 + Tactility/CMakeLists.txt | 1 + Tactility/Private/Tactility/lvgl/IconFonts.h | 12 + Tactility/Source/Tactility.cpp | 5 + Tactility/Source/lvgl/IconFonts.cpp | 188 + Tests/CMakeLists.txt | 2 + 59 files changed, 7821 insertions(+), 14164 deletions(-) create mode 100644 Data/system/fonts/MaterialSymbolsRounded.codepoints create mode 100644 Data/system/fonts/MaterialSymbolsRounded.ttf create mode 100644 Modules/binfont-module/CMakeLists.txt create mode 100644 Modules/binfont-module/LICENSE-Apache-2.0.md create mode 100644 Modules/binfont-module/README.md create mode 100644 Modules/binfont-module/include/binfont/binfont.h create mode 100644 Modules/binfont-module/include/binfont/generator.h create mode 100644 Modules/binfont-module/include/binfont/module.h create mode 100644 Modules/binfont-module/include/binfont/render.h create mode 100644 Modules/binfont-module/private/stb_truetype.h create mode 100644 Modules/binfont-module/source/binfont.cpp create mode 100644 Modules/binfont-module/source/generator.cpp create mode 100644 Modules/binfont-module/source/module.c create mode 100644 Modules/binfont-module/source/render.cpp create mode 100644 Modules/binfont-module/tests/CMakeLists.txt create mode 100644 Modules/binfont-module/tests/fixtures/icons_raw_2.bin create mode 100644 Modules/binfont-module/tests/fixtures/icons_raw_4.bin create mode 100644 Modules/binfont-module/tests/fixtures/icons_rle_2.bin create mode 100644 Modules/binfont-module/tests/fixtures/icons_rle_4.bin create mode 100644 Modules/binfont-module/tests/fixtures/icons_rlepf_2.bin create mode 100644 Modules/binfont-module/tests/fixtures/icons_rlepf_4.bin create mode 100644 Modules/binfont-module/tests/fixtures/text_kern_classes.bin create mode 100644 Modules/binfont-module/tests/fixtures/text_kern_pairs.bin create mode 100644 Modules/binfont-module/tests/source/binfont_test.cpp create mode 100644 Modules/binfont-module/tests/source/main.cpp create mode 100644 Modules/lvgl-module/include/lvgl/binfont.h create mode 100644 Modules/lvgl-module/include/lvgl/icons/names.h delete mode 100644 Modules/lvgl-module/source-fonts/material_symbols_launcher_30.c delete mode 100644 Modules/lvgl-module/source-fonts/material_symbols_launcher_36.c delete mode 100644 Modules/lvgl-module/source-fonts/material_symbols_launcher_42.c delete mode 100644 Modules/lvgl-module/source-fonts/material_symbols_launcher_48.c delete mode 100644 Modules/lvgl-module/source-fonts/material_symbols_launcher_64.c delete mode 100644 Modules/lvgl-module/source-fonts/material_symbols_launcher_72.c delete mode 100644 Modules/lvgl-module/source-fonts/material_symbols_shared_12.c delete mode 100644 Modules/lvgl-module/source-fonts/material_symbols_shared_16.c delete mode 100644 Modules/lvgl-module/source-fonts/material_symbols_shared_20.c delete mode 100644 Modules/lvgl-module/source-fonts/material_symbols_shared_24.c delete mode 100644 Modules/lvgl-module/source-fonts/material_symbols_shared_32.c delete mode 100644 Modules/lvgl-module/source-fonts/material_symbols_shared_40.c delete mode 100644 Modules/lvgl-module/source-fonts/material_symbols_shared_48.c delete mode 100644 Modules/lvgl-module/source-fonts/material_symbols_shared_64.c delete mode 100644 Modules/lvgl-module/source-fonts/material_symbols_statusbar_12.c delete mode 100644 Modules/lvgl-module/source-fonts/material_symbols_statusbar_16.c delete mode 100644 Modules/lvgl-module/source-fonts/material_symbols_statusbar_20.c delete mode 100644 Modules/lvgl-module/source-fonts/material_symbols_statusbar_30.c create mode 100644 Modules/lvgl-module/source/binfont.c create mode 100644 Modules/lvgl-module/source/icon_names.c create mode 100644 Tactility/Private/Tactility/lvgl/IconFonts.h create mode 100644 Tactility/Source/lvgl/IconFonts.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f1fc9fa75..f5e337a3e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -170,6 +170,7 @@ if (NOT DEFINED ENV{ESP_IDF_VERSION}) add_subdirectory(Libraries/minmea) add_subdirectory(Modules/lvgl-module) add_subdirectory(Modules/audio-decoder-module) + add_subdirectory(Modules/binfont-module) add_subdirectory(Modules/c-symbols-module) add_subdirectory(Modules/cjson-module) add_subdirectory(Modules/cpp-symbols-module) diff --git a/Data/system/fonts/MaterialSymbolsRounded.codepoints b/Data/system/fonts/MaterialSymbolsRounded.codepoints new file mode 100644 index 000000000..19433809a --- /dev/null +++ b/Data/system/fonts/MaterialSymbolsRounded.codepoints @@ -0,0 +1,69 @@ +add e145 +app_registration ef40 +apps e5c3 +area_chart e770 +battery_android_frame_1 f257 +battery_android_frame_2 f256 +battery_android_frame_3 f255 +battery_android_frame_4 f254 +battery_android_frame_5 f253 +battery_android_frame_6 f252 +battery_android_frame_bolt f250 +battery_android_frame_full f24f +bluetooth e1a7 +bluetooth_connected e1a8 +bluetooth_disabled e1a9 +bluetooth_searching e60f +cable efe6 +calendar_month ebcc +camera e3af +check e668 +circle ef4a +close e5cd +cloud f15c +delete e92e +deployed_code f720 +devices e326 +display_settings eb97 +download f090 +edit_note e745 +electric_bolt ec1c +folder e2c7 +forum e8af +gamepad e30f +help e8fd +hub e9f4 +image e3f4 +keyboard_alt f028 +keyboard_arrow_up e316 +language ea07 +lightbulb e90f +lightstrip fff75 +lists e9b9 +location_on f1db +logo_dev ead6 +mail e159 +memory e322 +menu e5d2 +mop e28d +more_vert e5d4 +music_note e405 +navigation e55d +network_wifi_1_bar ebe4 +network_wifi_2_bar ebd6 +network_wifi_3_bar ebe1 +note_add e89c +power_settings_new f8c7 +refresh e5d5 +sd_card e623 +sd_card_alert f057 +search ef7a +settings e8b8 +signal_wifi_0_bar f0b0 +signal_wifi_4_bar f065 +signal_wifi_bad f064 +signal_wifi_off e1da +terminal eb8e +toolbar e9f7 +usb e1e0 +wifi e63e diff --git a/Data/system/fonts/MaterialSymbolsRounded.ttf b/Data/system/fonts/MaterialSymbolsRounded.ttf new file mode 100644 index 0000000000000000000000000000000000000000..3be21646dd62c697c06187b44fdd1f1b4e63574c GIT binary patch literal 15972 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 BaVY=* literal 0 HcmV?d00001 diff --git a/Modules/binfont-module/CMakeLists.txt b/Modules/binfont-module/CMakeLists.txt new file mode 100644 index 000000000..c68445826 --- /dev/null +++ b/Modules/binfont-module/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.20) + +include("${CMAKE_CURRENT_LIST_DIR}/../../Buildscripts/module.cmake") + +file(GLOB_RECURSE SOURCE_FILES "source/*.c*") + +list(APPEND REQUIRES_LIST + TactilityKernel + graphics-module +) + +tactility_add_module(binfont-module + SRCS ${SOURCE_FILES} + INCLUDE_DIRS include/ + PRIV_INCLUDE_DIRS private/ + REQUIRES ${REQUIRES_LIST} +) diff --git a/Modules/binfont-module/LICENSE-Apache-2.0.md b/Modules/binfont-module/LICENSE-Apache-2.0.md new file mode 100644 index 000000000..f5f4b8b5e --- /dev/null +++ b/Modules/binfont-module/LICENSE-Apache-2.0.md @@ -0,0 +1,195 @@ +Apache License +============== + +_Version 2.0, January 2004_ +_<>_ + +### 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. + diff --git a/Modules/binfont-module/README.md b/Modules/binfont-module/README.md new file mode 100644 index 000000000..600974d6b --- /dev/null +++ b/Modules/binfont-module/README.md @@ -0,0 +1,14 @@ +# binfont-module + +Bitmap fonts in the [lv_font_conv](https://github.com/lvgl/lv_font_conv) binary format (`--format bin`), usable with and without LVGL. + +- ``: load fonts and decode glyphs +- ``: rasterize a TTF into the binary format on device +- ``: draw glyphs and text into a `PixelBuffer` + +For LVGL, see `lvgl_binfont_create()` in lvgl-module's ``. + +## License + +This module is licensed under the [Apache v2.0](LICENSE-Apache-2.0.md) license. +Uses [stb_truetype](https://github.com/nothings/stb) (public domain). diff --git a/Modules/binfont-module/include/binfont/binfont.h b/Modules/binfont-module/include/binfont/binfont.h new file mode 100644 index 000000000..413e14989 --- /dev/null +++ b/Modules/binfont-module/include/binfont/binfont.h @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#include + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * A bitmap font in the lv_font_conv binary format (lv_font_conv --format bin). + * Thread-safe: a font can be used from multiple tasks at the same time. + */ +struct BinFont; + +typedef struct BinFontMetrics { + /** Font size in pixels, as passed to the converter */ + uint16_t size; + /** Pixels above the baseline */ + int16_t ascent; + /** Pixels below the baseline (negative) */ + int16_t descent; + /** ascent - descent */ + uint16_t line_height; + /** Distance from the bottom of the line to the baseline (-descent) */ + int16_t base_line; + int16_t underline_position; + uint16_t underline_thickness; + /** Bits per pixel of the stored bitmaps (1-4) */ + uint8_t bpp; +} BinFontMetrics; + +typedef struct BinFontGlyph { + uint32_t glyph_id; + /** Horizontal advance in 1/16th pixels */ + uint32_t advance_x16; + /** Bounding box left, relative to the pen position */ + int16_t x; + /** Bounding box bottom, relative to the baseline (positive is up) */ + int16_t y; + uint16_t width; + uint16_t height; +} BinFontGlyph; + +/** + * @brief Opens a font file. + * The whole file is loaded into external memory (PSRAM) when available. Otherwise only the lookup + * tables are loaded and glyph data is read from the file on demand. + * @param[in] path the file path + * @param[out] out the opened font + * @retval ERROR_NONE on success + * @retval ERROR_NOT_FOUND when the file can't be opened + * @retval ERROR_NOT_SUPPORTED when the file is not a valid or supported font + * @retval ERROR_OUT_OF_MEMORY when memory allocation failed + */ +error_t binfont_open_file(const char* path, struct BinFont** out); + +/** + * @brief Opens a font from memory. + * @param[in] data the font file contents, which must stay valid until binfont_close() + * @param[in] size the size of data in bytes + * @param[in] take_ownership when true, data is released with memory_free() by binfont_close() (also on failure) + * @param[out] out the opened font + * @retval ERROR_NONE on success + * @retval ERROR_NOT_SUPPORTED when the data is not a valid or supported font + * @retval ERROR_OUT_OF_MEMORY when memory allocation failed + */ +error_t binfont_open_memory(const void* data, size_t size, bool take_ownership, struct BinFont** out); + +/** Releases the font and all its resources. */ +void binfont_close(struct BinFont* font); + +void binfont_get_metrics(const struct BinFont* font, BinFontMetrics* out); + +/** + * @param[in] font the font + * @param[in] codepoint the Unicode codepoint + * @param[out] out the glyph info + * @return false when the font has no glyph for this codepoint + */ +bool binfont_get_glyph(struct BinFont* font, uint32_t codepoint, BinFontGlyph* out); + +/** @return the kerning adjustment for a glyph pair in 1/16th pixels, or 0 when there is none */ +int32_t binfont_get_kerning_x16(struct BinFont* font, uint32_t left_glyph_id, uint32_t right_glyph_id); + +/** + * @brief Decodes a glyph bitmap as 8-bit alpha (0 = transparent, 255 = opaque). + * @param[in] font the font + * @param[in] glyph a glyph from binfont_get_glyph() + * @param[out] out the destination: glyph->height rows of glyph->width bytes + * @param[in] stride bytes per row in out (at least glyph->width) + * @retval ERROR_NONE on success + * @retval ERROR_INVALID_ARGUMENT when stride is too small + * @retval ERROR_RESOURCE when the glyph data can't be read + */ +error_t binfont_get_glyph_bitmap(struct BinFont* font, const BinFontGlyph* glyph, uint8_t* out, size_t stride); + +#ifdef __cplusplus +} +#endif diff --git a/Modules/binfont-module/include/binfont/generator.h b/Modules/binfont-module/include/binfont/generator.h new file mode 100644 index 000000000..f25fc2a64 --- /dev/null +++ b/Modules/binfont-module/include/binfont/generator.h @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct BinFontGeneratorConfig { + /** Path to a TrueType (.ttf) file */ + const char* ttf_path; + /** Font size in pixels (em height) */ + uint16_t size; + /** Bits per pixel: 1, 2, 3 or 4 */ + uint8_t bpp; + /** Codepoints to include. Codepoints that the TTF doesn't contain are skipped. */ + const uint32_t* codepoints; + size_t codepoint_count; +} BinFontGeneratorConfig; + +/** + * @brief Rasterizes a TrueType font into the lv_font_conv binary format. + * @param[in] config the generator configuration + * @param[out] out_data the generated font file contents, to be released with memory_free() + * @param[out] out_size the size of out_data in bytes + * @retval ERROR_NONE on success + * @retval ERROR_INVALID_ARGUMENT when the configuration is invalid + * @retval ERROR_NOT_FOUND when the TTF file can't be read + * @retval ERROR_NOT_SUPPORTED when the TTF file can't be parsed or contains none of the codepoints + * @retval ERROR_OUT_OF_MEMORY when memory allocation failed + */ +error_t binfont_generate(const BinFontGeneratorConfig* config, uint8_t** out_data, size_t* out_size); + +#ifdef __cplusplus +} +#endif diff --git a/Modules/binfont-module/include/binfont/module.h b/Modules/binfont-module/include/binfont/module.h new file mode 100644 index 000000000..c47796938 --- /dev/null +++ b/Modules/binfont-module/include/binfont/module.h @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct Module binfont_module; + +#ifdef __cplusplus +} +#endif diff --git a/Modules/binfont-module/include/binfont/render.h b/Modules/binfont-module/include/binfont/render.h new file mode 100644 index 000000000..d3b703e14 --- /dev/null +++ b/Modules/binfont-module/include/binfont/render.h @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Alpha-blends one glyph over the existing pixels of a PixelBuffer. + * @param[out] buffer destination, in any pixel format + * @param[in] x pen position x + * @param[in] baseline_y pen position y (the baseline) + * @param[in] font the font + * @param[in] codepoint the Unicode codepoint + * @param[in] color glyph colour as RGB565 + * @param[in] conversion how colours reduce into the buffer's native format (see PixelBufferConversion) + * @return the horizontal advance in pixels, or 0 when the font has no glyph for the codepoint + */ +int binfont_draw_glyph_rgb565( + struct PixelBuffer* buffer, + int x, + int baseline_y, + struct BinFont* font, + uint32_t codepoint, + uint16_t color, + enum PixelBufferConversion conversion +); + +/** + * @brief Alpha-blends a UTF-8 string over the existing pixels of a PixelBuffer, applying kerning. + * @param[out] buffer destination, in any pixel format + * @param[in] x pen position x + * @param[in] baseline_y pen position y (the baseline) + * @param[in] font the font + * @param[in] text UTF-8 encoded, null-terminated text + * @param[in] color glyph colour as RGB565 + * @param[in] conversion how colours reduce into the buffer's native format (see PixelBufferConversion) + * @return the total advance in pixels + */ +int binfont_draw_text_rgb565( + struct PixelBuffer* buffer, + int x, + int baseline_y, + struct BinFont* font, + const char* text, + uint16_t color, + enum PixelBufferConversion conversion +); + +#ifdef __cplusplus +} +#endif diff --git a/Modules/binfont-module/private/stb_truetype.h b/Modules/binfont-module/private/stb_truetype.h new file mode 100644 index 000000000..90a5c2e2b --- /dev/null +++ b/Modules/binfont-module/private/stb_truetype.h @@ -0,0 +1,5079 @@ +// stb_truetype.h - v1.26 - public domain +// authored from 2009-2021 by Sean Barrett / RAD Game Tools +// +// ======================================================================= +// +// NO SECURITY GUARANTEE -- DO NOT USE THIS ON UNTRUSTED FONT FILES +// +// This library does no range checking of the offsets found in the file, +// meaning an attacker can use it to read arbitrary memory. +// +// ======================================================================= +// +// This library processes TrueType files: +// parse files +// extract glyph metrics +// extract glyph shapes +// render glyphs to one-channel bitmaps with antialiasing (box filter) +// render glyphs to one-channel SDF bitmaps (signed-distance field/function) +// +// Todo: +// non-MS cmaps +// crashproof on bad data +// hinting? (no longer patented) +// cleartype-style AA? +// optimize: use simple memory allocator for intermediates +// optimize: build edge-list directly from curves +// optimize: rasterize directly from curves? +// +// ADDITIONAL CONTRIBUTORS +// +// Mikko Mononen: compound shape support, more cmap formats +// Tor Andersson: kerning, subpixel rendering +// Dougall Johnson: OpenType / Type 2 font handling +// Daniel Ribeiro Maciel: basic GPOS-based kerning +// +// Misc other: +// Ryan Gordon +// Simon Glass +// github:IntellectualKitty +// Imanol Celaya +// Daniel Ribeiro Maciel +// +// Bug/warning reports/fixes: +// "Zer" on mollyrocket Fabian "ryg" Giesen github:NiLuJe +// Cass Everitt Martins Mozeiko github:aloucks +// stoiko (Haemimont Games) Cap Petschulat github:oyvindjam +// Brian Hook Omar Cornut github:vassvik +// Walter van Niftrik Ryan Griege +// David Gow Peter LaValle +// David Given Sergey Popov +// Ivan-Assen Ivanov Giumo X. Clanjor +// Anthony Pesch Higor Euripedes +// Johan Duparc Thomas Fields +// Hou Qiming Derek Vinyard +// Rob Loach Cort Stratton +// Kenney Phillis Jr. Brian Costabile +// Ken Voskuil (kaesve) Yakov Galka +// +// VERSION HISTORY +// +// 1.26 (2021-08-28) fix broken rasterizer +// 1.25 (2021-07-11) many fixes +// 1.24 (2020-02-05) fix warning +// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS) +// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined +// 1.21 (2019-02-25) fix warning +// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics() +// 1.19 (2018-02-11) GPOS kerning, STBTT_fmod +// 1.18 (2018-01-29) add missing function +// 1.17 (2017-07-23) make more arguments const; doc fix +// 1.16 (2017-07-12) SDF support +// 1.15 (2017-03-03) make more arguments const +// 1.14 (2017-01-16) num-fonts-in-TTC function +// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts +// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual +// 1.11 (2016-04-02) fix unused-variable warning +// 1.10 (2016-04-02) user-defined fabs(); rare memory leak; remove duplicate typedef +// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use allocation userdata properly +// 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges +// 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; +// variant PackFontRanges to pack and render in separate phases; +// fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); +// fixed an assert() bug in the new rasterizer +// replace assert() with STBTT_assert() in new rasterizer +// +// Full history can be found at the end of this file. +// +// LICENSE +// +// See end of file for license information. +// +// USAGE +// +// Include this file in whatever places need to refer to it. In ONE C/C++ +// file, write: +// #define STB_TRUETYPE_IMPLEMENTATION +// before the #include of this file. This expands out the actual +// implementation into that C/C++ file. +// +// To make the implementation private to the file that generates the implementation, +// #define STBTT_STATIC +// +// Simple 3D API (don't ship this, but it's fine for tools and quick start) +// stbtt_BakeFontBitmap() -- bake a font to a bitmap for use as texture +// stbtt_GetBakedQuad() -- compute quad to draw for a given char +// +// Improved 3D API (more shippable): +// #include "stb_rect_pack.h" -- optional, but you really want it +// stbtt_PackBegin() +// stbtt_PackSetOversampling() -- for improved quality on small fonts +// stbtt_PackFontRanges() -- pack and renders +// stbtt_PackEnd() +// stbtt_GetPackedQuad() +// +// "Load" a font file from a memory buffer (you have to keep the buffer loaded) +// stbtt_InitFont() +// stbtt_GetFontOffsetForIndex() -- indexing for TTC font collections +// stbtt_GetNumberOfFonts() -- number of fonts for TTC font collections +// +// Render a unicode codepoint to a bitmap +// stbtt_GetCodepointBitmap() -- allocates and returns a bitmap +// stbtt_MakeCodepointBitmap() -- renders into bitmap you provide +// stbtt_GetCodepointBitmapBox() -- how big the bitmap must be +// +// Character advance/positioning +// stbtt_GetCodepointHMetrics() +// stbtt_GetFontVMetrics() +// stbtt_GetFontVMetricsOS2() +// stbtt_GetCodepointKernAdvance() +// +// Starting with version 1.06, the rasterizer was replaced with a new, +// faster and generally-more-precise rasterizer. The new rasterizer more +// accurately measures pixel coverage for anti-aliasing, except in the case +// where multiple shapes overlap, in which case it overestimates the AA pixel +// coverage. Thus, anti-aliasing of intersecting shapes may look wrong. If +// this turns out to be a problem, you can re-enable the old rasterizer with +// #define STBTT_RASTERIZER_VERSION 1 +// which will incur about a 15% speed hit. +// +// ADDITIONAL DOCUMENTATION +// +// Immediately after this block comment are a series of sample programs. +// +// After the sample programs is the "header file" section. This section +// includes documentation for each API function. +// +// Some important concepts to understand to use this library: +// +// Codepoint +// Characters are defined by unicode codepoints, e.g. 65 is +// uppercase A, 231 is lowercase c with a cedilla, 0x7e30 is +// the hiragana for "ma". +// +// Glyph +// A visual character shape (every codepoint is rendered as +// some glyph) +// +// Glyph index +// A font-specific integer ID representing a glyph +// +// Baseline +// Glyph shapes are defined relative to a baseline, which is the +// bottom of uppercase characters. Characters extend both above +// and below the baseline. +// +// Current Point +// As you draw text to the screen, you keep track of a "current point" +// which is the origin of each character. The current point's vertical +// position is the baseline. Even "baked fonts" use this model. +// +// Vertical Font Metrics +// The vertical qualities of the font, used to vertically position +// and space the characters. See docs for stbtt_GetFontVMetrics. +// +// Font Size in Pixels or Points +// The preferred interface for specifying font sizes in stb_truetype +// is to specify how tall the font's vertical extent should be in pixels. +// If that sounds good enough, skip the next paragraph. +// +// Most font APIs instead use "points", which are a common typographic +// measurement for describing font size, defined as 72 points per inch. +// stb_truetype provides a point API for compatibility. However, true +// "per inch" conventions don't make much sense on computer displays +// since different monitors have different number of pixels per +// inch. For example, Windows traditionally uses a convention that +// there are 96 pixels per inch, thus making 'inch' measurements have +// nothing to do with inches, and thus effectively defining a point to +// be 1.333 pixels. Additionally, the TrueType font data provides +// an explicit scale factor to scale a given font's glyphs to points, +// but the author has observed that this scale factor is often wrong +// for non-commercial fonts, thus making fonts scaled in points +// according to the TrueType spec incoherently sized in practice. +// +// DETAILED USAGE: +// +// Scale: +// Select how high you want the font to be, in points or pixels. +// Call ScaleForPixelHeight or ScaleForMappingEmToPixels to compute +// a scale factor SF that will be used by all other functions. +// +// Baseline: +// You need to select a y-coordinate that is the baseline of where +// your text will appear. Call GetFontBoundingBox to get the baseline-relative +// bounding box for all characters. SF*-y0 will be the distance in pixels +// that the worst-case character could extend above the baseline, so if +// you want the top edge of characters to appear at the top of the +// screen where y=0, then you would set the baseline to SF*-y0. +// +// Current point: +// Set the current point where the first character will appear. The +// first character could extend left of the current point; this is font +// dependent. You can either choose a current point that is the leftmost +// point and hope, or add some padding, or check the bounding box or +// left-side-bearing of the first character to be displayed and set +// the current point based on that. +// +// Displaying a character: +// Compute the bounding box of the character. It will contain signed values +// relative to . I.e. if it returns x0,y0,x1,y1, +// then the character should be displayed in the rectangle from +// to = 32 && *text < 128) { + stbtt_aligned_quad q; + stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9 + glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y0); + glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y0); + glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y1); + glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y1); + } + ++text; + } + glEnd(); +} +#endif +// +// +////////////////////////////////////////////////////////////////////////////// +// +// Complete program (this compiles): get a single bitmap, print as ASCII art +// +#if 0 +#include +#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation +#include "stb_truetype.h" + +char ttf_buffer[1<<25]; + +int main(int argc, char **argv) +{ + stbtt_fontinfo font; + unsigned char *bitmap; + int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20); + + fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/arialbd.ttf", "rb")); + + stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0)); + bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0,0); + + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) + putchar(" .:ioVM@"[bitmap[j*w+i]>>5]); + putchar('\n'); + } + return 0; +} +#endif +// +// Output: +// +// .ii. +// @@@@@@. +// V@Mio@@o +// :i. V@V +// :oM@@M +// :@@@MM@M +// @@o o@M +// :@@. M@M +// @@@o@@@@ +// :M@@V:@@. +// +////////////////////////////////////////////////////////////////////////////// +// +// Complete program: print "Hello World!" banner, with bugs +// +#if 0 +char buffer[24<<20]; +unsigned char screen[20][79]; + +int main(int arg, char **argv) +{ + stbtt_fontinfo font; + int i,j,ascent,baseline,ch=0; + float scale, xpos=2; // leave a little padding in case the character extends left + char *text = "Heljo World!"; // intentionally misspelled to show 'lj' brokenness + + fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb")); + stbtt_InitFont(&font, buffer, 0); + + scale = stbtt_ScaleForPixelHeight(&font, 15); + stbtt_GetFontVMetrics(&font, &ascent,0,0); + baseline = (int) (ascent*scale); + + while (text[ch]) { + int advance,lsb,x0,y0,x1,y1; + float x_shift = xpos - (float) floor(xpos); + stbtt_GetCodepointHMetrics(&font, text[ch], &advance, &lsb); + stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale,scale,x_shift,0, &x0,&y0,&x1,&y1); + stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,x_shift,0, text[ch]); + // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong + // because this API is really for baking character bitmaps into textures. if you want to render + // a sequence of characters, you really need to render each bitmap to a temp buffer, then + // "alpha blend" that into the working buffer + xpos += (advance * scale); + if (text[ch+1]) + xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]); + ++ch; + } + + for (j=0; j < 20; ++j) { + for (i=0; i < 78; ++i) + putchar(" .:ioVM@"[screen[j][i]>>5]); + putchar('\n'); + } + + return 0; +} +#endif + + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +//// +//// INTEGRATION WITH YOUR CODEBASE +//// +//// The following sections allow you to supply alternate definitions +//// of C library functions used by stb_truetype, e.g. if you don't +//// link with the C runtime library. + +#ifdef STB_TRUETYPE_IMPLEMENTATION + // #define your own (u)stbtt_int8/16/32 before including to override this + #ifndef stbtt_uint8 + typedef unsigned char stbtt_uint8; + typedef signed char stbtt_int8; + typedef unsigned short stbtt_uint16; + typedef signed short stbtt_int16; + typedef unsigned int stbtt_uint32; + typedef signed int stbtt_int32; + #endif + + typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1]; + typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1]; + + // e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h + #ifndef STBTT_ifloor + #include + #define STBTT_ifloor(x) ((int) floor(x)) + #define STBTT_iceil(x) ((int) ceil(x)) + #endif + + #ifndef STBTT_sqrt + #include + #define STBTT_sqrt(x) sqrt(x) + #define STBTT_pow(x,y) pow(x,y) + #endif + + #ifndef STBTT_fmod + #include + #define STBTT_fmod(x,y) fmod(x,y) + #endif + + #ifndef STBTT_cos + #include + #define STBTT_cos(x) cos(x) + #define STBTT_acos(x) acos(x) + #endif + + #ifndef STBTT_fabs + #include + #define STBTT_fabs(x) fabs(x) + #endif + + // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h + #ifndef STBTT_malloc + #include + #define STBTT_malloc(x,u) ((void)(u),malloc(x)) + #define STBTT_free(x,u) ((void)(u),free(x)) + #endif + + #ifndef STBTT_assert + #include + #define STBTT_assert(x) assert(x) + #endif + + #ifndef STBTT_strlen + #include + #define STBTT_strlen(x) strlen(x) + #endif + + #ifndef STBTT_memcpy + #include + #define STBTT_memcpy memcpy + #define STBTT_memset memset + #endif +#endif + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +//// +//// INTERFACE +//// +//// + +#ifndef __STB_INCLUDE_STB_TRUETYPE_H__ +#define __STB_INCLUDE_STB_TRUETYPE_H__ + +#ifdef STBTT_STATIC +#define STBTT_DEF static +#else +#define STBTT_DEF extern +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// private structure +typedef struct +{ + unsigned char *data; + int cursor; + int size; +} stbtt__buf; + +////////////////////////////////////////////////////////////////////////////// +// +// TEXTURE BAKING API +// +// If you use this API, you only have to call two functions ever. +// + +typedef struct +{ + unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap + float xoff,yoff,xadvance; +} stbtt_bakedchar; + +STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) + float pixel_height, // height of font in pixels + unsigned char *pixels, int pw, int ph, // bitmap to be filled in + int first_char, int num_chars, // characters to bake + stbtt_bakedchar *chardata); // you allocate this, it's num_chars long +// if return is positive, the first unused row of the bitmap +// if return is negative, returns the negative of the number of characters that fit +// if return is 0, no characters fit and no rows were used +// This uses a very crappy packing. + +typedef struct +{ + float x0,y0,s0,t0; // top-left + float x1,y1,s1,t1; // bottom-right +} stbtt_aligned_quad; + +STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, // same data as above + int char_index, // character to display + float *xpos, float *ypos, // pointers to current position in screen pixel space + stbtt_aligned_quad *q, // output: quad to draw + int opengl_fillrule); // true if opengl fill rule; false if DX9 or earlier +// Call GetBakedQuad with char_index = 'character - first_char', and it +// creates the quad you need to draw and advances the current position. +// +// The coordinate system used assumes y increases downwards. +// +// Characters will extend both above and below the current position; +// see discussion of "BASELINE" above. +// +// It's inefficient; you might want to c&p it and optimize it. + +STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap); +// Query the font vertical metrics without having to create a font first. + + +////////////////////////////////////////////////////////////////////////////// +// +// NEW TEXTURE BAKING API +// +// This provides options for packing multiple fonts into one atlas, not +// perfectly but better than nothing. + +typedef struct +{ + unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap + float xoff,yoff,xadvance; + float xoff2,yoff2; +} stbtt_packedchar; + +typedef struct stbtt_pack_context stbtt_pack_context; +typedef struct stbtt_fontinfo stbtt_fontinfo; +#ifndef STB_RECT_PACK_VERSION +typedef struct stbrp_rect stbrp_rect; +#endif + +STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context); +// Initializes a packing context stored in the passed-in stbtt_pack_context. +// Future calls using this context will pack characters into the bitmap passed +// in here: a 1-channel bitmap that is width * height. stride_in_bytes is +// the distance from one row to the next (or 0 to mean they are packed tightly +// together). "padding" is the amount of padding to leave between each +// character (normally you want '1' for bitmaps you'll use as textures with +// bilinear filtering). +// +// Returns 0 on failure, 1 on success. + +STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc); +// Cleans up the packing context and frees all memory. + +#define STBTT_POINT_SIZE(x) (-(x)) + +STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size, + int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range); +// Creates character bitmaps from the font_index'th font found in fontdata (use +// font_index=0 if you don't know what that is). It creates num_chars_in_range +// bitmaps for characters with unicode values starting at first_unicode_char_in_range +// and increasing. Data for how to render them is stored in chardata_for_range; +// pass these to stbtt_GetPackedQuad to get back renderable quads. +// +// font_size is the full height of the character from ascender to descender, +// as computed by stbtt_ScaleForPixelHeight. To use a point size as computed +// by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE() +// and pass that result as 'font_size': +// ..., 20 , ... // font max minus min y is 20 pixels tall +// ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall + +typedef struct +{ + float font_size; + int first_unicode_codepoint_in_range; // if non-zero, then the chars are continuous, and this is the first codepoint + int *array_of_unicode_codepoints; // if non-zero, then this is an array of unicode codepoints + int num_chars; + stbtt_packedchar *chardata_for_range; // output + unsigned char h_oversample, v_oversample; // don't set these, they're used internally +} stbtt_pack_range; + +STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges); +// Creates character bitmaps from multiple ranges of characters stored in +// ranges. This will usually create a better-packed bitmap than multiple +// calls to stbtt_PackFontRange. Note that you can call this multiple +// times within a single PackBegin/PackEnd. + +STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample); +// Oversampling a font increases the quality by allowing higher-quality subpixel +// positioning, and is especially valuable at smaller text sizes. +// +// This function sets the amount of oversampling for all following calls to +// stbtt_PackFontRange(s) or stbtt_PackFontRangesGatherRects for a given +// pack context. The default (no oversampling) is achieved by h_oversample=1 +// and v_oversample=1. The total number of pixels required is +// h_oversample*v_oversample larger than the default; for example, 2x2 +// oversampling requires 4x the storage of 1x1. For best results, render +// oversampled textures with bilinear filtering. Look at the readme in +// stb/tests/oversample for information about oversampled fonts +// +// To use with PackFontRangesGather etc., you must set it before calls +// call to PackFontRangesGatherRects. + +STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip); +// If skip != 0, this tells stb_truetype to skip any codepoints for which +// there is no corresponding glyph. If skip=0, which is the default, then +// codepoints without a glyph recived the font's "missing character" glyph, +// typically an empty box by convention. + +STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, // same data as above + int char_index, // character to display + float *xpos, float *ypos, // pointers to current position in screen pixel space + stbtt_aligned_quad *q, // output: quad to draw + int align_to_integer); + +STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); +STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects); +STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); +// Calling these functions in sequence is roughly equivalent to calling +// stbtt_PackFontRanges(). If you more control over the packing of multiple +// fonts, or if you want to pack custom data into a font texture, take a look +// at the source to of stbtt_PackFontRanges() and create a custom version +// using these functions, e.g. call GatherRects multiple times, +// building up a single array of rects, then call PackRects once, +// then call RenderIntoRects repeatedly. This may result in a +// better packing than calling PackFontRanges multiple times +// (or it may not). + +// this is an opaque structure that you shouldn't mess with which holds +// all the context needed from PackBegin to PackEnd. +struct stbtt_pack_context { + void *user_allocator_context; + void *pack_info; + int width; + int height; + int stride_in_bytes; + int padding; + int skip_missing; + unsigned int h_oversample, v_oversample; + unsigned char *pixels; + void *nodes; +}; + +////////////////////////////////////////////////////////////////////////////// +// +// FONT LOADING +// +// + +STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data); +// This function will determine the number of fonts in a font file. TrueType +// collection (.ttc) files may contain multiple fonts, while TrueType font +// (.ttf) files only contain one font. The number of fonts can be used for +// indexing with the previous function where the index is between zero and one +// less than the total fonts. If an error occurs, -1 is returned. + +STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index); +// Each .ttf/.ttc file may have more than one font. Each font has a sequential +// index number starting from 0. Call this function to get the font offset for +// a given index; it returns -1 if the index is out of range. A regular .ttf +// file will only define one font and it always be at offset 0, so it will +// return '0' for index 0, and -1 for all other indices. + +// The following structure is defined publicly so you can declare one on +// the stack or as a global or etc, but you should treat it as opaque. +struct stbtt_fontinfo +{ + void * userdata; + unsigned char * data; // pointer to .ttf file + int fontstart; // offset of start of font + + int numGlyphs; // number of glyphs, needed for range checking + + int loca,head,glyf,hhea,hmtx,kern,gpos,svg; // table locations as offset from start of .ttf + int index_map; // a cmap mapping for our chosen character encoding + int indexToLocFormat; // format needed to map from glyph index to glyph + + stbtt__buf cff; // cff font data + stbtt__buf charstrings; // the charstring index + stbtt__buf gsubrs; // global charstring subroutines index + stbtt__buf subrs; // private charstring subroutines index + stbtt__buf fontdicts; // array of font dicts + stbtt__buf fdselect; // map from glyph to fontdict +}; + +STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset); +// Given an offset into the file that defines a font, this function builds +// the necessary cached info for the rest of the system. You must allocate +// the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't +// need to do anything special to free it, because the contents are pure +// value data with no additional data structures. Returns 0 on failure. + + +////////////////////////////////////////////////////////////////////////////// +// +// CHARACTER TO GLYPH-INDEX CONVERSIOn + +STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint); +// If you're going to perform multiple operations on the same character +// and you want a speed-up, call this function with the character you're +// going to process, then use glyph-based functions instead of the +// codepoint-based functions. +// Returns 0 if the character codepoint is not defined in the font. + + +////////////////////////////////////////////////////////////////////////////// +// +// CHARACTER PROPERTIES +// + +STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels); +// computes a scale factor to produce a font whose "height" is 'pixels' tall. +// Height is measured as the distance from the highest ascender to the lowest +// descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics +// and computing: +// scale = pixels / (ascent - descent) +// so if you prefer to measure height by the ascent only, use a similar calculation. + +STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels); +// computes a scale factor to produce a font whose EM size is mapped to +// 'pixels' tall. This is probably what traditional APIs compute, but +// I'm not positive. + +STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap); +// ascent is the coordinate above the baseline the font extends; descent +// is the coordinate below the baseline the font extends (i.e. it is typically negative) +// lineGap is the spacing between one row's descent and the next row's ascent... +// so you should advance the vertical position by "*ascent - *descent + *lineGap" +// these are expressed in unscaled coordinates, so you must multiply by +// the scale factor for a given size + +STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap); +// analogous to GetFontVMetrics, but returns the "typographic" values from the OS/2 +// table (specific to MS/Windows TTF files). +// +// Returns 1 on success (table present), 0 on failure. + +STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1); +// the bounding box around all possible characters + +STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing); +// leftSideBearing is the offset from the current horizontal position to the left edge of the character +// advanceWidth is the offset from the current horizontal position to the next horizontal position +// these are expressed in unscaled coordinates + +STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2); +// an additional amount to add to the 'advance' value between ch1 and ch2 + +STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1); +// Gets the bounding box of the visible part of the glyph, in unscaled coordinates + +STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing); +STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2); +STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); +// as above, but takes one or more glyph indices for greater efficiency + +typedef struct stbtt_kerningentry +{ + int glyph1; // use stbtt_FindGlyphIndex + int glyph2; + int advance; +} stbtt_kerningentry; + +STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info); +STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length); +// Retrieves a complete list of all of the kerning pairs provided by the font +// stbtt_GetKerningTable never writes more than table_length entries and returns how many entries it did write. +// The table will be sorted by (a.glyph1 == b.glyph1)?(a.glyph2 < b.glyph2):(a.glyph1 < b.glyph1) + +////////////////////////////////////////////////////////////////////////////// +// +// GLYPH SHAPES (you probably don't need these, but they have to go before +// the bitmaps for C declaration-order reasons) +// + +#ifndef STBTT_vmove // you can predefine these to use different values (but why?) + enum { + STBTT_vmove=1, + STBTT_vline, + STBTT_vcurve, + STBTT_vcubic + }; +#endif + +#ifndef stbtt_vertex // you can predefine this to use different values + // (we share this with other code at RAD) + #define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file + typedef struct + { + stbtt_vertex_type x,y,cx,cy,cx1,cy1; + unsigned char type,padding; + } stbtt_vertex; +#endif + +STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index); +// returns non-zero if nothing is drawn for this glyph + +STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices); +STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices); +// returns # of vertices and fills *vertices with the pointer to them +// these are expressed in "unscaled" coordinates +// +// The shape is a series of contours. Each one starts with +// a STBTT_moveto, then consists of a series of mixed +// STBTT_lineto and STBTT_curveto segments. A lineto +// draws a line from previous endpoint to its x,y; a curveto +// draws a quadratic bezier from previous endpoint to +// its x,y, using cx,cy as the bezier control point. + +STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices); +// frees the data allocated above + +STBTT_DEF unsigned char *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl); +STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg); +STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg); +// fills svg with the character's SVG data. +// returns data size or 0 if SVG not found. + +////////////////////////////////////////////////////////////////////////////// +// +// BITMAP RENDERING +// + +STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata); +// frees the bitmap allocated below + +STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff); +// allocates a large-enough single-channel 8bpp bitmap and renders the +// specified character/glyph at the specified scale into it, with +// antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque). +// *width & *height are filled out with the width & height of the bitmap, +// which is stored left-to-right, top-to-bottom. +// +// xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap + +STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff); +// the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel +// shift for the character + +STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint); +// the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap +// in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap +// is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the +// width and height and positioning info for it first. + +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint); +// same as stbtt_MakeCodepointBitmap, but you can specify a subpixel +// shift for the character + +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint); +// same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering +// is performed (see stbtt_PackSetOversampling) + +STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); +// get the bbox of the bitmap centered around the glyph origin; so the +// bitmap width is ix1-ix0, height is iy1-iy0, and location to place +// the bitmap top left is (leftSideBearing*scale,iy0). +// (Note that the bitmap uses y-increases-down, but the shape uses +// y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.) + +STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); +// same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel +// shift for the character + +// the following functions are equivalent to the above functions, but operate +// on glyph indices instead of Unicode codepoints (for efficiency) +STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff); +STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff); +STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph); +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph); +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int glyph); +STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); +STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); + + +// @TODO: don't expose this structure +typedef struct +{ + int w,h,stride; + unsigned char *pixels; +} stbtt__bitmap; + +// rasterize a shape with quadratic beziers into a bitmap +STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, // 1-channel bitmap to draw into + float flatness_in_pixels, // allowable error of curve in pixels + stbtt_vertex *vertices, // array of vertices defining shape + int num_verts, // number of vertices in above array + float scale_x, float scale_y, // scale applied to input vertices + float shift_x, float shift_y, // translation applied to input vertices + int x_off, int y_off, // another translation applied to input + int invert, // if non-zero, vertically flip shape + void *userdata); // context for to STBTT_MALLOC + +////////////////////////////////////////////////////////////////////////////// +// +// Signed Distance Function (or Field) rendering + +STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata); +// frees the SDF bitmap allocated below + +STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff); +STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff); +// These functions compute a discretized SDF field for a single character, suitable for storing +// in a single-channel texture, sampling with bilinear filtering, and testing against +// larger than some threshold to produce scalable fonts. +// info -- the font +// scale -- controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap +// glyph/codepoint -- the character to generate the SDF for +// padding -- extra "pixels" around the character which are filled with the distance to the character (not 0), +// which allows effects like bit outlines +// onedge_value -- value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character) +// pixel_dist_scale -- what value the SDF should increase by when moving one SDF "pixel" away from the edge (on the 0..255 scale) +// if positive, > onedge_value is inside; if negative, < onedge_value is inside +// width,height -- output height & width of the SDF bitmap (including padding) +// xoff,yoff -- output origin of the character +// return value -- a 2D array of bytes 0..255, width*height in size +// +// pixel_dist_scale & onedge_value are a scale & bias that allows you to make +// optimal use of the limited 0..255 for your application, trading off precision +// and special effects. SDF values outside the range 0..255 are clamped to 0..255. +// +// Example: +// scale = stbtt_ScaleForPixelHeight(22) +// padding = 5 +// onedge_value = 180 +// pixel_dist_scale = 180/5.0 = 36.0 +// +// This will create an SDF bitmap in which the character is about 22 pixels +// high but the whole bitmap is about 22+5+5=32 pixels high. To produce a filled +// shape, sample the SDF at each pixel and fill the pixel if the SDF value +// is greater than or equal to 180/255. (You'll actually want to antialias, +// which is beyond the scope of this example.) Additionally, you can compute +// offset outlines (e.g. to stroke the character border inside & outside, +// or only outside). For example, to fill outside the character up to 3 SDF +// pixels, you would compare against (180-36.0*3)/255 = 72/255. The above +// choice of variables maps a range from 5 pixels outside the shape to +// 2 pixels inside the shape to 0..255; this is intended primarily for apply +// outside effects only (the interior range is needed to allow proper +// antialiasing of the font at *smaller* sizes) +// +// The function computes the SDF analytically at each SDF pixel, not by e.g. +// building a higher-res bitmap and approximating it. In theory the quality +// should be as high as possible for an SDF of this size & representation, but +// unclear if this is true in practice (perhaps building a higher-res bitmap +// and computing from that can allow drop-out prevention). +// +// The algorithm has not been optimized at all, so expect it to be slow +// if computing lots of characters or very large sizes. + + + +////////////////////////////////////////////////////////////////////////////// +// +// Finding the right font... +// +// You should really just solve this offline, keep your own tables +// of what font is what, and don't try to get it out of the .ttf file. +// That's because getting it out of the .ttf file is really hard, because +// the names in the file can appear in many possible encodings, in many +// possible languages, and e.g. if you need a case-insensitive comparison, +// the details of that depend on the encoding & language in a complex way +// (actually underspecified in truetype, but also gigantic). +// +// But you can use the provided functions in two possible ways: +// stbtt_FindMatchingFont() will use *case-sensitive* comparisons on +// unicode-encoded names to try to find the font you want; +// you can run this before calling stbtt_InitFont() +// +// stbtt_GetFontNameString() lets you get any of the various strings +// from the file yourself and do your own comparisons on them. +// You have to have called stbtt_InitFont() first. + + +STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags); +// returns the offset (not index) of the font that matches, or -1 if none +// if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold". +// if you use any other flag, use a font name like "Arial"; this checks +// the 'macStyle' header field; i don't know if fonts set this consistently +#define STBTT_MACSTYLE_DONTCARE 0 +#define STBTT_MACSTYLE_BOLD 1 +#define STBTT_MACSTYLE_ITALIC 2 +#define STBTT_MACSTYLE_UNDERSCORE 4 +#define STBTT_MACSTYLE_NONE 8 // <= not same as 0, this makes us check the bitfield is 0 + +STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2); +// returns 1/0 whether the first string interpreted as utf8 is identical to +// the second string interpreted as big-endian utf16... useful for strings from next func + +STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID); +// returns the string (which may be big-endian double byte, e.g. for unicode) +// and puts the length in bytes in *length. +// +// some of the values for the IDs are below; for more see the truetype spec: +// http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html +// http://www.microsoft.com/typography/otspec/name.htm + +enum { // platformID + STBTT_PLATFORM_ID_UNICODE =0, + STBTT_PLATFORM_ID_MAC =1, + STBTT_PLATFORM_ID_ISO =2, + STBTT_PLATFORM_ID_MICROSOFT =3 +}; + +enum { // encodingID for STBTT_PLATFORM_ID_UNICODE + STBTT_UNICODE_EID_UNICODE_1_0 =0, + STBTT_UNICODE_EID_UNICODE_1_1 =1, + STBTT_UNICODE_EID_ISO_10646 =2, + STBTT_UNICODE_EID_UNICODE_2_0_BMP=3, + STBTT_UNICODE_EID_UNICODE_2_0_FULL=4 +}; + +enum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT + STBTT_MS_EID_SYMBOL =0, + STBTT_MS_EID_UNICODE_BMP =1, + STBTT_MS_EID_SHIFTJIS =2, + STBTT_MS_EID_UNICODE_FULL =10 +}; + +enum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes + STBTT_MAC_EID_ROMAN =0, STBTT_MAC_EID_ARABIC =4, + STBTT_MAC_EID_JAPANESE =1, STBTT_MAC_EID_HEBREW =5, + STBTT_MAC_EID_CHINESE_TRAD =2, STBTT_MAC_EID_GREEK =6, + STBTT_MAC_EID_KOREAN =3, STBTT_MAC_EID_RUSSIAN =7 +}; + +enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID... + // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs + STBTT_MS_LANG_ENGLISH =0x0409, STBTT_MS_LANG_ITALIAN =0x0410, + STBTT_MS_LANG_CHINESE =0x0804, STBTT_MS_LANG_JAPANESE =0x0411, + STBTT_MS_LANG_DUTCH =0x0413, STBTT_MS_LANG_KOREAN =0x0412, + STBTT_MS_LANG_FRENCH =0x040c, STBTT_MS_LANG_RUSSIAN =0x0419, + STBTT_MS_LANG_GERMAN =0x0407, STBTT_MS_LANG_SPANISH =0x0409, + STBTT_MS_LANG_HEBREW =0x040d, STBTT_MS_LANG_SWEDISH =0x041D +}; + +enum { // languageID for STBTT_PLATFORM_ID_MAC + STBTT_MAC_LANG_ENGLISH =0 , STBTT_MAC_LANG_JAPANESE =11, + STBTT_MAC_LANG_ARABIC =12, STBTT_MAC_LANG_KOREAN =23, + STBTT_MAC_LANG_DUTCH =4 , STBTT_MAC_LANG_RUSSIAN =32, + STBTT_MAC_LANG_FRENCH =1 , STBTT_MAC_LANG_SPANISH =6 , + STBTT_MAC_LANG_GERMAN =2 , STBTT_MAC_LANG_SWEDISH =5 , + STBTT_MAC_LANG_HEBREW =10, STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33, + STBTT_MAC_LANG_ITALIAN =3 , STBTT_MAC_LANG_CHINESE_TRAD =19 +}; + +#ifdef __cplusplus +} +#endif + +#endif // __STB_INCLUDE_STB_TRUETYPE_H__ + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +//// +//// IMPLEMENTATION +//// +//// + +#ifdef STB_TRUETYPE_IMPLEMENTATION + +#ifndef STBTT_MAX_OVERSAMPLE +#define STBTT_MAX_OVERSAMPLE 8 +#endif + +#if STBTT_MAX_OVERSAMPLE > 255 +#error "STBTT_MAX_OVERSAMPLE cannot be > 255" +#endif + +typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1]; + +#ifndef STBTT_RASTERIZER_VERSION +#define STBTT_RASTERIZER_VERSION 2 +#endif + +#ifdef _MSC_VER +#define STBTT__NOTUSED(v) (void)(v) +#else +#define STBTT__NOTUSED(v) (void)sizeof(v) +#endif + +////////////////////////////////////////////////////////////////////////// +// +// stbtt__buf helpers to parse data from file +// + +static stbtt_uint8 stbtt__buf_get8(stbtt__buf *b) +{ + if (b->cursor >= b->size) + return 0; + return b->data[b->cursor++]; +} + +static stbtt_uint8 stbtt__buf_peek8(stbtt__buf *b) +{ + if (b->cursor >= b->size) + return 0; + return b->data[b->cursor]; +} + +static void stbtt__buf_seek(stbtt__buf *b, int o) +{ + STBTT_assert(!(o > b->size || o < 0)); + b->cursor = (o > b->size || o < 0) ? b->size : o; +} + +static void stbtt__buf_skip(stbtt__buf *b, int o) +{ + stbtt__buf_seek(b, b->cursor + o); +} + +static stbtt_uint32 stbtt__buf_get(stbtt__buf *b, int n) +{ + stbtt_uint32 v = 0; + int i; + STBTT_assert(n >= 1 && n <= 4); + for (i = 0; i < n; i++) + v = (v << 8) | stbtt__buf_get8(b); + return v; +} + +static stbtt__buf stbtt__new_buf(const void *p, size_t size) +{ + stbtt__buf r; + STBTT_assert(size < 0x40000000); + r.data = (stbtt_uint8*) p; + r.size = (int) size; + r.cursor = 0; + return r; +} + +#define stbtt__buf_get16(b) stbtt__buf_get((b), 2) +#define stbtt__buf_get32(b) stbtt__buf_get((b), 4) + +static stbtt__buf stbtt__buf_range(const stbtt__buf *b, int o, int s) +{ + stbtt__buf r = stbtt__new_buf(NULL, 0); + if (o < 0 || s < 0 || o > b->size || s > b->size - o) return r; + r.data = b->data + o; + r.size = s; + return r; +} + +static stbtt__buf stbtt__cff_get_index(stbtt__buf *b) +{ + int count, start, offsize; + start = b->cursor; + count = stbtt__buf_get16(b); + if (count) { + offsize = stbtt__buf_get8(b); + STBTT_assert(offsize >= 1 && offsize <= 4); + stbtt__buf_skip(b, offsize * count); + stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1); + } + return stbtt__buf_range(b, start, b->cursor - start); +} + +static stbtt_uint32 stbtt__cff_int(stbtt__buf *b) +{ + int b0 = stbtt__buf_get8(b); + if (b0 >= 32 && b0 <= 246) return b0 - 139; + else if (b0 >= 247 && b0 <= 250) return (b0 - 247)*256 + stbtt__buf_get8(b) + 108; + else if (b0 >= 251 && b0 <= 254) return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108; + else if (b0 == 28) return stbtt__buf_get16(b); + else if (b0 == 29) return stbtt__buf_get32(b); + STBTT_assert(0); + return 0; +} + +static void stbtt__cff_skip_operand(stbtt__buf *b) { + int v, b0 = stbtt__buf_peek8(b); + STBTT_assert(b0 >= 28); + if (b0 == 30) { + stbtt__buf_skip(b, 1); + while (b->cursor < b->size) { + v = stbtt__buf_get8(b); + if ((v & 0xF) == 0xF || (v >> 4) == 0xF) + break; + } + } else { + stbtt__cff_int(b); + } +} + +static stbtt__buf stbtt__dict_get(stbtt__buf *b, int key) +{ + stbtt__buf_seek(b, 0); + while (b->cursor < b->size) { + int start = b->cursor, end, op; + while (stbtt__buf_peek8(b) >= 28) + stbtt__cff_skip_operand(b); + end = b->cursor; + op = stbtt__buf_get8(b); + if (op == 12) op = stbtt__buf_get8(b) | 0x100; + if (op == key) return stbtt__buf_range(b, start, end-start); + } + return stbtt__buf_range(b, 0, 0); +} + +static void stbtt__dict_get_ints(stbtt__buf *b, int key, int outcount, stbtt_uint32 *out) +{ + int i; + stbtt__buf operands = stbtt__dict_get(b, key); + for (i = 0; i < outcount && operands.cursor < operands.size; i++) + out[i] = stbtt__cff_int(&operands); +} + +static int stbtt__cff_index_count(stbtt__buf *b) +{ + stbtt__buf_seek(b, 0); + return stbtt__buf_get16(b); +} + +static stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i) +{ + int count, offsize, start, end; + stbtt__buf_seek(&b, 0); + count = stbtt__buf_get16(&b); + offsize = stbtt__buf_get8(&b); + STBTT_assert(i >= 0 && i < count); + STBTT_assert(offsize >= 1 && offsize <= 4); + stbtt__buf_skip(&b, i*offsize); + start = stbtt__buf_get(&b, offsize); + end = stbtt__buf_get(&b, offsize); + return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start); +} + +////////////////////////////////////////////////////////////////////////// +// +// accessors to parse data from file +// + +// on platforms that don't allow misaligned reads, if we want to allow +// truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE + +#define ttBYTE(p) (* (stbtt_uint8 *) (p)) +#define ttCHAR(p) (* (stbtt_int8 *) (p)) +#define ttFixed(p) ttLONG(p) + +static stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } +static stbtt_int16 ttSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } +static stbtt_uint32 ttULONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } +static stbtt_int32 ttLONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } + +#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3)) +#define stbtt_tag(p,str) stbtt_tag4(p,str[0],str[1],str[2],str[3]) + +static int stbtt__isfont(stbtt_uint8 *font) +{ + // check the version number + if (stbtt_tag4(font, '1',0,0,0)) return 1; // TrueType 1 + if (stbtt_tag(font, "typ1")) return 1; // TrueType with type 1 font -- we don't support this! + if (stbtt_tag(font, "OTTO")) return 1; // OpenType with CFF + if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0 + if (stbtt_tag(font, "true")) return 1; // Apple specification for TrueType fonts + return 0; +} + +// @OPTIMIZE: binary search +static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const char *tag) +{ + stbtt_int32 num_tables = ttUSHORT(data+fontstart+4); + stbtt_uint32 tabledir = fontstart + 12; + stbtt_int32 i; + for (i=0; i < num_tables; ++i) { + stbtt_uint32 loc = tabledir + 16*i; + if (stbtt_tag(data+loc+0, tag)) + return ttULONG(data+loc+8); + } + return 0; +} + +static int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection, int index) +{ + // if it's just a font, there's only one valid index + if (stbtt__isfont(font_collection)) + return index == 0 ? 0 : -1; + + // check if it's a TTC + if (stbtt_tag(font_collection, "ttcf")) { + // version 1? + if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { + stbtt_int32 n = ttLONG(font_collection+8); + if (index >= n) + return -1; + return ttULONG(font_collection+12+index*4); + } + } + return -1; +} + +static int stbtt_GetNumberOfFonts_internal(unsigned char *font_collection) +{ + // if it's just a font, there's only one valid font + if (stbtt__isfont(font_collection)) + return 1; + + // check if it's a TTC + if (stbtt_tag(font_collection, "ttcf")) { + // version 1? + if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { + return ttLONG(font_collection+8); + } + } + return 0; +} + +static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict) +{ + stbtt_uint32 subrsoff = 0, private_loc[2] = { 0, 0 }; + stbtt__buf pdict; + stbtt__dict_get_ints(&fontdict, 18, 2, private_loc); + if (!private_loc[1] || !private_loc[0]) return stbtt__new_buf(NULL, 0); + pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]); + stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff); + if (!subrsoff) return stbtt__new_buf(NULL, 0); + stbtt__buf_seek(&cff, private_loc[1]+subrsoff); + return stbtt__cff_get_index(&cff); +} + +// since most people won't use this, find this table the first time it's needed +static int stbtt__get_svg(stbtt_fontinfo *info) +{ + stbtt_uint32 t; + if (info->svg < 0) { + t = stbtt__find_table(info->data, info->fontstart, "SVG "); + if (t) { + stbtt_uint32 offset = ttULONG(info->data + t + 2); + info->svg = t + offset; + } else { + info->svg = 0; + } + } + return info->svg; +} + +static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart) +{ + stbtt_uint32 cmap, t; + stbtt_int32 i,numTables; + + info->data = data; + info->fontstart = fontstart; + info->cff = stbtt__new_buf(NULL, 0); + + cmap = stbtt__find_table(data, fontstart, "cmap"); // required + info->loca = stbtt__find_table(data, fontstart, "loca"); // required + info->head = stbtt__find_table(data, fontstart, "head"); // required + info->glyf = stbtt__find_table(data, fontstart, "glyf"); // required + info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required + info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required + info->kern = stbtt__find_table(data, fontstart, "kern"); // not required + info->gpos = stbtt__find_table(data, fontstart, "GPOS"); // not required + + if (!cmap || !info->head || !info->hhea || !info->hmtx) + return 0; + if (info->glyf) { + // required for truetype + if (!info->loca) return 0; + } else { + // initialization for CFF / Type2 fonts (OTF) + stbtt__buf b, topdict, topdictidx; + stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0; + stbtt_uint32 cff; + + cff = stbtt__find_table(data, fontstart, "CFF "); + if (!cff) return 0; + + info->fontdicts = stbtt__new_buf(NULL, 0); + info->fdselect = stbtt__new_buf(NULL, 0); + + // @TODO this should use size from table (not 512MB) + info->cff = stbtt__new_buf(data+cff, 512*1024*1024); + b = info->cff; + + // read the header + stbtt__buf_skip(&b, 2); + stbtt__buf_seek(&b, stbtt__buf_get8(&b)); // hdrsize + + // @TODO the name INDEX could list multiple fonts, + // but we just use the first one. + stbtt__cff_get_index(&b); // name INDEX + topdictidx = stbtt__cff_get_index(&b); + topdict = stbtt__cff_index_get(topdictidx, 0); + stbtt__cff_get_index(&b); // string INDEX + info->gsubrs = stbtt__cff_get_index(&b); + + stbtt__dict_get_ints(&topdict, 17, 1, &charstrings); + stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype); + stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff); + stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff); + info->subrs = stbtt__get_subrs(b, topdict); + + // we only support Type 2 charstrings + if (cstype != 2) return 0; + if (charstrings == 0) return 0; + + if (fdarrayoff) { + // looks like a CID font + if (!fdselectoff) return 0; + stbtt__buf_seek(&b, fdarrayoff); + info->fontdicts = stbtt__cff_get_index(&b); + info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size-fdselectoff); + } + + stbtt__buf_seek(&b, charstrings); + info->charstrings = stbtt__cff_get_index(&b); + } + + t = stbtt__find_table(data, fontstart, "maxp"); + if (t) + info->numGlyphs = ttUSHORT(data+t+4); + else + info->numGlyphs = 0xffff; + + info->svg = -1; + + // find a cmap encoding table we understand *now* to avoid searching + // later. (todo: could make this installable) + // the same regardless of glyph. + numTables = ttUSHORT(data + cmap + 2); + info->index_map = 0; + for (i=0; i < numTables; ++i) { + stbtt_uint32 encoding_record = cmap + 4 + 8 * i; + // find an encoding we understand: + switch(ttUSHORT(data+encoding_record)) { + case STBTT_PLATFORM_ID_MICROSOFT: + switch (ttUSHORT(data+encoding_record+2)) { + case STBTT_MS_EID_UNICODE_BMP: + case STBTT_MS_EID_UNICODE_FULL: + // MS/Unicode + info->index_map = cmap + ttULONG(data+encoding_record+4); + break; + } + break; + case STBTT_PLATFORM_ID_UNICODE: + // Mac/iOS has these + // all the encodingIDs are unicode, so we don't bother to check it + info->index_map = cmap + ttULONG(data+encoding_record+4); + break; + } + } + if (info->index_map == 0) + return 0; + + info->indexToLocFormat = ttUSHORT(data+info->head + 50); + return 1; +} + +STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint) +{ + stbtt_uint8 *data = info->data; + stbtt_uint32 index_map = info->index_map; + + stbtt_uint16 format = ttUSHORT(data + index_map + 0); + if (format == 0) { // apple byte encoding + stbtt_int32 bytes = ttUSHORT(data + index_map + 2); + if (unicode_codepoint < bytes-6) + return ttBYTE(data + index_map + 6 + unicode_codepoint); + return 0; + } else if (format == 6) { + stbtt_uint32 first = ttUSHORT(data + index_map + 6); + stbtt_uint32 count = ttUSHORT(data + index_map + 8); + if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32) unicode_codepoint < first+count) + return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2); + return 0; + } else if (format == 2) { + STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean + return 0; + } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges + stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1; + stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1; + stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10); + stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1; + + // do a binary search of the segments + stbtt_uint32 endCount = index_map + 14; + stbtt_uint32 search = endCount; + + if (unicode_codepoint > 0xffff) + return 0; + + // they lie from endCount .. endCount + segCount + // but searchRange is the nearest power of two, so... + if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2)) + search += rangeShift*2; + + // now decrement to bias correctly to find smallest + search -= 2; + while (entrySelector) { + stbtt_uint16 end; + searchRange >>= 1; + end = ttUSHORT(data + search + searchRange*2); + if (unicode_codepoint > end) + search += searchRange*2; + --entrySelector; + } + search += 2; + + { + stbtt_uint16 offset, start, last; + stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1); + + start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item); + last = ttUSHORT(data + endCount + 2*item); + if (unicode_codepoint < start || unicode_codepoint > last) + return 0; + + offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item); + if (offset == 0) + return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item)); + + return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item); + } + } else if (format == 12 || format == 13) { + stbtt_uint32 ngroups = ttULONG(data+index_map+12); + stbtt_int32 low,high; + low = 0; high = (stbtt_int32)ngroups; + // Binary search the right group. + while (low < high) { + stbtt_int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high + stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12); + stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4); + if ((stbtt_uint32) unicode_codepoint < start_char) + high = mid; + else if ((stbtt_uint32) unicode_codepoint > end_char) + low = mid+1; + else { + stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8); + if (format == 12) + return start_glyph + unicode_codepoint-start_char; + else // format == 13 + return start_glyph; + } + } + return 0; // not found + } + // @TODO + STBTT_assert(0); + return 0; +} + +STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices) +{ + return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices); +} + +static void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy) +{ + v->type = type; + v->x = (stbtt_int16) x; + v->y = (stbtt_int16) y; + v->cx = (stbtt_int16) cx; + v->cy = (stbtt_int16) cy; +} + +static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index) +{ + int g1,g2; + + STBTT_assert(!info->cff.size); + + if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range + if (info->indexToLocFormat >= 2) return -1; // unknown index->glyph map format + + if (info->indexToLocFormat == 0) { + g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2; + g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2; + } else { + g1 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4); + g2 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4 + 4); + } + + return g1==g2 ? -1 : g1; // if length is 0, return -1 +} + +static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); + +STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) +{ + if (info->cff.size) { + stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1); + } else { + int g = stbtt__GetGlyfOffset(info, glyph_index); + if (g < 0) return 0; + + if (x0) *x0 = ttSHORT(info->data + g + 2); + if (y0) *y0 = ttSHORT(info->data + g + 4); + if (x1) *x1 = ttSHORT(info->data + g + 6); + if (y1) *y1 = ttSHORT(info->data + g + 8); + } + return 1; +} + +STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1) +{ + return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1); +} + +STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index) +{ + stbtt_int16 numberOfContours; + int g; + if (info->cff.size) + return stbtt__GetGlyphInfoT2(info, glyph_index, NULL, NULL, NULL, NULL) == 0; + g = stbtt__GetGlyfOffset(info, glyph_index); + if (g < 0) return 1; + numberOfContours = ttSHORT(info->data + g); + return numberOfContours == 0; +} + +static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off, + stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy) +{ + if (start_off) { + if (was_off) + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy); + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy); + } else { + if (was_off) + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy); + else + stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0); + } + return num_vertices; +} + +static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) +{ + stbtt_int16 numberOfContours; + stbtt_uint8 *endPtsOfContours; + stbtt_uint8 *data = info->data; + stbtt_vertex *vertices=0; + int num_vertices=0; + int g = stbtt__GetGlyfOffset(info, glyph_index); + + *pvertices = NULL; + + if (g < 0) return 0; + + numberOfContours = ttSHORT(data + g); + + if (numberOfContours > 0) { + stbtt_uint8 flags=0,flagcount; + stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0; + stbtt_int32 x,y,cx,cy,sx,sy, scx,scy; + stbtt_uint8 *points; + endPtsOfContours = (data + g + 10); + ins = ttUSHORT(data + g + 10 + numberOfContours * 2); + points = data + g + 10 + numberOfContours * 2 + 2 + ins; + + n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2); + + m = n + 2*numberOfContours; // a loose bound on how many vertices we might need + vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata); + if (vertices == 0) + return 0; + + next_move = 0; + flagcount=0; + + // in first pass, we load uninterpreted data into the allocated array + // above, shifted to the end of the array so we won't overwrite it when + // we create our final data starting from the front + + off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated + + // first load flags + + for (i=0; i < n; ++i) { + if (flagcount == 0) { + flags = *points++; + if (flags & 8) + flagcount = *points++; + } else + --flagcount; + vertices[off+i].type = flags; + } + + // now load x coordinates + x=0; + for (i=0; i < n; ++i) { + flags = vertices[off+i].type; + if (flags & 2) { + stbtt_int16 dx = *points++; + x += (flags & 16) ? dx : -dx; // ??? + } else { + if (!(flags & 16)) { + x = x + (stbtt_int16) (points[0]*256 + points[1]); + points += 2; + } + } + vertices[off+i].x = (stbtt_int16) x; + } + + // now load y coordinates + y=0; + for (i=0; i < n; ++i) { + flags = vertices[off+i].type; + if (flags & 4) { + stbtt_int16 dy = *points++; + y += (flags & 32) ? dy : -dy; // ??? + } else { + if (!(flags & 32)) { + y = y + (stbtt_int16) (points[0]*256 + points[1]); + points += 2; + } + } + vertices[off+i].y = (stbtt_int16) y; + } + + // now convert them to our format + num_vertices=0; + sx = sy = cx = cy = scx = scy = 0; + for (i=0; i < n; ++i) { + flags = vertices[off+i].type; + x = (stbtt_int16) vertices[off+i].x; + y = (stbtt_int16) vertices[off+i].y; + + if (next_move == i) { + if (i != 0) + num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); + + // now start the new one + start_off = !(flags & 1); + if (start_off) { + // if we start off with an off-curve point, then when we need to find a point on the curve + // where we can start, and we need to save some state for when we wraparound. + scx = x; + scy = y; + if (!(vertices[off+i+1].type & 1)) { + // next point is also a curve point, so interpolate an on-point curve + sx = (x + (stbtt_int32) vertices[off+i+1].x) >> 1; + sy = (y + (stbtt_int32) vertices[off+i+1].y) >> 1; + } else { + // otherwise just use the next point as our start point + sx = (stbtt_int32) vertices[off+i+1].x; + sy = (stbtt_int32) vertices[off+i+1].y; + ++i; // we're using point i+1 as the starting point, so skip it + } + } else { + sx = x; + sy = y; + } + stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0); + was_off = 0; + next_move = 1 + ttUSHORT(endPtsOfContours+j*2); + ++j; + } else { + if (!(flags & 1)) { // if it's a curve + if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy); + cx = x; + cy = y; + was_off = 1; + } else { + if (was_off) + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy); + else + stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0); + was_off = 0; + } + } + } + num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); + } else if (numberOfContours < 0) { + // Compound shapes. + int more = 1; + stbtt_uint8 *comp = data + g + 10; + num_vertices = 0; + vertices = 0; + while (more) { + stbtt_uint16 flags, gidx; + int comp_num_verts = 0, i; + stbtt_vertex *comp_verts = 0, *tmp = 0; + float mtx[6] = {1,0,0,1,0,0}, m, n; + + flags = ttSHORT(comp); comp+=2; + gidx = ttSHORT(comp); comp+=2; + + if (flags & 2) { // XY values + if (flags & 1) { // shorts + mtx[4] = ttSHORT(comp); comp+=2; + mtx[5] = ttSHORT(comp); comp+=2; + } else { + mtx[4] = ttCHAR(comp); comp+=1; + mtx[5] = ttCHAR(comp); comp+=1; + } + } + else { + // @TODO handle matching point + STBTT_assert(0); + } + if (flags & (1<<3)) { // WE_HAVE_A_SCALE + mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[1] = mtx[2] = 0; + } else if (flags & (1<<6)) { // WE_HAVE_AN_X_AND_YSCALE + mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[1] = mtx[2] = 0; + mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; + } else if (flags & (1<<7)) { // WE_HAVE_A_TWO_BY_TWO + mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[1] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[2] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; + } + + // Find transformation scales. + m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]); + n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]); + + // Get indexed glyph. + comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts); + if (comp_num_verts > 0) { + // Transform vertices. + for (i = 0; i < comp_num_verts; ++i) { + stbtt_vertex* v = &comp_verts[i]; + stbtt_vertex_type x,y; + x=v->x; y=v->y; + v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); + v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); + x=v->cx; y=v->cy; + v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); + v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); + } + // Append vertices. + tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata); + if (!tmp) { + if (vertices) STBTT_free(vertices, info->userdata); + if (comp_verts) STBTT_free(comp_verts, info->userdata); + return 0; + } + if (num_vertices > 0 && vertices) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); + STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex)); + if (vertices) STBTT_free(vertices, info->userdata); + vertices = tmp; + STBTT_free(comp_verts, info->userdata); + num_vertices += comp_num_verts; + } + // More components ? + more = flags & (1<<5); + } + } else { + // numberOfCounters == 0, do nothing + } + + *pvertices = vertices; + return num_vertices; +} + +typedef struct +{ + int bounds; + int started; + float first_x, first_y; + float x, y; + stbtt_int32 min_x, max_x, min_y, max_y; + + stbtt_vertex *pvertices; + int num_vertices; +} stbtt__csctx; + +#define STBTT__CSCTX_INIT(bounds) {bounds,0, 0,0, 0,0, 0,0,0,0, NULL, 0} + +static void stbtt__track_vertex(stbtt__csctx *c, stbtt_int32 x, stbtt_int32 y) +{ + if (x > c->max_x || !c->started) c->max_x = x; + if (y > c->max_y || !c->started) c->max_y = y; + if (x < c->min_x || !c->started) c->min_x = x; + if (y < c->min_y || !c->started) c->min_y = y; + c->started = 1; +} + +static void stbtt__csctx_v(stbtt__csctx *c, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy, stbtt_int32 cx1, stbtt_int32 cy1) +{ + if (c->bounds) { + stbtt__track_vertex(c, x, y); + if (type == STBTT_vcubic) { + stbtt__track_vertex(c, cx, cy); + stbtt__track_vertex(c, cx1, cy1); + } + } else { + stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy); + c->pvertices[c->num_vertices].cx1 = (stbtt_int16) cx1; + c->pvertices[c->num_vertices].cy1 = (stbtt_int16) cy1; + } + c->num_vertices++; +} + +static void stbtt__csctx_close_shape(stbtt__csctx *ctx) +{ + if (ctx->first_x != ctx->x || ctx->first_y != ctx->y) + stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->first_x, (int)ctx->first_y, 0, 0, 0, 0); +} + +static void stbtt__csctx_rmove_to(stbtt__csctx *ctx, float dx, float dy) +{ + stbtt__csctx_close_shape(ctx); + ctx->first_x = ctx->x = ctx->x + dx; + ctx->first_y = ctx->y = ctx->y + dy; + stbtt__csctx_v(ctx, STBTT_vmove, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); +} + +static void stbtt__csctx_rline_to(stbtt__csctx *ctx, float dx, float dy) +{ + ctx->x += dx; + ctx->y += dy; + stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); +} + +static void stbtt__csctx_rccurve_to(stbtt__csctx *ctx, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3) +{ + float cx1 = ctx->x + dx1; + float cy1 = ctx->y + dy1; + float cx2 = cx1 + dx2; + float cy2 = cy1 + dy2; + ctx->x = cx2 + dx3; + ctx->y = cy2 + dy3; + stbtt__csctx_v(ctx, STBTT_vcubic, (int)ctx->x, (int)ctx->y, (int)cx1, (int)cy1, (int)cx2, (int)cy2); +} + +static stbtt__buf stbtt__get_subr(stbtt__buf idx, int n) +{ + int count = stbtt__cff_index_count(&idx); + int bias = 107; + if (count >= 33900) + bias = 32768; + else if (count >= 1240) + bias = 1131; + n += bias; + if (n < 0 || n >= count) + return stbtt__new_buf(NULL, 0); + return stbtt__cff_index_get(idx, n); +} + +static stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo *info, int glyph_index) +{ + stbtt__buf fdselect = info->fdselect; + int nranges, start, end, v, fmt, fdselector = -1, i; + + stbtt__buf_seek(&fdselect, 0); + fmt = stbtt__buf_get8(&fdselect); + if (fmt == 0) { + // untested + stbtt__buf_skip(&fdselect, glyph_index); + fdselector = stbtt__buf_get8(&fdselect); + } else if (fmt == 3) { + nranges = stbtt__buf_get16(&fdselect); + start = stbtt__buf_get16(&fdselect); + for (i = 0; i < nranges; i++) { + v = stbtt__buf_get8(&fdselect); + end = stbtt__buf_get16(&fdselect); + if (glyph_index >= start && glyph_index < end) { + fdselector = v; + break; + } + start = end; + } + } + if (fdselector == -1) stbtt__new_buf(NULL, 0); + return stbtt__get_subrs(info->cff, stbtt__cff_index_get(info->fontdicts, fdselector)); +} + +static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, stbtt__csctx *c) +{ + int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0; + int has_subrs = 0, clear_stack; + float s[48]; + stbtt__buf subr_stack[10], subrs = info->subrs, b; + float f; + +#define STBTT__CSERR(s) (0) + + // this currently ignores the initial width value, which isn't needed if we have hmtx + b = stbtt__cff_index_get(info->charstrings, glyph_index); + while (b.cursor < b.size) { + i = 0; + clear_stack = 1; + b0 = stbtt__buf_get8(&b); + switch (b0) { + // @TODO implement hinting + case 0x13: // hintmask + case 0x14: // cntrmask + if (in_header) + maskbits += (sp / 2); // implicit "vstem" + in_header = 0; + stbtt__buf_skip(&b, (maskbits + 7) / 8); + break; + + case 0x01: // hstem + case 0x03: // vstem + case 0x12: // hstemhm + case 0x17: // vstemhm + maskbits += (sp / 2); + break; + + case 0x15: // rmoveto + in_header = 0; + if (sp < 2) return STBTT__CSERR("rmoveto stack"); + stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]); + break; + case 0x04: // vmoveto + in_header = 0; + if (sp < 1) return STBTT__CSERR("vmoveto stack"); + stbtt__csctx_rmove_to(c, 0, s[sp-1]); + break; + case 0x16: // hmoveto + in_header = 0; + if (sp < 1) return STBTT__CSERR("hmoveto stack"); + stbtt__csctx_rmove_to(c, s[sp-1], 0); + break; + + case 0x05: // rlineto + if (sp < 2) return STBTT__CSERR("rlineto stack"); + for (; i + 1 < sp; i += 2) + stbtt__csctx_rline_to(c, s[i], s[i+1]); + break; + + // hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical + // starting from a different place. + + case 0x07: // vlineto + if (sp < 1) return STBTT__CSERR("vlineto stack"); + goto vlineto; + case 0x06: // hlineto + if (sp < 1) return STBTT__CSERR("hlineto stack"); + for (;;) { + if (i >= sp) break; + stbtt__csctx_rline_to(c, s[i], 0); + i++; + vlineto: + if (i >= sp) break; + stbtt__csctx_rline_to(c, 0, s[i]); + i++; + } + break; + + case 0x1F: // hvcurveto + if (sp < 4) return STBTT__CSERR("hvcurveto stack"); + goto hvcurveto; + case 0x1E: // vhcurveto + if (sp < 4) return STBTT__CSERR("vhcurveto stack"); + for (;;) { + if (i + 3 >= sp) break; + stbtt__csctx_rccurve_to(c, 0, s[i], s[i+1], s[i+2], s[i+3], (sp - i == 5) ? s[i + 4] : 0.0f); + i += 4; + hvcurveto: + if (i + 3 >= sp) break; + stbtt__csctx_rccurve_to(c, s[i], 0, s[i+1], s[i+2], (sp - i == 5) ? s[i+4] : 0.0f, s[i+3]); + i += 4; + } + break; + + case 0x08: // rrcurveto + if (sp < 6) return STBTT__CSERR("rcurveline stack"); + for (; i + 5 < sp; i += 6) + stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); + break; + + case 0x18: // rcurveline + if (sp < 8) return STBTT__CSERR("rcurveline stack"); + for (; i + 5 < sp - 2; i += 6) + stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); + if (i + 1 >= sp) return STBTT__CSERR("rcurveline stack"); + stbtt__csctx_rline_to(c, s[i], s[i+1]); + break; + + case 0x19: // rlinecurve + if (sp < 8) return STBTT__CSERR("rlinecurve stack"); + for (; i + 1 < sp - 6; i += 2) + stbtt__csctx_rline_to(c, s[i], s[i+1]); + if (i + 5 >= sp) return STBTT__CSERR("rlinecurve stack"); + stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); + break; + + case 0x1A: // vvcurveto + case 0x1B: // hhcurveto + if (sp < 4) return STBTT__CSERR("(vv|hh)curveto stack"); + f = 0.0; + if (sp & 1) { f = s[i]; i++; } + for (; i + 3 < sp; i += 4) { + if (b0 == 0x1B) + stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0); + else + stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]); + f = 0.0; + } + break; + + case 0x0A: // callsubr + if (!has_subrs) { + if (info->fdselect.size) + subrs = stbtt__cid_get_glyph_subrs(info, glyph_index); + has_subrs = 1; + } + // FALLTHROUGH + case 0x1D: // callgsubr + if (sp < 1) return STBTT__CSERR("call(g|)subr stack"); + v = (int) s[--sp]; + if (subr_stack_height >= 10) return STBTT__CSERR("recursion limit"); + subr_stack[subr_stack_height++] = b; + b = stbtt__get_subr(b0 == 0x0A ? subrs : info->gsubrs, v); + if (b.size == 0) return STBTT__CSERR("subr not found"); + b.cursor = 0; + clear_stack = 0; + break; + + case 0x0B: // return + if (subr_stack_height <= 0) return STBTT__CSERR("return outside subr"); + b = subr_stack[--subr_stack_height]; + clear_stack = 0; + break; + + case 0x0E: // endchar + stbtt__csctx_close_shape(c); + return 1; + + case 0x0C: { // two-byte escape + float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6; + float dx, dy; + int b1 = stbtt__buf_get8(&b); + switch (b1) { + // @TODO These "flex" implementations ignore the flex-depth and resolution, + // and always draw beziers. + case 0x22: // hflex + if (sp < 7) return STBTT__CSERR("hflex stack"); + dx1 = s[0]; + dx2 = s[1]; + dy2 = s[2]; + dx3 = s[3]; + dx4 = s[4]; + dx5 = s[5]; + dx6 = s[6]; + stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0); + stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0); + break; + + case 0x23: // flex + if (sp < 13) return STBTT__CSERR("flex stack"); + dx1 = s[0]; + dy1 = s[1]; + dx2 = s[2]; + dy2 = s[3]; + dx3 = s[4]; + dy3 = s[5]; + dx4 = s[6]; + dy4 = s[7]; + dx5 = s[8]; + dy5 = s[9]; + dx6 = s[10]; + dy6 = s[11]; + //fd is s[12] + stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); + stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); + break; + + case 0x24: // hflex1 + if (sp < 9) return STBTT__CSERR("hflex1 stack"); + dx1 = s[0]; + dy1 = s[1]; + dx2 = s[2]; + dy2 = s[3]; + dx3 = s[4]; + dx4 = s[5]; + dx5 = s[6]; + dy5 = s[7]; + dx6 = s[8]; + stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0); + stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5)); + break; + + case 0x25: // flex1 + if (sp < 11) return STBTT__CSERR("flex1 stack"); + dx1 = s[0]; + dy1 = s[1]; + dx2 = s[2]; + dy2 = s[3]; + dx3 = s[4]; + dy3 = s[5]; + dx4 = s[6]; + dy4 = s[7]; + dx5 = s[8]; + dy5 = s[9]; + dx6 = dy6 = s[10]; + dx = dx1+dx2+dx3+dx4+dx5; + dy = dy1+dy2+dy3+dy4+dy5; + if (STBTT_fabs(dx) > STBTT_fabs(dy)) + dy6 = -dy; + else + dx6 = -dx; + stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); + stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); + break; + + default: + return STBTT__CSERR("unimplemented"); + } + } break; + + default: + if (b0 != 255 && b0 != 28 && b0 < 32) + return STBTT__CSERR("reserved operator"); + + // push immediate + if (b0 == 255) { + f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000; + } else { + stbtt__buf_skip(&b, -1); + f = (float)(stbtt_int16)stbtt__cff_int(&b); + } + if (sp >= 48) return STBTT__CSERR("push stack overflow"); + s[sp++] = f; + clear_stack = 0; + break; + } + if (clear_stack) sp = 0; + } + return STBTT__CSERR("no endchar"); + +#undef STBTT__CSERR +} + +static int stbtt__GetGlyphShapeT2(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) +{ + // runs the charstring twice, once to count and once to output (to avoid realloc) + stbtt__csctx count_ctx = STBTT__CSCTX_INIT(1); + stbtt__csctx output_ctx = STBTT__CSCTX_INIT(0); + if (stbtt__run_charstring(info, glyph_index, &count_ctx)) { + *pvertices = (stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices*sizeof(stbtt_vertex), info->userdata); + output_ctx.pvertices = *pvertices; + if (stbtt__run_charstring(info, glyph_index, &output_ctx)) { + STBTT_assert(output_ctx.num_vertices == count_ctx.num_vertices); + return output_ctx.num_vertices; + } + } + *pvertices = NULL; + return 0; +} + +static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) +{ + stbtt__csctx c = STBTT__CSCTX_INIT(1); + int r = stbtt__run_charstring(info, glyph_index, &c); + if (x0) *x0 = r ? c.min_x : 0; + if (y0) *y0 = r ? c.min_y : 0; + if (x1) *x1 = r ? c.max_x : 0; + if (y1) *y1 = r ? c.max_y : 0; + return r ? c.num_vertices : 0; +} + +STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) +{ + if (!info->cff.size) + return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices); + else + return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices); +} + +STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing) +{ + stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34); + if (glyph_index < numOfLongHorMetrics) { + if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*glyph_index); + if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*glyph_index + 2); + } else { + if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1)); + if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics)); + } +} + +STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info) +{ + stbtt_uint8 *data = info->data + info->kern; + + // we only look at the first table. it must be 'horizontal' and format 0. + if (!info->kern) + return 0; + if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 + return 0; + if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format + return 0; + + return ttUSHORT(data+10); +} + +STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length) +{ + stbtt_uint8 *data = info->data + info->kern; + int k, length; + + // we only look at the first table. it must be 'horizontal' and format 0. + if (!info->kern) + return 0; + if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 + return 0; + if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format + return 0; + + length = ttUSHORT(data+10); + if (table_length < length) + length = table_length; + + for (k = 0; k < length; k++) + { + table[k].glyph1 = ttUSHORT(data+18+(k*6)); + table[k].glyph2 = ttUSHORT(data+20+(k*6)); + table[k].advance = ttSHORT(data+22+(k*6)); + } + + return length; +} + +static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) +{ + stbtt_uint8 *data = info->data + info->kern; + stbtt_uint32 needle, straw; + int l, r, m; + + // we only look at the first table. it must be 'horizontal' and format 0. + if (!info->kern) + return 0; + if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 + return 0; + if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format + return 0; + + l = 0; + r = ttUSHORT(data+10) - 1; + needle = glyph1 << 16 | glyph2; + while (l <= r) { + m = (l + r) >> 1; + straw = ttULONG(data+18+(m*6)); // note: unaligned read + if (needle < straw) + r = m - 1; + else if (needle > straw) + l = m + 1; + else + return ttSHORT(data+22+(m*6)); + } + return 0; +} + +static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph) +{ + stbtt_uint16 coverageFormat = ttUSHORT(coverageTable); + switch (coverageFormat) { + case 1: { + stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2); + + // Binary search. + stbtt_int32 l=0, r=glyphCount-1, m; + int straw, needle=glyph; + while (l <= r) { + stbtt_uint8 *glyphArray = coverageTable + 4; + stbtt_uint16 glyphID; + m = (l + r) >> 1; + glyphID = ttUSHORT(glyphArray + 2 * m); + straw = glyphID; + if (needle < straw) + r = m - 1; + else if (needle > straw) + l = m + 1; + else { + return m; + } + } + break; + } + + case 2: { + stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2); + stbtt_uint8 *rangeArray = coverageTable + 4; + + // Binary search. + stbtt_int32 l=0, r=rangeCount-1, m; + int strawStart, strawEnd, needle=glyph; + while (l <= r) { + stbtt_uint8 *rangeRecord; + m = (l + r) >> 1; + rangeRecord = rangeArray + 6 * m; + strawStart = ttUSHORT(rangeRecord); + strawEnd = ttUSHORT(rangeRecord + 2); + if (needle < strawStart) + r = m - 1; + else if (needle > strawEnd) + l = m + 1; + else { + stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4); + return startCoverageIndex + glyph - strawStart; + } + } + break; + } + + default: return -1; // unsupported + } + + return -1; +} + +static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph) +{ + stbtt_uint16 classDefFormat = ttUSHORT(classDefTable); + switch (classDefFormat) + { + case 1: { + stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2); + stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4); + stbtt_uint8 *classDef1ValueArray = classDefTable + 6; + + if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount) + return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID)); + break; + } + + case 2: { + stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2); + stbtt_uint8 *classRangeRecords = classDefTable + 4; + + // Binary search. + stbtt_int32 l=0, r=classRangeCount-1, m; + int strawStart, strawEnd, needle=glyph; + while (l <= r) { + stbtt_uint8 *classRangeRecord; + m = (l + r) >> 1; + classRangeRecord = classRangeRecords + 6 * m; + strawStart = ttUSHORT(classRangeRecord); + strawEnd = ttUSHORT(classRangeRecord + 2); + if (needle < strawStart) + r = m - 1; + else if (needle > strawEnd) + l = m + 1; + else + return (stbtt_int32)ttUSHORT(classRangeRecord + 4); + } + break; + } + + default: + return -1; // Unsupported definition type, return an error. + } + + // "All glyphs not assigned to a class fall into class 0". (OpenType spec) + return 0; +} + +// Define to STBTT_assert(x) if you want to break on unimplemented formats. +#define STBTT_GPOS_TODO_assert(x) + +static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) +{ + stbtt_uint16 lookupListOffset; + stbtt_uint8 *lookupList; + stbtt_uint16 lookupCount; + stbtt_uint8 *data; + stbtt_int32 i, sti; + + if (!info->gpos) return 0; + + data = info->data + info->gpos; + + if (ttUSHORT(data+0) != 1) return 0; // Major version 1 + if (ttUSHORT(data+2) != 0) return 0; // Minor version 0 + + lookupListOffset = ttUSHORT(data+8); + lookupList = data + lookupListOffset; + lookupCount = ttUSHORT(lookupList); + + for (i=0; i= pairSetCount) return 0; + + needle=glyph2; + r=pairValueCount-1; + l=0; + + // Binary search. + while (l <= r) { + stbtt_uint16 secondGlyph; + stbtt_uint8 *pairValue; + m = (l + r) >> 1; + pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m; + secondGlyph = ttUSHORT(pairValue); + straw = secondGlyph; + if (needle < straw) + r = m - 1; + else if (needle > straw) + l = m + 1; + else { + stbtt_int16 xAdvance = ttSHORT(pairValue + 2); + return xAdvance; + } + } + } else + return 0; + break; + } + + case 2: { + stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); + stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); + if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats? + stbtt_uint16 classDef1Offset = ttUSHORT(table + 8); + stbtt_uint16 classDef2Offset = ttUSHORT(table + 10); + int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1); + int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2); + + stbtt_uint16 class1Count = ttUSHORT(table + 12); + stbtt_uint16 class2Count = ttUSHORT(table + 14); + stbtt_uint8 *class1Records, *class2Records; + stbtt_int16 xAdvance; + + if (glyph1class < 0 || glyph1class >= class1Count) return 0; // malformed + if (glyph2class < 0 || glyph2class >= class2Count) return 0; // malformed + + class1Records = table + 16; + class2Records = class1Records + 2 * (glyph1class * class2Count); + xAdvance = ttSHORT(class2Records + 2 * glyph2class); + return xAdvance; + } else + return 0; + break; + } + + default: + return 0; // Unsupported position format + } + } + } + + return 0; +} + +STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2) +{ + int xAdvance = 0; + + if (info->gpos) + xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2); + else if (info->kern) + xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2); + + return xAdvance; +} + +STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2) +{ + if (!info->kern && !info->gpos) // if no kerning table, don't waste time looking up both codepoint->glyphs + return 0; + return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2)); +} + +STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing) +{ + stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing); +} + +STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap) +{ + if (ascent ) *ascent = ttSHORT(info->data+info->hhea + 4); + if (descent) *descent = ttSHORT(info->data+info->hhea + 6); + if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8); +} + +STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap) +{ + int tab = stbtt__find_table(info->data, info->fontstart, "OS/2"); + if (!tab) + return 0; + if (typoAscent ) *typoAscent = ttSHORT(info->data+tab + 68); + if (typoDescent) *typoDescent = ttSHORT(info->data+tab + 70); + if (typoLineGap) *typoLineGap = ttSHORT(info->data+tab + 72); + return 1; +} + +STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1) +{ + *x0 = ttSHORT(info->data + info->head + 36); + *y0 = ttSHORT(info->data + info->head + 38); + *x1 = ttSHORT(info->data + info->head + 40); + *y1 = ttSHORT(info->data + info->head + 42); +} + +STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height) +{ + int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6); + return (float) height / fheight; +} + +STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels) +{ + int unitsPerEm = ttUSHORT(info->data + info->head + 18); + return pixels / unitsPerEm; +} + +STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v) +{ + STBTT_free(v, info->userdata); +} + +STBTT_DEF stbtt_uint8 *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl) +{ + int i; + stbtt_uint8 *data = info->data; + stbtt_uint8 *svg_doc_list = data + stbtt__get_svg((stbtt_fontinfo *) info); + + int numEntries = ttUSHORT(svg_doc_list); + stbtt_uint8 *svg_docs = svg_doc_list + 2; + + for(i=0; i= ttUSHORT(svg_doc)) && (gl <= ttUSHORT(svg_doc + 2))) + return svg_doc; + } + return 0; +} + +STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg) +{ + stbtt_uint8 *data = info->data; + stbtt_uint8 *svg_doc; + + if (info->svg == 0) + return 0; + + svg_doc = stbtt_FindSVGDoc(info, gl); + if (svg_doc != NULL) { + *svg = (char *) data + info->svg + ttULONG(svg_doc + 4); + return ttULONG(svg_doc + 8); + } else { + return 0; + } +} + +STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg) +{ + return stbtt_GetGlyphSVG(info, stbtt_FindGlyphIndex(info, unicode_codepoint), svg); +} + +////////////////////////////////////////////////////////////////////////////// +// +// antialiasing software rasterizer +// + +STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) +{ + int x0=0,y0=0,x1,y1; // =0 suppresses compiler warning + if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) { + // e.g. space character + if (ix0) *ix0 = 0; + if (iy0) *iy0 = 0; + if (ix1) *ix1 = 0; + if (iy1) *iy1 = 0; + } else { + // move to integral bboxes (treating pixels as little squares, what pixels get touched)? + if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x); + if (iy0) *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y); + if (ix1) *ix1 = STBTT_iceil ( x1 * scale_x + shift_x); + if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y); + } +} + +STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) +{ + stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1); +} + +STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) +{ + stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1); +} + +STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) +{ + stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1); +} + +////////////////////////////////////////////////////////////////////////////// +// +// Rasterizer + +typedef struct stbtt__hheap_chunk +{ + struct stbtt__hheap_chunk *next; +} stbtt__hheap_chunk; + +typedef struct stbtt__hheap +{ + struct stbtt__hheap_chunk *head; + void *first_free; + int num_remaining_in_head_chunk; +} stbtt__hheap; + +static void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata) +{ + if (hh->first_free) { + void *p = hh->first_free; + hh->first_free = * (void **) p; + return p; + } else { + if (hh->num_remaining_in_head_chunk == 0) { + int count = (size < 32 ? 2000 : size < 128 ? 800 : 100); + stbtt__hheap_chunk *c = (stbtt__hheap_chunk *) STBTT_malloc(sizeof(stbtt__hheap_chunk) + size * count, userdata); + if (c == NULL) + return NULL; + c->next = hh->head; + hh->head = c; + hh->num_remaining_in_head_chunk = count; + } + --hh->num_remaining_in_head_chunk; + return (char *) (hh->head) + sizeof(stbtt__hheap_chunk) + size * hh->num_remaining_in_head_chunk; + } +} + +static void stbtt__hheap_free(stbtt__hheap *hh, void *p) +{ + *(void **) p = hh->first_free; + hh->first_free = p; +} + +static void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata) +{ + stbtt__hheap_chunk *c = hh->head; + while (c) { + stbtt__hheap_chunk *n = c->next; + STBTT_free(c, userdata); + c = n; + } +} + +typedef struct stbtt__edge { + float x0,y0, x1,y1; + int invert; +} stbtt__edge; + + +typedef struct stbtt__active_edge +{ + struct stbtt__active_edge *next; + #if STBTT_RASTERIZER_VERSION==1 + int x,dx; + float ey; + int direction; + #elif STBTT_RASTERIZER_VERSION==2 + float fx,fdx,fdy; + float direction; + float sy; + float ey; + #else + #error "Unrecognized value of STBTT_RASTERIZER_VERSION" + #endif +} stbtt__active_edge; + +#if STBTT_RASTERIZER_VERSION == 1 +#define STBTT_FIXSHIFT 10 +#define STBTT_FIX (1 << STBTT_FIXSHIFT) +#define STBTT_FIXMASK (STBTT_FIX-1) + +static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) +{ + stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); + float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); + STBTT_assert(z != NULL); + if (!z) return z; + + // round dx down to avoid overshooting + if (dxdy < 0) + z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy); + else + z->dx = STBTT_ifloor(STBTT_FIX * dxdy); + + z->x = STBTT_ifloor(STBTT_FIX * e->x0 + z->dx * (start_point - e->y0)); // use z->dx so when we offset later it's by the same amount + z->x -= off_x * STBTT_FIX; + + z->ey = e->y1; + z->next = 0; + z->direction = e->invert ? 1 : -1; + return z; +} +#elif STBTT_RASTERIZER_VERSION == 2 +static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) +{ + stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); + float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); + STBTT_assert(z != NULL); + //STBTT_assert(e->y0 <= start_point); + if (!z) return z; + z->fdx = dxdy; + z->fdy = dxdy != 0.0f ? (1.0f/dxdy) : 0.0f; + z->fx = e->x0 + dxdy * (start_point - e->y0); + z->fx -= off_x; + z->direction = e->invert ? 1.0f : -1.0f; + z->sy = e->y0; + z->ey = e->y1; + z->next = 0; + return z; +} +#else +#error "Unrecognized value of STBTT_RASTERIZER_VERSION" +#endif + +#if STBTT_RASTERIZER_VERSION == 1 +// note: this routine clips fills that extend off the edges... ideally this +// wouldn't happen, but it could happen if the truetype glyph bounding boxes +// are wrong, or if the user supplies a too-small bitmap +static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight) +{ + // non-zero winding fill + int x0=0, w=0; + + while (e) { + if (w == 0) { + // if we're currently at zero, we need to record the edge start point + x0 = e->x; w += e->direction; + } else { + int x1 = e->x; w += e->direction; + // if we went to zero, we need to draw + if (w == 0) { + int i = x0 >> STBTT_FIXSHIFT; + int j = x1 >> STBTT_FIXSHIFT; + + if (i < len && j >= 0) { + if (i == j) { + // x0,x1 are the same pixel, so compute combined coverage + scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT); + } else { + if (i >= 0) // add antialiasing for x0 + scanline[i] = scanline[i] + (stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT); + else + i = -1; // clip + + if (j < len) // add antialiasing for x1 + scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT); + else + j = len; // clip + + for (++i; i < j; ++i) // fill pixels between x0 and x1 + scanline[i] = scanline[i] + (stbtt_uint8) max_weight; + } + } + } + } + + e = e->next; + } +} + +static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) +{ + stbtt__hheap hh = { 0, 0, 0 }; + stbtt__active_edge *active = NULL; + int y,j=0; + int max_weight = (255 / vsubsample); // weight per vertical scanline + int s; // vertical subsample index + unsigned char scanline_data[512], *scanline; + + if (result->w > 512) + scanline = (unsigned char *) STBTT_malloc(result->w, userdata); + else + scanline = scanline_data; + + y = off_y * vsubsample; + e[n].y0 = (off_y + result->h) * (float) vsubsample + 1; + + while (j < result->h) { + STBTT_memset(scanline, 0, result->w); + for (s=0; s < vsubsample; ++s) { + // find center of pixel for this scanline + float scan_y = y + 0.5f; + stbtt__active_edge **step = &active; + + // update all active edges; + // remove all active edges that terminate before the center of this scanline + while (*step) { + stbtt__active_edge * z = *step; + if (z->ey <= scan_y) { + *step = z->next; // delete from list + STBTT_assert(z->direction); + z->direction = 0; + stbtt__hheap_free(&hh, z); + } else { + z->x += z->dx; // advance to position for current scanline + step = &((*step)->next); // advance through list + } + } + + // resort the list if needed + for(;;) { + int changed=0; + step = &active; + while (*step && (*step)->next) { + if ((*step)->x > (*step)->next->x) { + stbtt__active_edge *t = *step; + stbtt__active_edge *q = t->next; + + t->next = q->next; + q->next = t; + *step = q; + changed = 1; + } + step = &(*step)->next; + } + if (!changed) break; + } + + // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline + while (e->y0 <= scan_y) { + if (e->y1 > scan_y) { + stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata); + if (z != NULL) { + // find insertion point + if (active == NULL) + active = z; + else if (z->x < active->x) { + // insert at front + z->next = active; + active = z; + } else { + // find thing to insert AFTER + stbtt__active_edge *p = active; + while (p->next && p->next->x < z->x) + p = p->next; + // at this point, p->next->x is NOT < z->x + z->next = p->next; + p->next = z; + } + } + } + ++e; + } + + // now process all active edges in XOR fashion + if (active) + stbtt__fill_active_edges(scanline, result->w, active, max_weight); + + ++y; + } + STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w); + ++j; + } + + stbtt__hheap_cleanup(&hh, userdata); + + if (scanline != scanline_data) + STBTT_free(scanline, userdata); +} + +#elif STBTT_RASTERIZER_VERSION == 2 + +// the edge passed in here does not cross the vertical line at x or the vertical line at x+1 +// (i.e. it has already been clipped to those) +static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edge *e, float x0, float y0, float x1, float y1) +{ + if (y0 == y1) return; + STBTT_assert(y0 < y1); + STBTT_assert(e->sy <= e->ey); + if (y0 > e->ey) return; + if (y1 < e->sy) return; + if (y0 < e->sy) { + x0 += (x1-x0) * (e->sy - y0) / (y1-y0); + y0 = e->sy; + } + if (y1 > e->ey) { + x1 += (x1-x0) * (e->ey - y1) / (y1-y0); + y1 = e->ey; + } + + if (x0 == x) + STBTT_assert(x1 <= x+1); + else if (x0 == x+1) + STBTT_assert(x1 >= x); + else if (x0 <= x) + STBTT_assert(x1 <= x); + else if (x0 >= x+1) + STBTT_assert(x1 >= x+1); + else + STBTT_assert(x1 >= x && x1 <= x+1); + + if (x0 <= x && x1 <= x) + scanline[x] += e->direction * (y1-y0); + else if (x0 >= x+1 && x1 >= x+1) + ; + else { + STBTT_assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1); + scanline[x] += e->direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); // coverage = 1 - average x position + } +} + +static float stbtt__sized_trapezoid_area(float height, float top_width, float bottom_width) +{ + STBTT_assert(top_width >= 0); + STBTT_assert(bottom_width >= 0); + return (top_width + bottom_width) / 2.0f * height; +} + +static float stbtt__position_trapezoid_area(float height, float tx0, float tx1, float bx0, float bx1) +{ + return stbtt__sized_trapezoid_area(height, tx1 - tx0, bx1 - bx0); +} + +static float stbtt__sized_triangle_area(float height, float width) +{ + return height * width / 2; +} + +static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top) +{ + float y_bottom = y_top+1; + + while (e) { + // brute force every pixel + + // compute intersection points with top & bottom + STBTT_assert(e->ey >= y_top); + + if (e->fdx == 0) { + float x0 = e->fx; + if (x0 < len) { + if (x0 >= 0) { + stbtt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom); + stbtt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom); + } else { + stbtt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom); + } + } + } else { + float x0 = e->fx; + float dx = e->fdx; + float xb = x0 + dx; + float x_top, x_bottom; + float sy0,sy1; + float dy = e->fdy; + STBTT_assert(e->sy <= y_bottom && e->ey >= y_top); + + // compute endpoints of line segment clipped to this scanline (if the + // line segment starts on this scanline. x0 is the intersection of the + // line with y_top, but that may be off the line segment. + if (e->sy > y_top) { + x_top = x0 + dx * (e->sy - y_top); + sy0 = e->sy; + } else { + x_top = x0; + sy0 = y_top; + } + if (e->ey < y_bottom) { + x_bottom = x0 + dx * (e->ey - y_top); + sy1 = e->ey; + } else { + x_bottom = xb; + sy1 = y_bottom; + } + + if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) { + // from here on, we don't have to range check x values + + if ((int) x_top == (int) x_bottom) { + float height; + // simple case, only spans one pixel + int x = (int) x_top; + height = (sy1 - sy0) * e->direction; + STBTT_assert(x >= 0 && x < len); + scanline[x] += stbtt__position_trapezoid_area(height, x_top, x+1.0f, x_bottom, x+1.0f); + scanline_fill[x] += height; // everything right of this pixel is filled + } else { + int x,x1,x2; + float y_crossing, y_final, step, sign, area; + // covers 2+ pixels + if (x_top > x_bottom) { + // flip scanline vertically; signed area is the same + float t; + sy0 = y_bottom - (sy0 - y_top); + sy1 = y_bottom - (sy1 - y_top); + t = sy0, sy0 = sy1, sy1 = t; + t = x_bottom, x_bottom = x_top, x_top = t; + dx = -dx; + dy = -dy; + t = x0, x0 = xb, xb = t; + } + STBTT_assert(dy >= 0); + STBTT_assert(dx >= 0); + + x1 = (int) x_top; + x2 = (int) x_bottom; + // compute intersection with y axis at x1+1 + y_crossing = y_top + dy * (x1+1 - x0); + + // compute intersection with y axis at x2 + y_final = y_top + dy * (x2 - x0); + + // x1 x_top x2 x_bottom + // y_top +------|-----+------------+------------+--------|---+------------+ + // | | | | | | + // | | | | | | + // sy0 | Txxxxx|............|............|............|............| + // y_crossing | *xxxxx.......|............|............|............| + // | | xxxxx..|............|............|............| + // | | /- xx*xxxx........|............|............| + // | | dy < | xxxxxx..|............|............| + // y_final | | \- | xx*xxx.........|............| + // sy1 | | | | xxxxxB...|............| + // | | | | | | + // | | | | | | + // y_bottom +------------+------------+------------+------------+------------+ + // + // goal is to measure the area covered by '.' in each pixel + + // if x2 is right at the right edge of x1, y_crossing can blow up, github #1057 + // @TODO: maybe test against sy1 rather than y_bottom? + if (y_crossing > y_bottom) + y_crossing = y_bottom; + + sign = e->direction; + + // area of the rectangle covered from sy0..y_crossing + area = sign * (y_crossing-sy0); + + // area of the triangle (x_top,sy0), (x1+1,sy0), (x1+1,y_crossing) + scanline[x1] += stbtt__sized_triangle_area(area, x1+1 - x_top); + + // check if final y_crossing is blown up; no test case for this + if (y_final > y_bottom) { + y_final = y_bottom; + dy = (y_final - y_crossing ) / (x2 - (x1+1)); // if denom=0, y_final = y_crossing, so y_final <= y_bottom + } + + // in second pixel, area covered by line segment found in first pixel + // is always a rectangle 1 wide * the height of that line segment; this + // is exactly what the variable 'area' stores. it also gets a contribution + // from the line segment within it. the THIRD pixel will get the first + // pixel's rectangle contribution, the second pixel's rectangle contribution, + // and its own contribution. the 'own contribution' is the same in every pixel except + // the leftmost and rightmost, a trapezoid that slides down in each pixel. + // the second pixel's contribution to the third pixel will be the + // rectangle 1 wide times the height change in the second pixel, which is dy. + + step = sign * dy * 1; // dy is dy/dx, change in y for every 1 change in x, + // which multiplied by 1-pixel-width is how much pixel area changes for each step in x + // so the area advances by 'step' every time + + for (x = x1+1; x < x2; ++x) { + scanline[x] += area + step/2; // area of trapezoid is 1*step/2 + area += step; + } + STBTT_assert(STBTT_fabs(area) <= 1.01f); // accumulated error from area += step unless we round step down + STBTT_assert(sy1 > y_final-0.01f); + + // area covered in the last pixel is the rectangle from all the pixels to the left, + // plus the trapezoid filled by the line segment in this pixel all the way to the right edge + scanline[x2] += area + sign * stbtt__position_trapezoid_area(sy1-y_final, (float) x2, x2+1.0f, x_bottom, x2+1.0f); + + // the rest of the line is filled based on the total height of the line segment in this pixel + scanline_fill[x2] += sign * (sy1-sy0); + } + } else { + // if edge goes outside of box we're drawing, we require + // clipping logic. since this does not match the intended use + // of this library, we use a different, very slow brute + // force implementation + // note though that this does happen some of the time because + // x_top and x_bottom can be extrapolated at the top & bottom of + // the shape and actually lie outside the bounding box + int x; + for (x=0; x < len; ++x) { + // cases: + // + // there can be up to two intersections with the pixel. any intersection + // with left or right edges can be handled by splitting into two (or three) + // regions. intersections with top & bottom do not necessitate case-wise logic. + // + // the old way of doing this found the intersections with the left & right edges, + // then used some simple logic to produce up to three segments in sorted order + // from top-to-bottom. however, this had a problem: if an x edge was epsilon + // across the x border, then the corresponding y position might not be distinct + // from the other y segment, and it might ignored as an empty segment. to avoid + // that, we need to explicitly produce segments based on x positions. + + // rename variables to clearly-defined pairs + float y0 = y_top; + float x1 = (float) (x); + float x2 = (float) (x+1); + float x3 = xb; + float y3 = y_bottom; + + // x = e->x + e->dx * (y-y_top) + // (y-y_top) = (x - e->x) / e->dx + // y = (x - e->x) / e->dx + y_top + float y1 = (x - x0) / dx + y_top; + float y2 = (x+1 - x0) / dx + y_top; + + if (x0 < x1 && x3 > x2) { // three segments descending down-right + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); + stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x2,y2); + stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); + } else if (x3 < x1 && x0 > x2) { // three segments descending down-left + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); + stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x1,y1); + stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); + } else if (x0 < x1 && x3 > x1) { // two segments across x, down-right + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); + stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); + } else if (x3 < x1 && x0 > x1) { // two segments across x, down-left + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); + stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); + } else if (x0 < x2 && x3 > x2) { // two segments across x+1, down-right + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); + stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); + } else if (x3 < x2 && x0 > x2) { // two segments across x+1, down-left + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); + stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); + } else { // one segment + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3); + } + } + } + } + e = e->next; + } +} + +// directly AA rasterize edges w/o supersampling +static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) +{ + stbtt__hheap hh = { 0, 0, 0 }; + stbtt__active_edge *active = NULL; + int y,j=0, i; + float scanline_data[129], *scanline, *scanline2; + + STBTT__NOTUSED(vsubsample); + + if (result->w > 64) + scanline = (float *) STBTT_malloc((result->w*2+1) * sizeof(float), userdata); + else + scanline = scanline_data; + + scanline2 = scanline + result->w; + + y = off_y; + e[n].y0 = (float) (off_y + result->h) + 1; + + while (j < result->h) { + // find center of pixel for this scanline + float scan_y_top = y + 0.0f; + float scan_y_bottom = y + 1.0f; + stbtt__active_edge **step = &active; + + STBTT_memset(scanline , 0, result->w*sizeof(scanline[0])); + STBTT_memset(scanline2, 0, (result->w+1)*sizeof(scanline[0])); + + // update all active edges; + // remove all active edges that terminate before the top of this scanline + while (*step) { + stbtt__active_edge * z = *step; + if (z->ey <= scan_y_top) { + *step = z->next; // delete from list + STBTT_assert(z->direction); + z->direction = 0; + stbtt__hheap_free(&hh, z); + } else { + step = &((*step)->next); // advance through list + } + } + + // insert all edges that start before the bottom of this scanline + while (e->y0 <= scan_y_bottom) { + if (e->y0 != e->y1) { + stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata); + if (z != NULL) { + if (j == 0 && off_y != 0) { + if (z->ey < scan_y_top) { + // this can happen due to subpixel positioning and some kind of fp rounding error i think + z->ey = scan_y_top; + } + } + STBTT_assert(z->ey >= scan_y_top); // if we get really unlucky a tiny bit of an edge can be out of bounds + // insert at front + z->next = active; + active = z; + } + } + ++e; + } + + // now process all active edges + if (active) + stbtt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top); + + { + float sum = 0; + for (i=0; i < result->w; ++i) { + float k; + int m; + sum += scanline2[i]; + k = scanline[i] + sum; + k = (float) STBTT_fabs(k)*255 + 0.5f; + m = (int) k; + if (m > 255) m = 255; + result->pixels[j*result->stride + i] = (unsigned char) m; + } + } + // advance all the edges + step = &active; + while (*step) { + stbtt__active_edge *z = *step; + z->fx += z->fdx; // advance to position for current scanline + step = &((*step)->next); // advance through list + } + + ++y; + ++j; + } + + stbtt__hheap_cleanup(&hh, userdata); + + if (scanline != scanline_data) + STBTT_free(scanline, userdata); +} +#else +#error "Unrecognized value of STBTT_RASTERIZER_VERSION" +#endif + +#define STBTT__COMPARE(a,b) ((a)->y0 < (b)->y0) + +static void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n) +{ + int i,j; + for (i=1; i < n; ++i) { + stbtt__edge t = p[i], *a = &t; + j = i; + while (j > 0) { + stbtt__edge *b = &p[j-1]; + int c = STBTT__COMPARE(a,b); + if (!c) break; + p[j] = p[j-1]; + --j; + } + if (i != j) + p[j] = t; + } +} + +static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n) +{ + /* threshold for transitioning to insertion sort */ + while (n > 12) { + stbtt__edge t; + int c01,c12,c,m,i,j; + + /* compute median of three */ + m = n >> 1; + c01 = STBTT__COMPARE(&p[0],&p[m]); + c12 = STBTT__COMPARE(&p[m],&p[n-1]); + /* if 0 >= mid >= end, or 0 < mid < end, then use mid */ + if (c01 != c12) { + /* otherwise, we'll need to swap something else to middle */ + int z; + c = STBTT__COMPARE(&p[0],&p[n-1]); + /* 0>mid && midn => n; 0 0 */ + /* 0n: 0>n => 0; 0 n */ + z = (c == c12) ? 0 : n-1; + t = p[z]; + p[z] = p[m]; + p[m] = t; + } + /* now p[m] is the median-of-three */ + /* swap it to the beginning so it won't move around */ + t = p[0]; + p[0] = p[m]; + p[m] = t; + + /* partition loop */ + i=1; + j=n-1; + for(;;) { + /* handling of equality is crucial here */ + /* for sentinels & efficiency with duplicates */ + for (;;++i) { + if (!STBTT__COMPARE(&p[i], &p[0])) break; + } + for (;;--j) { + if (!STBTT__COMPARE(&p[0], &p[j])) break; + } + /* make sure we haven't crossed */ + if (i >= j) break; + t = p[i]; + p[i] = p[j]; + p[j] = t; + + ++i; + --j; + } + /* recurse on smaller side, iterate on larger */ + if (j < (n-i)) { + stbtt__sort_edges_quicksort(p,j); + p = p+i; + n = n-i; + } else { + stbtt__sort_edges_quicksort(p+i, n-i); + n = j; + } + } +} + +static void stbtt__sort_edges(stbtt__edge *p, int n) +{ + stbtt__sort_edges_quicksort(p, n); + stbtt__sort_edges_ins_sort(p, n); +} + +typedef struct +{ + float x,y; +} stbtt__point; + +static void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcount, int windings, float scale_x, float scale_y, float shift_x, float shift_y, int off_x, int off_y, int invert, void *userdata) +{ + float y_scale_inv = invert ? -scale_y : scale_y; + stbtt__edge *e; + int n,i,j,k,m; +#if STBTT_RASTERIZER_VERSION == 1 + int vsubsample = result->h < 8 ? 15 : 5; +#elif STBTT_RASTERIZER_VERSION == 2 + int vsubsample = 1; +#else + #error "Unrecognized value of STBTT_RASTERIZER_VERSION" +#endif + // vsubsample should divide 255 evenly; otherwise we won't reach full opacity + + // now we have to blow out the windings into explicit edge lists + n = 0; + for (i=0; i < windings; ++i) + n += wcount[i]; + + e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); // add an extra one as a sentinel + if (e == 0) return; + n = 0; + + m=0; + for (i=0; i < windings; ++i) { + stbtt__point *p = pts + m; + m += wcount[i]; + j = wcount[i]-1; + for (k=0; k < wcount[i]; j=k++) { + int a=k,b=j; + // skip the edge if horizontal + if (p[j].y == p[k].y) + continue; + // add edge from j to k to the list + e[n].invert = 0; + if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) { + e[n].invert = 1; + a=j,b=k; + } + e[n].x0 = p[a].x * scale_x + shift_x; + e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample; + e[n].x1 = p[b].x * scale_x + shift_x; + e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample; + ++n; + } + } + + // now sort the edges by their highest point (should snap to integer, and then by x) + //STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare); + stbtt__sort_edges(e, n); + + // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule + stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata); + + STBTT_free(e, userdata); +} + +static void stbtt__add_point(stbtt__point *points, int n, float x, float y) +{ + if (!points) return; // during first pass, it's unallocated + points[n].x = x; + points[n].y = y; +} + +// tessellate until threshold p is happy... @TODO warped to compensate for non-linear stretching +static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n) +{ + // midpoint + float mx = (x0 + 2*x1 + x2)/4; + float my = (y0 + 2*y1 + y2)/4; + // versus directly drawn line + float dx = (x0+x2)/2 - mx; + float dy = (y0+y2)/2 - my; + if (n > 16) // 65536 segments on one curve better be enough! + return 1; + if (dx*dx+dy*dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA + stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1); + stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1); + } else { + stbtt__add_point(points, *num_points,x2,y2); + *num_points = *num_points+1; + } + return 1; +} + +static void stbtt__tesselate_cubic(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float objspace_flatness_squared, int n) +{ + // @TODO this "flatness" calculation is just made-up nonsense that seems to work well enough + float dx0 = x1-x0; + float dy0 = y1-y0; + float dx1 = x2-x1; + float dy1 = y2-y1; + float dx2 = x3-x2; + float dy2 = y3-y2; + float dx = x3-x0; + float dy = y3-y0; + float longlen = (float) (STBTT_sqrt(dx0*dx0+dy0*dy0)+STBTT_sqrt(dx1*dx1+dy1*dy1)+STBTT_sqrt(dx2*dx2+dy2*dy2)); + float shortlen = (float) STBTT_sqrt(dx*dx+dy*dy); + float flatness_squared = longlen*longlen-shortlen*shortlen; + + if (n > 16) // 65536 segments on one curve better be enough! + return; + + if (flatness_squared > objspace_flatness_squared) { + float x01 = (x0+x1)/2; + float y01 = (y0+y1)/2; + float x12 = (x1+x2)/2; + float y12 = (y1+y2)/2; + float x23 = (x2+x3)/2; + float y23 = (y2+y3)/2; + + float xa = (x01+x12)/2; + float ya = (y01+y12)/2; + float xb = (x12+x23)/2; + float yb = (y12+y23)/2; + + float mx = (xa+xb)/2; + float my = (ya+yb)/2; + + stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1); + stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1); + } else { + stbtt__add_point(points, *num_points,x3,y3); + *num_points = *num_points+1; + } +} + +// returns number of contours +static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata) +{ + stbtt__point *points=0; + int num_points=0; + + float objspace_flatness_squared = objspace_flatness * objspace_flatness; + int i,n=0,start=0, pass; + + // count how many "moves" there are to get the contour count + for (i=0; i < num_verts; ++i) + if (vertices[i].type == STBTT_vmove) + ++n; + + *num_contours = n; + if (n == 0) return 0; + + *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata); + + if (*contour_lengths == 0) { + *num_contours = 0; + return 0; + } + + // make two passes through the points so we don't need to realloc + for (pass=0; pass < 2; ++pass) { + float x=0,y=0; + if (pass == 1) { + points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata); + if (points == NULL) goto error; + } + num_points = 0; + n= -1; + for (i=0; i < num_verts; ++i) { + switch (vertices[i].type) { + case STBTT_vmove: + // start the next contour + if (n >= 0) + (*contour_lengths)[n] = num_points - start; + ++n; + start = num_points; + + x = vertices[i].x, y = vertices[i].y; + stbtt__add_point(points, num_points++, x,y); + break; + case STBTT_vline: + x = vertices[i].x, y = vertices[i].y; + stbtt__add_point(points, num_points++, x, y); + break; + case STBTT_vcurve: + stbtt__tesselate_curve(points, &num_points, x,y, + vertices[i].cx, vertices[i].cy, + vertices[i].x, vertices[i].y, + objspace_flatness_squared, 0); + x = vertices[i].x, y = vertices[i].y; + break; + case STBTT_vcubic: + stbtt__tesselate_cubic(points, &num_points, x,y, + vertices[i].cx, vertices[i].cy, + vertices[i].cx1, vertices[i].cy1, + vertices[i].x, vertices[i].y, + objspace_flatness_squared, 0); + x = vertices[i].x, y = vertices[i].y; + break; + } + } + (*contour_lengths)[n] = num_points - start; + } + + return points; +error: + STBTT_free(points, userdata); + STBTT_free(*contour_lengths, userdata); + *contour_lengths = 0; + *num_contours = 0; + return NULL; +} + +STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata) +{ + float scale = scale_x > scale_y ? scale_y : scale_x; + int winding_count = 0; + int *winding_lengths = NULL; + stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata); + if (windings) { + stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata); + STBTT_free(winding_lengths, userdata); + STBTT_free(windings, userdata); + } +} + +STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata) +{ + STBTT_free(bitmap, userdata); +} + +STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff) +{ + int ix0,iy0,ix1,iy1; + stbtt__bitmap gbm; + stbtt_vertex *vertices; + int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); + + if (scale_x == 0) scale_x = scale_y; + if (scale_y == 0) { + if (scale_x == 0) { + STBTT_free(vertices, info->userdata); + return NULL; + } + scale_y = scale_x; + } + + stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1); + + // now we get the size + gbm.w = (ix1 - ix0); + gbm.h = (iy1 - iy0); + gbm.pixels = NULL; // in case we error + + if (width ) *width = gbm.w; + if (height) *height = gbm.h; + if (xoff ) *xoff = ix0; + if (yoff ) *yoff = iy0; + + if (gbm.w && gbm.h) { + gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata); + if (gbm.pixels) { + gbm.stride = gbm.w; + + stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info->userdata); + } + } + STBTT_free(vertices, info->userdata); + return gbm.pixels; +} + +STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff) +{ + return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff); +} + +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph) +{ + int ix0,iy0; + stbtt_vertex *vertices; + int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); + stbtt__bitmap gbm; + + stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0); + gbm.pixels = output; + gbm.w = out_w; + gbm.h = out_h; + gbm.stride = out_stride; + + if (gbm.w && gbm.h) + stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info->userdata); + + STBTT_free(vertices, info->userdata); +} + +STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph) +{ + stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph); +} + +STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff) +{ + return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff); +} + +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint) +{ + stbtt_MakeGlyphBitmapSubpixelPrefilter(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, oversample_x, oversample_y, sub_x, sub_y, stbtt_FindGlyphIndex(info,codepoint)); +} + +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint) +{ + stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint)); +} + +STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff) +{ + return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff); +} + +STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint) +{ + stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint); +} + +////////////////////////////////////////////////////////////////////////////// +// +// bitmap baking +// +// This is SUPER-CRAPPY packing to keep source code small + +static int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) + float pixel_height, // height of font in pixels + unsigned char *pixels, int pw, int ph, // bitmap to be filled in + int first_char, int num_chars, // characters to bake + stbtt_bakedchar *chardata) +{ + float scale; + int x,y,bottom_y, i; + stbtt_fontinfo f; + f.userdata = NULL; + if (!stbtt_InitFont(&f, data, offset)) + return -1; + STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels + x=y=1; + bottom_y = 1; + + scale = stbtt_ScaleForPixelHeight(&f, pixel_height); + + for (i=0; i < num_chars; ++i) { + int advance, lsb, x0,y0,x1,y1,gw,gh; + int g = stbtt_FindGlyphIndex(&f, first_char + i); + stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb); + stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1); + gw = x1-x0; + gh = y1-y0; + if (x + gw + 1 >= pw) + y = bottom_y, x = 1; // advance to next row + if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row + return -i; + STBTT_assert(x+gw < pw); + STBTT_assert(y+gh < ph); + stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g); + chardata[i].x0 = (stbtt_int16) x; + chardata[i].y0 = (stbtt_int16) y; + chardata[i].x1 = (stbtt_int16) (x + gw); + chardata[i].y1 = (stbtt_int16) (y + gh); + chardata[i].xadvance = scale * advance; + chardata[i].xoff = (float) x0; + chardata[i].yoff = (float) y0; + x = x + gw + 1; + if (y+gh+1 > bottom_y) + bottom_y = y+gh+1; + } + return bottom_y; +} + +STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule) +{ + float d3d_bias = opengl_fillrule ? 0 : -0.5f; + float ipw = 1.0f / pw, iph = 1.0f / ph; + const stbtt_bakedchar *b = chardata + char_index; + int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f); + int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f); + + q->x0 = round_x + d3d_bias; + q->y0 = round_y + d3d_bias; + q->x1 = round_x + b->x1 - b->x0 + d3d_bias; + q->y1 = round_y + b->y1 - b->y0 + d3d_bias; + + q->s0 = b->x0 * ipw; + q->t0 = b->y0 * iph; + q->s1 = b->x1 * ipw; + q->t1 = b->y1 * iph; + + *xpos += b->xadvance; +} + +////////////////////////////////////////////////////////////////////////////// +// +// rectangle packing replacement routines if you don't have stb_rect_pack.h +// + +#ifndef STB_RECT_PACK_VERSION + +typedef int stbrp_coord; + +//////////////////////////////////////////////////////////////////////////////////// +// // +// // +// COMPILER WARNING ?!?!? // +// // +// // +// if you get a compile warning due to these symbols being defined more than // +// once, move #include "stb_rect_pack.h" before #include "stb_truetype.h" // +// // +//////////////////////////////////////////////////////////////////////////////////// + +typedef struct +{ + int width,height; + int x,y,bottom_y; +} stbrp_context; + +typedef struct +{ + unsigned char x; +} stbrp_node; + +struct stbrp_rect +{ + stbrp_coord x,y; + int id,w,h,was_packed; +}; + +static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes) +{ + con->width = pw; + con->height = ph; + con->x = 0; + con->y = 0; + con->bottom_y = 0; + STBTT__NOTUSED(nodes); + STBTT__NOTUSED(num_nodes); +} + +static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects) +{ + int i; + for (i=0; i < num_rects; ++i) { + if (con->x + rects[i].w > con->width) { + con->x = 0; + con->y = con->bottom_y; + } + if (con->y + rects[i].h > con->height) + break; + rects[i].x = con->x; + rects[i].y = con->y; + rects[i].was_packed = 1; + con->x += rects[i].w; + if (con->y + rects[i].h > con->bottom_y) + con->bottom_y = con->y + rects[i].h; + } + for ( ; i < num_rects; ++i) + rects[i].was_packed = 0; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// bitmap baking +// +// This is SUPER-AWESOME (tm Ryan Gordon) packing using stb_rect_pack.h. If +// stb_rect_pack.h isn't available, it uses the BakeFontBitmap strategy. + +STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context) +{ + stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context) ,alloc_context); + int num_nodes = pw - padding; + stbrp_node *nodes = (stbrp_node *) STBTT_malloc(sizeof(*nodes ) * num_nodes,alloc_context); + + if (context == NULL || nodes == NULL) { + if (context != NULL) STBTT_free(context, alloc_context); + if (nodes != NULL) STBTT_free(nodes , alloc_context); + return 0; + } + + spc->user_allocator_context = alloc_context; + spc->width = pw; + spc->height = ph; + spc->pixels = pixels; + spc->pack_info = context; + spc->nodes = nodes; + spc->padding = padding; + spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw; + spc->h_oversample = 1; + spc->v_oversample = 1; + spc->skip_missing = 0; + + stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes); + + if (pixels) + STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels + + return 1; +} + +STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc) +{ + STBTT_free(spc->nodes , spc->user_allocator_context); + STBTT_free(spc->pack_info, spc->user_allocator_context); +} + +STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample) +{ + STBTT_assert(h_oversample <= STBTT_MAX_OVERSAMPLE); + STBTT_assert(v_oversample <= STBTT_MAX_OVERSAMPLE); + if (h_oversample <= STBTT_MAX_OVERSAMPLE) + spc->h_oversample = h_oversample; + if (v_oversample <= STBTT_MAX_OVERSAMPLE) + spc->v_oversample = v_oversample; +} + +STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip) +{ + spc->skip_missing = skip; +} + +#define STBTT__OVER_MASK (STBTT_MAX_OVERSAMPLE-1) + +static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) +{ + unsigned char buffer[STBTT_MAX_OVERSAMPLE]; + int safe_w = w - kernel_width; + int j; + STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze + for (j=0; j < h; ++j) { + int i; + unsigned int total; + STBTT_memset(buffer, 0, kernel_width); + + total = 0; + + // make kernel_width a constant in common cases so compiler can optimize out the divide + switch (kernel_width) { + case 2: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / 2); + } + break; + case 3: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / 3); + } + break; + case 4: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / 4); + } + break; + case 5: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / 5); + } + break; + default: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / kernel_width); + } + break; + } + + for (; i < w; ++i) { + STBTT_assert(pixels[i] == 0); + total -= buffer[i & STBTT__OVER_MASK]; + pixels[i] = (unsigned char) (total / kernel_width); + } + + pixels += stride_in_bytes; + } +} + +static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) +{ + unsigned char buffer[STBTT_MAX_OVERSAMPLE]; + int safe_h = h - kernel_width; + int j; + STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze + for (j=0; j < w; ++j) { + int i; + unsigned int total; + STBTT_memset(buffer, 0, kernel_width); + + total = 0; + + // make kernel_width a constant in common cases so compiler can optimize out the divide + switch (kernel_width) { + case 2: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / 2); + } + break; + case 3: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / 3); + } + break; + case 4: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / 4); + } + break; + case 5: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / 5); + } + break; + default: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); + } + break; + } + + for (; i < h; ++i) { + STBTT_assert(pixels[i*stride_in_bytes] == 0); + total -= buffer[i & STBTT__OVER_MASK]; + pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); + } + + pixels += 1; + } +} + +static float stbtt__oversample_shift(int oversample) +{ + if (!oversample) + return 0.0f; + + // The prefilter is a box filter of width "oversample", + // which shifts phase by (oversample - 1)/2 pixels in + // oversampled space. We want to shift in the opposite + // direction to counter this. + return (float)-(oversample - 1) / (2.0f * (float)oversample); +} + +// rects array must be big enough to accommodate all characters in the given ranges +STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) +{ + int i,j,k; + int missing_glyph_added = 0; + + k=0; + for (i=0; i < num_ranges; ++i) { + float fh = ranges[i].font_size; + float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); + ranges[i].h_oversample = (unsigned char) spc->h_oversample; + ranges[i].v_oversample = (unsigned char) spc->v_oversample; + for (j=0; j < ranges[i].num_chars; ++j) { + int x0,y0,x1,y1; + int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; + int glyph = stbtt_FindGlyphIndex(info, codepoint); + if (glyph == 0 && (spc->skip_missing || missing_glyph_added)) { + rects[k].w = rects[k].h = 0; + } else { + stbtt_GetGlyphBitmapBoxSubpixel(info,glyph, + scale * spc->h_oversample, + scale * spc->v_oversample, + 0,0, + &x0,&y0,&x1,&y1); + rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1); + rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1); + if (glyph == 0) + missing_glyph_added = 1; + } + ++k; + } + } + + return k; +} + +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int prefilter_x, int prefilter_y, float *sub_x, float *sub_y, int glyph) +{ + stbtt_MakeGlyphBitmapSubpixel(info, + output, + out_w - (prefilter_x - 1), + out_h - (prefilter_y - 1), + out_stride, + scale_x, + scale_y, + shift_x, + shift_y, + glyph); + + if (prefilter_x > 1) + stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x); + + if (prefilter_y > 1) + stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y); + + *sub_x = stbtt__oversample_shift(prefilter_x); + *sub_y = stbtt__oversample_shift(prefilter_y); +} + +// rects array must be big enough to accommodate all characters in the given ranges +STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) +{ + int i,j,k, missing_glyph = -1, return_value = 1; + + // save current values + int old_h_over = spc->h_oversample; + int old_v_over = spc->v_oversample; + + k = 0; + for (i=0; i < num_ranges; ++i) { + float fh = ranges[i].font_size; + float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); + float recip_h,recip_v,sub_x,sub_y; + spc->h_oversample = ranges[i].h_oversample; + spc->v_oversample = ranges[i].v_oversample; + recip_h = 1.0f / spc->h_oversample; + recip_v = 1.0f / spc->v_oversample; + sub_x = stbtt__oversample_shift(spc->h_oversample); + sub_y = stbtt__oversample_shift(spc->v_oversample); + for (j=0; j < ranges[i].num_chars; ++j) { + stbrp_rect *r = &rects[k]; + if (r->was_packed && r->w != 0 && r->h != 0) { + stbtt_packedchar *bc = &ranges[i].chardata_for_range[j]; + int advance, lsb, x0,y0,x1,y1; + int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; + int glyph = stbtt_FindGlyphIndex(info, codepoint); + stbrp_coord pad = (stbrp_coord) spc->padding; + + // pad on left and top + r->x += pad; + r->y += pad; + r->w -= pad; + r->h -= pad; + stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb); + stbtt_GetGlyphBitmapBox(info, glyph, + scale * spc->h_oversample, + scale * spc->v_oversample, + &x0,&y0,&x1,&y1); + stbtt_MakeGlyphBitmapSubpixel(info, + spc->pixels + r->x + r->y*spc->stride_in_bytes, + r->w - spc->h_oversample+1, + r->h - spc->v_oversample+1, + spc->stride_in_bytes, + scale * spc->h_oversample, + scale * spc->v_oversample, + 0,0, + glyph); + + if (spc->h_oversample > 1) + stbtt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, + r->w, r->h, spc->stride_in_bytes, + spc->h_oversample); + + if (spc->v_oversample > 1) + stbtt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, + r->w, r->h, spc->stride_in_bytes, + spc->v_oversample); + + bc->x0 = (stbtt_int16) r->x; + bc->y0 = (stbtt_int16) r->y; + bc->x1 = (stbtt_int16) (r->x + r->w); + bc->y1 = (stbtt_int16) (r->y + r->h); + bc->xadvance = scale * advance; + bc->xoff = (float) x0 * recip_h + sub_x; + bc->yoff = (float) y0 * recip_v + sub_y; + bc->xoff2 = (x0 + r->w) * recip_h + sub_x; + bc->yoff2 = (y0 + r->h) * recip_v + sub_y; + + if (glyph == 0) + missing_glyph = j; + } else if (spc->skip_missing) { + return_value = 0; + } else if (r->was_packed && r->w == 0 && r->h == 0 && missing_glyph >= 0) { + ranges[i].chardata_for_range[j] = ranges[i].chardata_for_range[missing_glyph]; + } else { + return_value = 0; // if any fail, report failure + } + + ++k; + } + } + + // restore original values + spc->h_oversample = old_h_over; + spc->v_oversample = old_v_over; + + return return_value; +} + +STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects) +{ + stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects); +} + +STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges) +{ + stbtt_fontinfo info; + int i,j,n, return_value = 1; + //stbrp_context *context = (stbrp_context *) spc->pack_info; + stbrp_rect *rects; + + // flag all characters as NOT packed + for (i=0; i < num_ranges; ++i) + for (j=0; j < ranges[i].num_chars; ++j) + ranges[i].chardata_for_range[j].x0 = + ranges[i].chardata_for_range[j].y0 = + ranges[i].chardata_for_range[j].x1 = + ranges[i].chardata_for_range[j].y1 = 0; + + n = 0; + for (i=0; i < num_ranges; ++i) + n += ranges[i].num_chars; + + rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context); + if (rects == NULL) + return 0; + + info.userdata = spc->user_allocator_context; + stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index)); + + n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects); + + stbtt_PackFontRangesPackRects(spc, rects, n); + + return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects); + + STBTT_free(rects, spc->user_allocator_context); + return return_value; +} + +STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size, + int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range) +{ + stbtt_pack_range range; + range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range; + range.array_of_unicode_codepoints = NULL; + range.num_chars = num_chars_in_range; + range.chardata_for_range = chardata_for_range; + range.font_size = font_size; + return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1); +} + +STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap) +{ + int i_ascent, i_descent, i_lineGap; + float scale; + stbtt_fontinfo info; + stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, index)); + scale = size > 0 ? stbtt_ScaleForPixelHeight(&info, size) : stbtt_ScaleForMappingEmToPixels(&info, -size); + stbtt_GetFontVMetrics(&info, &i_ascent, &i_descent, &i_lineGap); + *ascent = (float) i_ascent * scale; + *descent = (float) i_descent * scale; + *lineGap = (float) i_lineGap * scale; +} + +STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer) +{ + float ipw = 1.0f / pw, iph = 1.0f / ph; + const stbtt_packedchar *b = chardata + char_index; + + if (align_to_integer) { + float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f); + float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5f); + q->x0 = x; + q->y0 = y; + q->x1 = x + b->xoff2 - b->xoff; + q->y1 = y + b->yoff2 - b->yoff; + } else { + q->x0 = *xpos + b->xoff; + q->y0 = *ypos + b->yoff; + q->x1 = *xpos + b->xoff2; + q->y1 = *ypos + b->yoff2; + } + + q->s0 = b->x0 * ipw; + q->t0 = b->y0 * iph; + q->s1 = b->x1 * ipw; + q->t1 = b->y1 * iph; + + *xpos += b->xadvance; +} + +////////////////////////////////////////////////////////////////////////////// +// +// sdf computation +// + +#define STBTT_min(a,b) ((a) < (b) ? (a) : (b)) +#define STBTT_max(a,b) ((a) < (b) ? (b) : (a)) + +static int stbtt__ray_intersect_bezier(float orig[2], float ray[2], float q0[2], float q1[2], float q2[2], float hits[2][2]) +{ + float q0perp = q0[1]*ray[0] - q0[0]*ray[1]; + float q1perp = q1[1]*ray[0] - q1[0]*ray[1]; + float q2perp = q2[1]*ray[0] - q2[0]*ray[1]; + float roperp = orig[1]*ray[0] - orig[0]*ray[1]; + + float a = q0perp - 2*q1perp + q2perp; + float b = q1perp - q0perp; + float c = q0perp - roperp; + + float s0 = 0., s1 = 0.; + int num_s = 0; + + if (a != 0.0) { + float discr = b*b - a*c; + if (discr > 0.0) { + float rcpna = -1 / a; + float d = (float) STBTT_sqrt(discr); + s0 = (b+d) * rcpna; + s1 = (b-d) * rcpna; + if (s0 >= 0.0 && s0 <= 1.0) + num_s = 1; + if (d > 0.0 && s1 >= 0.0 && s1 <= 1.0) { + if (num_s == 0) s0 = s1; + ++num_s; + } + } + } else { + // 2*b*s + c = 0 + // s = -c / (2*b) + s0 = c / (-2 * b); + if (s0 >= 0.0 && s0 <= 1.0) + num_s = 1; + } + + if (num_s == 0) + return 0; + else { + float rcp_len2 = 1 / (ray[0]*ray[0] + ray[1]*ray[1]); + float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2; + + float q0d = q0[0]*rayn_x + q0[1]*rayn_y; + float q1d = q1[0]*rayn_x + q1[1]*rayn_y; + float q2d = q2[0]*rayn_x + q2[1]*rayn_y; + float rod = orig[0]*rayn_x + orig[1]*rayn_y; + + float q10d = q1d - q0d; + float q20d = q2d - q0d; + float q0rd = q0d - rod; + + hits[0][0] = q0rd + s0*(2.0f - 2.0f*s0)*q10d + s0*s0*q20d; + hits[0][1] = a*s0+b; + + if (num_s > 1) { + hits[1][0] = q0rd + s1*(2.0f - 2.0f*s1)*q10d + s1*s1*q20d; + hits[1][1] = a*s1+b; + return 2; + } else { + return 1; + } + } +} + +static int equal(float *a, float *b) +{ + return (a[0] == b[0] && a[1] == b[1]); +} + +static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex *verts) +{ + int i; + float orig[2], ray[2] = { 1, 0 }; + float y_frac; + int winding = 0; + + // make sure y never passes through a vertex of the shape + y_frac = (float) STBTT_fmod(y, 1.0f); + if (y_frac < 0.01f) + y += 0.01f; + else if (y_frac > 0.99f) + y -= 0.01f; + + orig[0] = x; + orig[1] = y; + + // test a ray from (-infinity,y) to (x,y) + for (i=0; i < nverts; ++i) { + if (verts[i].type == STBTT_vline) { + int x0 = (int) verts[i-1].x, y0 = (int) verts[i-1].y; + int x1 = (int) verts[i ].x, y1 = (int) verts[i ].y; + if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { + float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; + if (x_inter < x) + winding += (y0 < y1) ? 1 : -1; + } + } + if (verts[i].type == STBTT_vcurve) { + int x0 = (int) verts[i-1].x , y0 = (int) verts[i-1].y ; + int x1 = (int) verts[i ].cx, y1 = (int) verts[i ].cy; + int x2 = (int) verts[i ].x , y2 = (int) verts[i ].y ; + int ax = STBTT_min(x0,STBTT_min(x1,x2)), ay = STBTT_min(y0,STBTT_min(y1,y2)); + int by = STBTT_max(y0,STBTT_max(y1,y2)); + if (y > ay && y < by && x > ax) { + float q0[2],q1[2],q2[2]; + float hits[2][2]; + q0[0] = (float)x0; + q0[1] = (float)y0; + q1[0] = (float)x1; + q1[1] = (float)y1; + q2[0] = (float)x2; + q2[1] = (float)y2; + if (equal(q0,q1) || equal(q1,q2)) { + x0 = (int)verts[i-1].x; + y0 = (int)verts[i-1].y; + x1 = (int)verts[i ].x; + y1 = (int)verts[i ].y; + if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { + float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; + if (x_inter < x) + winding += (y0 < y1) ? 1 : -1; + } + } else { + int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits); + if (num_hits >= 1) + if (hits[0][0] < 0) + winding += (hits[0][1] < 0 ? -1 : 1); + if (num_hits >= 2) + if (hits[1][0] < 0) + winding += (hits[1][1] < 0 ? -1 : 1); + } + } + } + } + return winding; +} + +static float stbtt__cuberoot( float x ) +{ + if (x<0) + return -(float) STBTT_pow(-x,1.0f/3.0f); + else + return (float) STBTT_pow( x,1.0f/3.0f); +} + +// x^3 + a*x^2 + b*x + c = 0 +static int stbtt__solve_cubic(float a, float b, float c, float* r) +{ + float s = -a / 3; + float p = b - a*a / 3; + float q = a * (2*a*a - 9*b) / 27 + c; + float p3 = p*p*p; + float d = q*q + 4*p3 / 27; + if (d >= 0) { + float z = (float) STBTT_sqrt(d); + float u = (-q + z) / 2; + float v = (-q - z) / 2; + u = stbtt__cuberoot(u); + v = stbtt__cuberoot(v); + r[0] = s + u + v; + return 1; + } else { + float u = (float) STBTT_sqrt(-p/3); + float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative + float m = (float) STBTT_cos(v); + float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f; + r[0] = s + u * 2 * m; + r[1] = s - u * (m + n); + r[2] = s - u * (m - n); + + //STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f); // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe? + //STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f); + //STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f); + return 3; + } +} + +STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff) +{ + float scale_x = scale, scale_y = scale; + int ix0,iy0,ix1,iy1; + int w,h; + unsigned char *data; + + if (scale == 0) return NULL; + + stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1); + + // if empty, return NULL + if (ix0 == ix1 || iy0 == iy1) + return NULL; + + ix0 -= padding; + iy0 -= padding; + ix1 += padding; + iy1 += padding; + + w = (ix1 - ix0); + h = (iy1 - iy0); + + if (width ) *width = w; + if (height) *height = h; + if (xoff ) *xoff = ix0; + if (yoff ) *yoff = iy0; + + // invert for y-downwards bitmaps + scale_y = -scale_y; + + { + // distance from singular values (in the same units as the pixel grid) + const float eps = 1./1024, eps2 = eps*eps; + int x,y,i,j; + float *precompute; + stbtt_vertex *verts; + int num_verts = stbtt_GetGlyphShape(info, glyph, &verts); + data = (unsigned char *) STBTT_malloc(w * h, info->userdata); + precompute = (float *) STBTT_malloc(num_verts * sizeof(float), info->userdata); + + for (i=0,j=num_verts-1; i < num_verts; j=i++) { + if (verts[i].type == STBTT_vline) { + float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; + float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y; + float dist = (float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0)); + precompute[i] = (dist < eps) ? 0.0f : 1.0f / dist; + } else if (verts[i].type == STBTT_vcurve) { + float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y; + float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y; + float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y; + float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; + float len2 = bx*bx + by*by; + if (len2 >= eps2) + precompute[i] = 1.0f / len2; + else + precompute[i] = 0.0f; + } else + precompute[i] = 0.0f; + } + + for (y=iy0; y < iy1; ++y) { + for (x=ix0; x < ix1; ++x) { + float val; + float min_dist = 999999.0f; + float sx = (float) x + 0.5f; + float sy = (float) y + 0.5f; + float x_gspace = (sx / scale_x); + float y_gspace = (sy / scale_y); + + int winding = stbtt__compute_crossings_x(x_gspace, y_gspace, num_verts, verts); // @OPTIMIZE: this could just be a rasterization, but needs to be line vs. non-tesselated curves so a new path + + for (i=0; i < num_verts; ++i) { + float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; + + if (verts[i].type == STBTT_vline && precompute[i] != 0.0f) { + float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y; + + float dist,dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); + if (dist2 < min_dist*min_dist) + min_dist = (float) STBTT_sqrt(dist2); + + // coarse culling against bbox + //if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist && + // sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist) + dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i]; + STBTT_assert(i != 0); + if (dist < min_dist) { + // check position along line + // x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0) + // minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy) + float dx = x1-x0, dy = y1-y0; + float px = x0-sx, py = y0-sy; + // minimize (px+t*dx)^2 + (py+t*dy)^2 = px*px + 2*px*dx*t + t^2*dx*dx + py*py + 2*py*dy*t + t^2*dy*dy + // derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve + float t = -(px*dx + py*dy) / (dx*dx + dy*dy); + if (t >= 0.0f && t <= 1.0f) + min_dist = dist; + } + } else if (verts[i].type == STBTT_vcurve) { + float x2 = verts[i-1].x *scale_x, y2 = verts[i-1].y *scale_y; + float x1 = verts[i ].cx*scale_x, y1 = verts[i ].cy*scale_y; + float box_x0 = STBTT_min(STBTT_min(x0,x1),x2); + float box_y0 = STBTT_min(STBTT_min(y0,y1),y2); + float box_x1 = STBTT_max(STBTT_max(x0,x1),x2); + float box_y1 = STBTT_max(STBTT_max(y0,y1),y2); + // coarse culling against bbox to avoid computing cubic unnecessarily + if (sx > box_x0-min_dist && sx < box_x1+min_dist && sy > box_y0-min_dist && sy < box_y1+min_dist) { + int num=0; + float ax = x1-x0, ay = y1-y0; + float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; + float mx = x0 - sx, my = y0 - sy; + float res[3] = {0.f,0.f,0.f}; + float px,py,t,it,dist2; + float a_inv = precompute[i]; + if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula + float a = 3*(ax*bx + ay*by); + float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by); + float c = mx*ax+my*ay; + if (STBTT_fabs(a) < eps2) { // if a is 0, it's linear + if (STBTT_fabs(b) >= eps2) { + res[num++] = -c/b; + } + } else { + float discriminant = b*b - 4*a*c; + if (discriminant < 0) + num = 0; + else { + float root = (float) STBTT_sqrt(discriminant); + res[0] = (-b - root)/(2*a); + res[1] = (-b + root)/(2*a); + num = 2; // don't bother distinguishing 1-solution case, as code below will still work + } + } + } else { + float b = 3*(ax*bx + ay*by) * a_inv; // could precompute this as it doesn't depend on sample point + float c = (2*(ax*ax + ay*ay) + (mx*bx+my*by)) * a_inv; + float d = (mx*ax+my*ay) * a_inv; + num = stbtt__solve_cubic(b, c, d, res); + } + dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); + if (dist2 < min_dist*min_dist) + min_dist = (float) STBTT_sqrt(dist2); + + if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) { + t = res[0], it = 1.0f - t; + px = it*it*x0 + 2*t*it*x1 + t*t*x2; + py = it*it*y0 + 2*t*it*y1 + t*t*y2; + dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); + if (dist2 < min_dist * min_dist) + min_dist = (float) STBTT_sqrt(dist2); + } + if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) { + t = res[1], it = 1.0f - t; + px = it*it*x0 + 2*t*it*x1 + t*t*x2; + py = it*it*y0 + 2*t*it*y1 + t*t*y2; + dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); + if (dist2 < min_dist * min_dist) + min_dist = (float) STBTT_sqrt(dist2); + } + if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) { + t = res[2], it = 1.0f - t; + px = it*it*x0 + 2*t*it*x1 + t*t*x2; + py = it*it*y0 + 2*t*it*y1 + t*t*y2; + dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); + if (dist2 < min_dist * min_dist) + min_dist = (float) STBTT_sqrt(dist2); + } + } + } + } + if (winding == 0) + min_dist = -min_dist; // if outside the shape, value is negative + val = onedge_value + pixel_dist_scale * min_dist; + if (val < 0) + val = 0; + else if (val > 255) + val = 255; + data[(y-iy0)*w+(x-ix0)] = (unsigned char) val; + } + } + STBTT_free(precompute, info->userdata); + STBTT_free(verts, info->userdata); + } + return data; +} + +STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff) +{ + return stbtt_GetGlyphSDF(info, scale, stbtt_FindGlyphIndex(info, codepoint), padding, onedge_value, pixel_dist_scale, width, height, xoff, yoff); +} + +STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata) +{ + STBTT_free(bitmap, userdata); +} + +////////////////////////////////////////////////////////////////////////////// +// +// font name matching -- recommended not to use this +// + +// check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string +static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2) +{ + stbtt_int32 i=0; + + // convert utf16 to utf8 and compare the results while converting + while (len2) { + stbtt_uint16 ch = s2[0]*256 + s2[1]; + if (ch < 0x80) { + if (i >= len1) return -1; + if (s1[i++] != ch) return -1; + } else if (ch < 0x800) { + if (i+1 >= len1) return -1; + if (s1[i++] != 0xc0 + (ch >> 6)) return -1; + if (s1[i++] != 0x80 + (ch & 0x3f)) return -1; + } else if (ch >= 0xd800 && ch < 0xdc00) { + stbtt_uint32 c; + stbtt_uint16 ch2 = s2[2]*256 + s2[3]; + if (i+3 >= len1) return -1; + c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000; + if (s1[i++] != 0xf0 + (c >> 18)) return -1; + if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1; + if (s1[i++] != 0x80 + ((c >> 6) & 0x3f)) return -1; + if (s1[i++] != 0x80 + ((c ) & 0x3f)) return -1; + s2 += 2; // plus another 2 below + len2 -= 2; + } else if (ch >= 0xdc00 && ch < 0xe000) { + return -1; + } else { + if (i+2 >= len1) return -1; + if (s1[i++] != 0xe0 + (ch >> 12)) return -1; + if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1; + if (s1[i++] != 0x80 + ((ch ) & 0x3f)) return -1; + } + s2 += 2; + len2 -= 2; + } + return i; +} + +static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2) +{ + return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2); +} + +// returns results in whatever encoding you request... but note that 2-byte encodings +// will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare +STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID) +{ + stbtt_int32 i,count,stringOffset; + stbtt_uint8 *fc = font->data; + stbtt_uint32 offset = font->fontstart; + stbtt_uint32 nm = stbtt__find_table(fc, offset, "name"); + if (!nm) return NULL; + + count = ttUSHORT(fc+nm+2); + stringOffset = nm + ttUSHORT(fc+nm+4); + for (i=0; i < count; ++i) { + stbtt_uint32 loc = nm + 6 + 12 * i; + if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2) + && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) { + *length = ttUSHORT(fc+loc+8); + return (const char *) (fc+stringOffset+ttUSHORT(fc+loc+10)); + } + } + return NULL; +} + +static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id) +{ + stbtt_int32 i; + stbtt_int32 count = ttUSHORT(fc+nm+2); + stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4); + + for (i=0; i < count; ++i) { + stbtt_uint32 loc = nm + 6 + 12 * i; + stbtt_int32 id = ttUSHORT(fc+loc+6); + if (id == target_id) { + // find the encoding + stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4); + + // is this a Unicode encoding? + if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) { + stbtt_int32 slen = ttUSHORT(fc+loc+8); + stbtt_int32 off = ttUSHORT(fc+loc+10); + + // check if there's a prefix match + stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen); + if (matchlen >= 0) { + // check for target_id+1 immediately following, with same encoding & language + if (i+1 < count && ttUSHORT(fc+loc+12+6) == next_id && ttUSHORT(fc+loc+12) == platform && ttUSHORT(fc+loc+12+2) == encoding && ttUSHORT(fc+loc+12+4) == language) { + slen = ttUSHORT(fc+loc+12+8); + off = ttUSHORT(fc+loc+12+10); + if (slen == 0) { + if (matchlen == nlen) + return 1; + } else if (matchlen < nlen && name[matchlen] == ' ') { + ++matchlen; + if (stbtt_CompareUTF8toUTF16_bigendian_internal((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen)) + return 1; + } + } else { + // if nothing immediately following + if (matchlen == nlen) + return 1; + } + } + } + + // @TODO handle other encodings + } + } + return 0; +} + +static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags) +{ + stbtt_int32 nlen = (stbtt_int32) STBTT_strlen((char *) name); + stbtt_uint32 nm,hd; + if (!stbtt__isfont(fc+offset)) return 0; + + // check italics/bold/underline flags in macStyle... + if (flags) { + hd = stbtt__find_table(fc, offset, "head"); + if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0; + } + + nm = stbtt__find_table(fc, offset, "name"); + if (!nm) return 0; + + if (flags) { + // if we checked the macStyle flags, then just check the family and ignore the subfamily + if (stbtt__matchpair(fc, nm, name, nlen, 16, -1)) return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 1, -1)) return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; + } else { + if (stbtt__matchpair(fc, nm, name, nlen, 16, 17)) return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 1, 2)) return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; + } + + return 0; +} + +static int stbtt_FindMatchingFont_internal(unsigned char *font_collection, char *name_utf8, stbtt_int32 flags) +{ + stbtt_int32 i; + for (i=0;;++i) { + stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i); + if (off < 0) return off; + if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*) name_utf8, flags)) + return off; + } +} + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif + +STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, + float pixel_height, unsigned char *pixels, int pw, int ph, + int first_char, int num_chars, stbtt_bakedchar *chardata) +{ + return stbtt_BakeFontBitmap_internal((unsigned char *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata); +} + +STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index) +{ + return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index); +} + +STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data) +{ + return stbtt_GetNumberOfFonts_internal((unsigned char *) data); +} + +STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset) +{ + return stbtt_InitFont_internal(info, (unsigned char *) data, offset); +} + +STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags) +{ + return stbtt_FindMatchingFont_internal((unsigned char *) fontdata, (char *) name, flags); +} + +STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2) +{ + return stbtt_CompareUTF8toUTF16_bigendian_internal((char *) s1, len1, (char *) s2, len2); +} + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic pop +#endif + +#endif // STB_TRUETYPE_IMPLEMENTATION + + +// FULL VERSION HISTORY +// +// 1.25 (2021-07-11) many fixes +// 1.24 (2020-02-05) fix warning +// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS) +// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined +// 1.21 (2019-02-25) fix warning +// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics() +// 1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod +// 1.18 (2018-01-29) add missing function +// 1.17 (2017-07-23) make more arguments const; doc fix +// 1.16 (2017-07-12) SDF support +// 1.15 (2017-03-03) make more arguments const +// 1.14 (2017-01-16) num-fonts-in-TTC function +// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts +// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual +// 1.11 (2016-04-02) fix unused-variable warning +// 1.10 (2016-04-02) allow user-defined fabs() replacement +// fix memory leak if fontsize=0.0 +// fix warning from duplicate typedef +// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use alloc userdata for PackFontRanges +// 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges +// 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; +// allow PackFontRanges to pack and render in separate phases; +// fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); +// fixed an assert() bug in the new rasterizer +// replace assert() with STBTT_assert() in new rasterizer +// 1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on test machine) +// also more precise AA rasterizer, except if shapes overlap +// remove need for STBTT_sort +// 1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC +// 1.04 (2015-04-15) typo in example +// 1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes +// 1.02 (2014-12-10) fix various warnings & compile issues w/ stb_rect_pack, C++ +// 1.01 (2014-12-08) fix subpixel position when oversampling to exactly match +// non-oversampled; STBTT_POINT_SIZE for packed case only +// 1.00 (2014-12-06) add new PackBegin etc. API, w/ support for oversampling +// 0.99 (2014-09-18) fix multiple bugs with subpixel rendering (ryg) +// 0.9 (2014-08-07) support certain mac/iOS fonts without an MS platformID +// 0.8b (2014-07-07) fix a warning +// 0.8 (2014-05-25) fix a few more warnings +// 0.7 (2013-09-25) bugfix: subpixel glyph bug fixed in 0.5 had come back +// 0.6c (2012-07-24) improve documentation +// 0.6b (2012-07-20) fix a few more warnings +// 0.6 (2012-07-17) fix warnings; added stbtt_ScaleForMappingEmToPixels, +// stbtt_GetFontBoundingBox, stbtt_IsGlyphEmpty +// 0.5 (2011-12-09) bugfixes: +// subpixel glyph renderer computed wrong bounding box +// first vertex of shape can be off-curve (FreeSans) +// 0.4b (2011-12-03) fixed an error in the font baking example +// 0.4 (2011-12-01) kerning, subpixel rendering (tor) +// bugfixes for: +// codepoint-to-glyph conversion using table fmt=12 +// codepoint-to-glyph conversion using table fmt=4 +// stbtt_GetBakedQuad with non-square texture (Zer) +// updated Hello World! sample to use kerning and subpixel +// fixed some warnings +// 0.3 (2009-06-24) cmap fmt=12, compound shapes (MM) +// userdata, malloc-from-userdata, non-zero fill (stb) +// 0.2 (2009-03-11) Fix unsigned/signed char warnings +// 0.1 (2009-03-09) First public release +// + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +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. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +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 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. +------------------------------------------------------------------------------ +*/ diff --git a/Modules/binfont-module/source/binfont.cpp b/Modules/binfont-module/source/binfont.cpp new file mode 100644 index 000000000..8cc4af230 --- /dev/null +++ b/Modules/binfont-module/source/binfont.cpp @@ -0,0 +1,718 @@ +// SPDX-License-Identifier: Apache-2.0 +#include + +#include +#include + +#include +#include +#include +#include + +namespace { + +constexpr size_t RECORD_HEADER_SIZE = 8; +constexpr size_t HEAD_MIN_SIZE = 48; +constexpr size_t CMAP_SUBTABLE_HEADER_SIZE = 16; +constexpr size_t GLYPH_HEADER_MAX_BYTES = 16; + +enum CmapFormat : uint8_t { + CMAP_FORMAT_0 = 0, + CMAP_FORMAT_SPARSE = 1, + CMAP_FORMAT_0_TINY = 2, + CMAP_FORMAT_SPARSE_TINY = 3, +}; + +enum Compression : uint8_t { + COMPRESSION_NONE = 0, + COMPRESSION_RLE_PREFILTER = 1, + COMPRESSION_RLE = 2, +}; + +uint16_t read_u16(const uint8_t* p) { + return static_cast(p[0] | (p[1] << 8)); +} + +int16_t read_i16(const uint8_t* p) { + return static_cast(read_u16(p)); +} + +uint32_t read_u32(const uint8_t* p) { + return static_cast(p[0]) | (static_cast(p[1]) << 8) | (static_cast(p[2]) << 16) | (static_cast(p[3]) << 24); +} + +bool has_marker(const uint8_t* record, const char* marker) { + return memcmp(record + 4, marker, 4) == 0; +} + +/** MSB-first bit reader. Bits past the end read as 0. */ +class BitReader { + const uint8_t* data; + size_t sizeBits; + size_t position; + +public: + BitReader(const uint8_t* data, size_t size, size_t bitOffset = 0) : data(data), sizeBits(size * 8), position(bitOffset) {} + + uint32_t read(uint8_t bits) { + uint32_t value = 0; + for (uint8_t i = 0; i < bits; i++) { + value <<= 1; + if (position < sizeBits) { + value |= (data[position >> 3] >> (7 - (position & 7))) & 1U; + } + position++; + } + return value; + } + + int32_t readSigned(uint8_t bits) { + if (bits == 0) { + return 0; + } + const uint32_t value = read(bits); + if (value & (1U << (bits - 1))) { + return static_cast(value | (~0U << bits)); + } + return static_cast(value); + } +}; + +/** Decoder for the modified I3BN RLE stream of lv_font_conv. */ +class RleReader { + enum class State { Single, Repeated, Counter }; + + BitReader& bits; + uint8_t bpp; + State state = State::Single; + bool first = true; + uint8_t previous = 0; + uint32_t count = 0; + + uint8_t readSingle() { + previous = static_cast(bits.read(bpp)); + state = State::Single; + return previous; + } + +public: + RleReader(BitReader& bits, uint8_t bpp) : bits(bits), bpp(bpp) {} + + uint8_t next() { + switch (state) { + case State::Single: { + const auto value = static_cast(bits.read(bpp)); + if (!first && value == previous) { + count = 0; + state = State::Repeated; + } + first = false; + previous = value; + return value; + } + case State::Repeated: { + count++; + if (bits.read(1) == 0) { + return readSingle(); + } + if (count == 11) { + count = bits.read(6); + if (count != 0) { + state = State::Counter; + } else { + return readSingle(); + } + } + return previous; + } + case State::Counter: + count--; + if (count == 0) { + return readSingle(); + } + return previous; + } + return 0; + } +}; + +struct Header { + uint16_t fontSize; + int16_t ascent; + int16_t descent; + uint16_t defaultAdvanceWidth; + uint16_t kerningScale; + uint8_t indexToLocFormat; + uint8_t glyphIdFormat; + uint8_t advanceWidthFormat; + uint8_t bpp; + uint8_t xyBits; + uint8_t whBits; + uint8_t advanceWidthBits; + uint8_t compression; + uint8_t subpixelMode; + int16_t underlinePosition; + uint16_t underlineThickness; +}; + +} // namespace + +struct BinFont { + Header header; + /** The whole file in memory mode, nullptr in stream mode */ + const uint8_t* data; + bool ownsData; + /** Stream mode only */ + FILE* file; + Mutex mutex; + /** Owned copy of the cmap/loca/kern records in stream mode */ + uint8_t* tables; + /** Each record pointer includes its 8-byte record header */ + const uint8_t* cmap; + size_t cmapSize; + const uint8_t* loca; + size_t locaSize; + uint32_t locaCount; + const uint8_t* kern; + size_t kernSize; + size_t glyfOffset; + size_t glyfSize; +}; + +namespace { + +bool read_at(BinFont* font, size_t offset, uint8_t* out, size_t size) { + if (fseek(font->file, static_cast(offset), SEEK_SET) != 0) { + return false; + } + return fread(out, 1, size, font->file) == size; +} + +bool parse_header(const uint8_t* record, size_t size, Header& header) { + if (size < HEAD_MIN_SIZE || !has_marker(record, "head")) { + return false; + } + header.fontSize = read_u16(record + 14); + header.ascent = read_i16(record + 16); + header.descent = read_i16(record + 18); + header.defaultAdvanceWidth = read_u16(record + 30); + header.kerningScale = read_u16(record + 32); + header.indexToLocFormat = record[34]; + header.glyphIdFormat = record[35]; + header.advanceWidthFormat = record[36]; + header.bpp = record[37]; + header.xyBits = record[38]; + header.whBits = record[39]; + header.advanceWidthBits = record[40]; + header.compression = record[41]; + header.subpixelMode = record[42]; + header.underlinePosition = read_i16(record + 44); + header.underlineThickness = read_u16(record + 46); + + return header.bpp >= 1 && header.bpp <= 4 && + header.compression <= COMPRESSION_RLE && + header.subpixelMode == 0 && + header.indexToLocFormat <= 1 && + header.xyBits <= 16 && header.whBits <= 16 && header.advanceWidthBits <= 32; +} + +bool validate_cmap(const uint8_t* cmap, size_t size) { + if (size < 12) { + return false; + } + const uint32_t count = read_u32(cmap + 8); + if (count > (size - 12) / CMAP_SUBTABLE_HEADER_SIZE) { + return false; + } + for (uint32_t i = 0; i < count; i++) { + const uint8_t* subtable = cmap + 12 + i * CMAP_SUBTABLE_HEADER_SIZE; + const size_t data_offset = read_u32(subtable); + const size_t range_length = read_u16(subtable + 8); + const size_t entries = read_u16(subtable + 12); + size_t data_size; + switch (subtable[14]) { + case CMAP_FORMAT_0: data_size = range_length; break; + case CMAP_FORMAT_SPARSE: data_size = entries * 4; break; + case CMAP_FORMAT_0_TINY: data_size = 0; break; + case CMAP_FORMAT_SPARSE_TINY: data_size = entries * 2; break; + default: return false; + } + if (data_size > 0 && (data_offset > size || data_size > size - data_offset)) { + return false; + } + } + return true; +} + +bool validate_kern(const uint8_t* kern, size_t size, uint8_t glyphIdFormat) { + if (size < 16) { + return false; + } + const uint8_t format = kern[8]; + if (format == 0) { + const size_t count = read_u32(kern + 12); + const size_t entry_size = (glyphIdFormat ? 4 : 2) + 1; + return count <= (size - 16) / entry_size; + } else if (format == 3) { + const size_t glyph_count = read_u16(kern + 12); + const size_t left_count = kern[14]; + const size_t right_count = kern[15]; + return 16 + glyph_count * 2 + left_count * right_count <= size; + } + return false; +} + +/** + * Locates all tables. In memory mode the table pointers point into font->data, in stream mode + * the lookup tables are copied into font->tables. + */ +error_t parse_layout(BinFont* font, size_t fileSize) { + uint8_t record_header[RECORD_HEADER_SIZE]; + uint8_t head[64]; + + auto read = [font](size_t offset, uint8_t* out, size_t size) { + if (font->data != nullptr) { + memcpy(out, font->data + offset, size); + return true; + } + return read_at(font, offset, out, size); + }; + + // head + if (fileSize < RECORD_HEADER_SIZE || !read(0, record_header, RECORD_HEADER_SIZE)) { + return ERROR_NOT_SUPPORTED; + } + const size_t head_size = read_u32(record_header); + if (head_size < HEAD_MIN_SIZE || head_size > fileSize) { + return ERROR_NOT_SUPPORTED; + } + if (!read(0, head, HEAD_MIN_SIZE) || !parse_header(head, HEAD_MIN_SIZE, font->header)) { + return ERROR_NOT_SUPPORTED; + } + + // cmap, loca, glyf and optionally kern follow each other + size_t offsets[4] = {}; + size_t sizes[4] = {}; + const char* markers[4] = { "cmap", "loca", "glyf", "kern" }; + size_t offset = head_size; + for (int i = 0; i < 4; i++) { + if (offset > fileSize || fileSize - offset < RECORD_HEADER_SIZE || !read(offset, record_header, RECORD_HEADER_SIZE)) { + if (i == 3) { + break; // kern is optional + } + return ERROR_NOT_SUPPORTED; + } + const size_t size = read_u32(record_header); + if (!has_marker(record_header, markers[i]) || size < RECORD_HEADER_SIZE || size > fileSize - offset) { + if (i == 3) { + break; + } + return ERROR_NOT_SUPPORTED; + } + offsets[i] = offset; + sizes[i] = size; + offset += size; + } + + font->glyfOffset = offsets[2]; + font->glyfSize = sizes[2]; + + if (font->data != nullptr) { + font->cmap = font->data + offsets[0]; + font->loca = font->data + offsets[1]; + font->kern = sizes[3] ? font->data + offsets[3] : nullptr; + } else { + font->tables = static_cast(memory_alloc(sizes[0] + sizes[1] + sizes[3])); + if (font->tables == nullptr) { + return ERROR_OUT_OF_MEMORY; + } + uint8_t* cursor = font->tables; + for (int i : { 0, 1, 3 }) { + if (sizes[i] > 0 && !read_at(font, offsets[i], cursor, sizes[i])) { + return ERROR_NOT_SUPPORTED; + } + cursor += sizes[i]; + } + font->cmap = font->tables; + font->loca = font->tables + sizes[0]; + font->kern = sizes[3] ? font->tables + sizes[0] + sizes[1] : nullptr; + } + font->cmapSize = sizes[0]; + font->locaSize = sizes[1]; + font->kernSize = sizes[3]; + + if (!validate_cmap(font->cmap, font->cmapSize)) { + return ERROR_NOT_SUPPORTED; + } + + if (font->locaSize < 12) { + return ERROR_NOT_SUPPORTED; + } + font->locaCount = read_u32(font->loca + 8); + const size_t loca_entry_size = font->header.indexToLocFormat ? 4 : 2; + if (font->locaCount > (font->locaSize - 12) / loca_entry_size) { + return ERROR_NOT_SUPPORTED; + } + + if (font->kern != nullptr && !validate_kern(font->kern, font->kernSize, font->header.glyphIdFormat)) { + font->kern = nullptr; + font->kernSize = 0; + } + + return ERROR_NONE; +} + +BinFont* create_font() { + auto* font = static_cast(memory_calloc(1, sizeof(BinFont))); + if (font != nullptr) { + mutex_construct(&font->mutex); + } + return font; +} + +uint32_t find_glyph_id(const BinFont* font, uint32_t codepoint) { + const uint8_t* cmap = font->cmap; + const uint32_t count = read_u32(cmap + 8); + + // Find the last subtable that starts at or before the codepoint + uint32_t low = 0; + uint32_t high = count; + while (low < high) { + const uint32_t mid = (low + high) / 2; + if (read_u32(cmap + 12 + mid * CMAP_SUBTABLE_HEADER_SIZE + 4) <= codepoint) { + low = mid + 1; + } else { + high = mid; + } + } + if (low == 0) { + return 0; + } + + const uint8_t* subtable = cmap + 12 + (low - 1) * CMAP_SUBTABLE_HEADER_SIZE; + const uint32_t data_offset = read_u32(subtable); + const uint32_t range_start = read_u32(subtable + 4); + const uint16_t range_length = read_u16(subtable + 8); + const uint16_t glyph_id_start = read_u16(subtable + 10); + const uint16_t entries = read_u16(subtable + 12); + const uint32_t relative = codepoint - range_start; + if (relative >= range_length) { + return 0; + } + + switch (subtable[14]) { + case CMAP_FORMAT_0: + return glyph_id_start + cmap[data_offset + relative]; + case CMAP_FORMAT_0_TINY: + return glyph_id_start + relative; + case CMAP_FORMAT_SPARSE: + case CMAP_FORMAT_SPARSE_TINY: { + const uint8_t* list = cmap + data_offset; + uint32_t list_low = 0; + uint32_t list_high = entries; + while (list_low < list_high) { + const uint32_t mid = (list_low + list_high) / 2; + const uint16_t value = read_u16(list + mid * 2); + if (value == relative) { + if (subtable[14] == CMAP_FORMAT_SPARSE_TINY) { + return glyph_id_start + mid; + } + return glyph_id_start + read_u16(list + entries * 2 + mid * 2); + } else if (value < relative) { + list_low = mid + 1; + } else { + list_high = mid; + } + } + return 0; + } + default: + return 0; + } +} + +/** Gets the offset and size of a glyph record, relative to the glyf data (after its record header). */ +bool get_glyph_location(const BinFont* font, uint32_t glyphId, size_t& offset, size_t& size) { + if (glyphId == 0 || glyphId >= font->locaCount) { + return false; + } + const uint8_t* entries = font->loca + 12; + auto entry = [&](uint32_t index) -> size_t { + return font->header.indexToLocFormat ? read_u32(entries + index * 4) : read_u16(entries + index * 2); + }; + const size_t start = entry(glyphId); + const size_t end = (glyphId + 1 < font->locaCount) ? entry(glyphId + 1) : font->glyfSize; + if (start < RECORD_HEADER_SIZE || end < start || end > font->glyfSize) { + return false; + } + offset = start; + size = end - start; + return true; +} + +/** + * Provides the record of a glyph. In memory mode it points into the font data, in stream mode it + * is read into buffer (bufferSize bytes) or, when that is too small, into an allocation returned + * via allocated (to be freed by the caller). + */ +bool get_glyph_record(BinFont* font, uint32_t glyphId, size_t maxSize, uint8_t* buffer, size_t bufferSize, const uint8_t*& record, size_t& size, uint8_t*& allocated) { + size_t offset; + allocated = nullptr; + if (!get_glyph_location(font, glyphId, offset, size)) { + return false; + } + if (font->data != nullptr) { + record = font->data + font->glyfOffset + offset; + return true; + } + + if (size > maxSize) { + size = maxSize; + } + uint8_t* target = buffer; + if (size > bufferSize) { + allocated = static_cast(memory_alloc(size)); + if (allocated == nullptr) { + return false; + } + target = allocated; + } + + mutex_lock(&font->mutex); + const bool success = read_at(font, font->glyfOffset + offset, target, size); + mutex_unlock(&font->mutex); + + if (!success) { + memory_free(allocated); + allocated = nullptr; + return false; + } + record = target; + return true; +} + +void parse_glyph(const Header& header, BitReader& reader, uint32_t glyphId, BinFontGlyph* out) { + uint32_t advance = header.advanceWidthBits ? reader.read(header.advanceWidthBits) : header.defaultAdvanceWidth; + if (header.advanceWidthFormat == 0) { + advance *= 16; + } + out->glyph_id = glyphId; + out->advance_x16 = advance; + out->x = static_cast(reader.readSigned(header.xyBits)); + out->y = static_cast(reader.readSigned(header.xyBits)); + out->width = static_cast(reader.read(header.whBits)); + out->height = static_cast(reader.read(header.whBits)); +} + +} // namespace + +extern "C" { + +error_t binfont_open_memory(const void* data, size_t size, bool take_ownership, BinFont** out) { + BinFont* font = create_font(); + if (font == nullptr) { + if (take_ownership) { + memory_free(const_cast(data)); + } + return ERROR_OUT_OF_MEMORY; + } + font->data = static_cast(data); + font->ownsData = take_ownership; + + const error_t error = parse_layout(font, size); + if (error != ERROR_NONE) { + binfont_close(font); + return error; + } + *out = font; + return ERROR_NONE; +} + +error_t binfont_open_file(const char* path, BinFont** out) { + FILE* file = fopen(path, "rb"); + if (file == nullptr) { + return ERROR_NOT_FOUND; + } + if (fseek(file, 0, SEEK_END) != 0) { + fclose(file); + return ERROR_NOT_SUPPORTED; + } + const long file_size = ftell(file); + if (file_size <= 0 || fseek(file, 0, SEEK_SET) != 0) { + fclose(file); + return ERROR_NOT_SUPPORTED; + } + const auto size = static_cast(file_size); + + if (memory_external_total() > 0) { + constexpr MemoryPolicy policy = { .required = MEMORY_CAPABILITY_EXTERNAL, .desired = 0, .alignment = 0 }; + auto* data = static_cast(memory_alloc_with_policy(size, &policy)); + if (data != nullptr) { + const bool success = fread(data, 1, size, file) == size; + fclose(file); + if (!success) { + memory_free(data); + return ERROR_NOT_SUPPORTED; + } + return binfont_open_memory(data, size, true, out); + } + } + + BinFont* font = create_font(); + if (font == nullptr) { + fclose(file); + return ERROR_OUT_OF_MEMORY; + } + font->file = file; + + const error_t error = parse_layout(font, size); + if (error != ERROR_NONE) { + binfont_close(font); + return error; + } + *out = font; + return ERROR_NONE; +} + +void binfont_close(BinFont* font) { + if (font->ownsData) { + memory_free(const_cast(font->data)); + } + if (font->file != nullptr) { + fclose(font->file); + } + memory_free(font->tables); + mutex_destruct(&font->mutex); + memory_free(font); +} + +void binfont_get_metrics(const BinFont* font, BinFontMetrics* out) { + const Header& header = font->header; + out->size = header.fontSize; + out->ascent = header.ascent; + out->descent = header.descent; + out->line_height = static_cast(header.ascent - header.descent); + out->base_line = static_cast(-header.descent); + out->underline_position = header.underlinePosition; + out->underline_thickness = header.underlineThickness; + out->bpp = header.bpp; +} + +bool binfont_get_glyph(BinFont* font, uint32_t codepoint, BinFontGlyph* out) { + const uint32_t glyph_id = find_glyph_id(font, codepoint); + uint8_t buffer[GLYPH_HEADER_MAX_BYTES]; + const uint8_t* record; + size_t size; + uint8_t* allocated; + if (!get_glyph_record(font, glyph_id, sizeof(buffer), buffer, sizeof(buffer), record, size, allocated)) { + return false; + } + BitReader reader(record, size); + parse_glyph(font->header, reader, glyph_id, out); + return true; +} + +int32_t binfont_get_kerning_x16(BinFont* font, uint32_t left_glyph_id, uint32_t right_glyph_id) { + const uint8_t* kern = font->kern; + if (kern == nullptr) { + return 0; + } + + int8_t value = 0; + if (kern[8] == 0) { + const uint32_t count = read_u32(kern + 12); + const uint8_t* pairs = kern + 16; + const bool wide = font->header.glyphIdFormat != 0; + const size_t pair_size = wide ? 4 : 2; + const uint32_t key = (left_glyph_id << 16) | right_glyph_id; + uint32_t low = 0; + uint32_t high = count; + while (low < high) { + const uint32_t mid = (low + high) / 2; + const uint8_t* pair = pairs + mid * pair_size; + const uint32_t left = wide ? read_u16(pair) : pair[0]; + const uint32_t right = wide ? read_u16(pair + 2) : pair[1]; + const uint32_t mid_key = (left << 16) | right; + if (mid_key == key) { + value = static_cast(pairs[count * pair_size + mid]); + break; + } else if (mid_key < key) { + low = mid + 1; + } else { + high = mid; + } + } + } else { + const uint16_t glyph_count = read_u16(kern + 12); + const uint8_t right_count = kern[15]; + if (left_glyph_id >= glyph_count || right_glyph_id >= glyph_count) { + return 0; + } + const uint8_t* left_classes = kern + 16; + const uint8_t* right_classes = left_classes + glyph_count; + const uint8_t* values = right_classes + glyph_count; + const uint8_t left_class = left_classes[left_glyph_id]; + const uint8_t right_class = right_classes[right_glyph_id]; + if (left_class == 0 || right_class == 0 || left_class > kern[14] || right_class > right_count) { + return 0; + } + value = static_cast(values[(left_class - 1) * right_count + (right_class - 1)]); + } + + return (static_cast(value) * font->header.kerningScale) >> 4; +} + +error_t binfont_get_glyph_bitmap(BinFont* font, const BinFontGlyph* glyph, uint8_t* out, size_t stride) { + if (stride < glyph->width) { + return ERROR_INVALID_ARGUMENT; + } + if (glyph->width == 0 || glyph->height == 0) { + return ERROR_NONE; + } + + const uint8_t* record; + size_t size; + uint8_t* allocated; + if (!get_glyph_record(font, glyph->glyph_id, SIZE_MAX, nullptr, 0, record, size, allocated)) { + return ERROR_RESOURCE; + } + + const Header& header = font->header; + const uint8_t bpp = header.bpp; + const size_t header_bits = header.advanceWidthBits + 2U * header.xyBits + 2U * header.whBits; + BitReader reader(record, size, header_bits); + + // Raw pixel values first, so the XOR prefilter can work on the previous line + if (header.compression == COMPRESSION_NONE) { + for (uint16_t y = 0; y < glyph->height; y++) { + uint8_t* line = out + y * stride; + for (uint16_t x = 0; x < glyph->width; x++) { + line[x] = static_cast(reader.read(bpp)); + } + } + } else { + RleReader rle(reader, bpp); + const bool prefilter = header.compression == COMPRESSION_RLE_PREFILTER; + for (uint16_t y = 0; y < glyph->height; y++) { + uint8_t* line = out + y * stride; + const uint8_t* previous = line - stride; + for (uint16_t x = 0; x < glyph->width; x++) { + const uint8_t value = rle.next(); + line[x] = (prefilter && y > 0) ? (value ^ previous[x]) : value; + } + } + } + + const uint32_t max_value = (1U << bpp) - 1; + for (uint16_t y = 0; y < glyph->height; y++) { + uint8_t* line = out + y * stride; + for (uint16_t x = 0; x < glyph->width; x++) { + line[x] = static_cast(line[x] * 255U / max_value); + } + } + + memory_free(allocated); + return ERROR_NONE; +} + +} diff --git a/Modules/binfont-module/source/generator.cpp b/Modules/binfont-module/source/generator.cpp new file mode 100644 index 000000000..c16b0e7e2 --- /dev/null +++ b/Modules/binfont-module/source/generator.cpp @@ -0,0 +1,443 @@ +// SPDX-License-Identifier: Apache-2.0 +#include + +#include + +#include +#include +#include +#include +#include + +#define STBTT_STATIC +#define STB_TRUETYPE_IMPLEMENTATION +#define STBTT_malloc(size, user) ((void)(user), memory_alloc(size)) +#define STBTT_free(pointer, user) ((void)(user), memory_free(pointer)) +#include "stb_truetype.h" + +namespace { + +constexpr size_t HEAD_SIZE = 48; +constexpr uint8_t CMAP_FORMAT_0_TINY = 2; +constexpr uint8_t CMAP_FORMAT_SPARSE_TINY = 3; +constexpr uint32_t CMAP_MAX_RANGE = 0xFFFF; + +constexpr MemoryPolicy EXTERNAL_PREFERRED = { .required = 0, .desired = MEMORY_CAPABILITY_EXTERNAL, .alignment = 0 }; + +class ByteBuffer { + uint8_t* data = nullptr; + size_t size = 0; + size_t capacity = 0; + bool failed = false; + + bool reserve(size_t required) { + if (failed) { + return false; + } + if (required <= capacity) { + return true; + } + size_t new_capacity = capacity ? capacity * 2 : 4096; + while (new_capacity < required) { + new_capacity *= 2; + } + auto* new_data = static_cast(memory_realloc_with_policy(data, new_capacity, &EXTERNAL_PREFERRED)); + if (new_data == nullptr) { + failed = true; + return false; + } + data = new_data; + capacity = new_capacity; + return true; + } + +public: + ~ByteBuffer() { memory_free(data); } + + size_t getSize() const { return size; } + bool hasFailed() const { return failed; } + + void append(const void* bytes, size_t count) { + if (reserve(size + count)) { + memcpy(data + size, bytes, count); + size += count; + } + } + + void appendZeros(size_t count) { + if (reserve(size + count)) { + memset(data + size, 0, count); + size += count; + } + } + + void appendU8(uint8_t value) { append(&value, 1); } + + void appendU16(uint16_t value) { + const uint8_t bytes[2] = { static_cast(value), static_cast(value >> 8) }; + append(bytes, 2); + } + + void appendU32(uint32_t value) { + const uint8_t bytes[4] = { static_cast(value), static_cast(value >> 8), static_cast(value >> 16), static_cast(value >> 24) }; + append(bytes, 4); + } + + void setU32(size_t offset, uint32_t value) { + if (!failed) { + data[offset] = static_cast(value); + data[offset + 1] = static_cast(value >> 8); + data[offset + 2] = static_cast(value >> 16); + data[offset + 3] = static_cast(value >> 24); + } + } + + void alignTo4() { appendZeros((4 - size % 4) % 4); } + + /** Starts a record and returns its offset, for endRecord(). */ + size_t beginRecord(const char* marker) { + const size_t offset = size; + appendU32(0); + append(marker, 4); + return offset; + } + + void endRecord(size_t offset) { setU32(offset, static_cast(size - offset)); } + + uint8_t* release() { + uint8_t* result = data; + data = nullptr; + size = 0; + capacity = 0; + return result; + } +}; + +/** MSB-first bit writer */ +class BitWriter { + ByteBuffer& buffer; + uint8_t current = 0; + uint8_t used = 0; + +public: + explicit BitWriter(ByteBuffer& buffer) : buffer(buffer) {} + + void write(uint32_t value, uint8_t bits) { + while (bits > 0) { + bits--; + current = static_cast((current << 1) | ((value >> bits) & 1U)); + used++; + if (used == 8) { + buffer.appendU8(current); + current = 0; + used = 0; + } + } + } + + void flush() { + if (used > 0) { + buffer.appendU8(static_cast(current << (8 - used))); + current = 0; + used = 0; + } + } +}; + +struct GlyphInfo { + uint32_t codepoint; + int ttfIndex; + uint32_t advanceX16; + int x0, y0, x1, y1; // stb_truetype bitmap box: y points down +}; + +uint8_t bits_for_unsigned(uint32_t value) { + uint8_t bits = 1; + while (bits < 32 && (value >> bits) != 0) { + bits++; + } + return bits; +} + +uint8_t bits_for_signed(int32_t min, int32_t max) { + uint8_t bits = 1; + while (bits < 32 && (min < -(1 << (bits - 1)) || max > (1 << (bits - 1)) - 1)) { + bits++; + } + return bits; +} + +int16_t scale_metric(int value, float scale) { + return static_cast(std::lround(static_cast(value) * scale)); +} + +uint8_t* read_file(const char* path, size_t& size) { + FILE* file = fopen(path, "rb"); + if (file == nullptr) { + return nullptr; + } + uint8_t* data = nullptr; + long file_size = 0; + if (fseek(file, 0, SEEK_END) == 0 && (file_size = ftell(file)) > 0 && fseek(file, 0, SEEK_SET) == 0) { + data = static_cast(memory_alloc_with_policy(static_cast(file_size), &EXTERNAL_PREFERRED)); + if (data != nullptr && fread(data, 1, static_cast(file_size), file) != static_cast(file_size)) { + memory_free(data); + data = nullptr; + } + } + fclose(file); + size = static_cast(file_size); + return data; +} + +void write_cmap(ByteBuffer& out, const GlyphInfo* glyphs, size_t count) { + // Glyph ids are 1..count in codepoint order, so every subtable can be a "tiny" format + struct Range { + size_t first; + size_t count; + bool contiguous; + }; + + auto next_range = [&](size_t first) { + Range range = { first, 1, true }; + while (first + range.count < count && range.count < CMAP_MAX_RANGE) { + const GlyphInfo& candidate = glyphs[first + range.count]; + if (candidate.codepoint - glyphs[first].codepoint >= CMAP_MAX_RANGE) { + break; + } + if (candidate.codepoint != glyphs[first].codepoint + range.count) { + range.contiguous = false; + } + range.count++; + } + return range; + }; + + uint32_t range_count = 0; + for (size_t i = 0; i < count; i += next_range(i).count) { + range_count++; + } + + const size_t record = out.beginRecord("cmap"); + out.appendU32(range_count); + + size_t data_offset = 12 + range_count * 16; + for (size_t i = 0; i < count;) { + const Range range = next_range(i); + const uint32_t range_start = glyphs[i].codepoint; + const uint32_t range_length = glyphs[i + range.count - 1].codepoint - range_start + 1; + out.appendU32(range.contiguous ? 0 : static_cast(data_offset)); + out.appendU32(range_start); + out.appendU16(static_cast(range_length)); + out.appendU16(static_cast(i + 1)); + out.appendU16(range.contiguous ? 0 : static_cast(range.count)); + out.appendU8(range.contiguous ? CMAP_FORMAT_0_TINY : CMAP_FORMAT_SPARSE_TINY); + out.appendU8(0); + if (!range.contiguous) { + data_offset += (range.count * 2 + 3) & ~static_cast(3); + } + i += range.count; + } + + for (size_t i = 0; i < count;) { + const Range range = next_range(i); + if (!range.contiguous) { + for (size_t j = 0; j < range.count; j++) { + out.appendU16(static_cast(glyphs[i + j].codepoint - glyphs[i].codepoint)); + } + out.alignTo4(); + } + i += range.count; + } + + out.endRecord(record); +} + +error_t generate(const BinFontGeneratorConfig* config, const stbtt_fontinfo& info, GlyphInfo* glyphs, ByteBuffer& out) { + const float scale = stbtt_ScaleForMappingEmToPixels(&info, config->size); + + // Collect glyphs, sorted by codepoint and without duplicates or missing glyphs + size_t count = 0; + for (size_t i = 0; i < config->codepoint_count; i++) { + const int index = stbtt_FindGlyphIndex(&info, static_cast(config->codepoints[i])); + if (index != 0) { + glyphs[count].codepoint = config->codepoints[i]; + glyphs[count].ttfIndex = index; + count++; + } + } + std::sort(glyphs, glyphs + count, [](const GlyphInfo& a, const GlyphInfo& b) { return a.codepoint < b.codepoint; }); + count = std::unique(glyphs, glyphs + count, [](const GlyphInfo& a, const GlyphInfo& b) { return a.codepoint == b.codepoint; }) - glyphs; + if (count == 0 || count >= 0xFFFF) { + return ERROR_NOT_SUPPORTED; + } + + int32_t min_xy = 0; + int32_t max_xy = 0; + uint32_t max_wh = 0; + uint32_t max_advance = 0; + // Like lv_font_conv, ascent and descent are the extents of the included glyphs + int32_t min_y = INT32_MAX; + int32_t max_y = INT32_MIN; + for (size_t i = 0; i < count; i++) { + GlyphInfo& glyph = glyphs[i]; + int advance; + int left_side_bearing; + stbtt_GetGlyphHMetrics(&info, glyph.ttfIndex, &advance, &left_side_bearing); + glyph.advanceX16 = static_cast(std::lround(static_cast(advance) * scale * 16.0f)); + stbtt_GetGlyphBitmapBox(&info, glyph.ttfIndex, scale, scale, &glyph.x0, &glyph.y0, &glyph.x1, &glyph.y1); + + const int32_t bottom = -glyph.y1; + min_xy = std::min({ min_xy, static_cast(glyph.x0), bottom }); + max_xy = std::max({ max_xy, static_cast(glyph.x0), bottom }); + max_wh = std::max({ max_wh, static_cast(glyph.x1 - glyph.x0), static_cast(glyph.y1 - glyph.y0) }); + max_advance = std::max(max_advance, glyph.advanceX16); + min_y = std::min(min_y, bottom); + max_y = std::max(max_y, static_cast(-glyph.y0)); + } + + const uint8_t xy_bits = bits_for_signed(min_xy, max_xy); + const uint8_t wh_bits = bits_for_unsigned(max_wh); + const uint8_t advance_bits = bits_for_unsigned(max_advance); + const uint32_t glyph_count = static_cast(count) + 1; + + int typo_ascent = 0; + int typo_descent = 0; + int typo_line_gap = 0; + stbtt_GetFontVMetricsOS2(&info, &typo_ascent, &typo_descent, &typo_line_gap); + int underline_position = 0; + int underline_thickness = 0; + const stbtt_uint32 post = stbtt__find_table(info.data, info.fontstart, "post"); + if (post != 0) { + underline_position = ttSHORT(info.data + post + 8); + underline_thickness = ttSHORT(info.data + post + 10); + } + + // head + const size_t head = out.beginRecord("head"); + out.appendU32(1); // version + out.appendU16(3); // additional tables: cmap, loca, glyf + out.appendU16(config->size); + out.appendU16(static_cast(max_y)); + out.appendU16(static_cast(min_y)); + out.appendU16(static_cast(scale_metric(typo_ascent, scale))); + out.appendU16(static_cast(scale_metric(typo_descent, scale))); + out.appendU16(static_cast(scale_metric(typo_line_gap, scale))); + out.appendU16(static_cast(min_y)); + out.appendU16(static_cast(max_y)); + out.appendU16(0); // default advance width + out.appendU16(16); // kerning scale 1.0 in FP12.4 + out.appendU8(1); // loca: Offset32 + out.appendU8(glyph_count > 256 ? 1 : 0); + out.appendU8(1); // advance width with 4 fractional bits + out.appendU8(config->bpp); + out.appendU8(xy_bits); + out.appendU8(wh_bits); + out.appendU8(advance_bits); + out.appendU8(0); // no compression + out.appendU8(0); // no subpixel rendering + out.appendU8(0); + out.appendU16(static_cast(scale_metric(underline_position, scale))); + out.appendU16(static_cast(scale_metric(underline_thickness, scale))); + out.endRecord(head); + + write_cmap(out, glyphs, count); + + const size_t loca = out.beginRecord("loca"); + out.appendU32(glyph_count); + const size_t loca_entries = out.getSize(); + out.appendZeros(glyph_count * 4); + out.endRecord(loca); + + const size_t glyf = out.beginRecord("glyf"); + uint8_t* bitmap = nullptr; + size_t bitmap_capacity = 0; + const uint32_t max_value = (1U << config->bpp) - 1; + for (uint32_t id = 0; id < glyph_count && !out.hasFailed(); id++) { + out.setU32(loca_entries + id * 4, static_cast(out.getSize() - glyf)); + BitWriter writer(out); + if (id == 0) { + writer.write(0, advance_bits); + writer.write(0, xy_bits); + writer.write(0, xy_bits); + writer.write(0, wh_bits); + writer.write(0, wh_bits); + writer.flush(); + continue; + } + + const GlyphInfo& glyph = glyphs[id - 1]; + const int width = glyph.x1 - glyph.x0; + const int height = glyph.y1 - glyph.y0; + writer.write(glyph.advanceX16, advance_bits); + writer.write(static_cast(glyph.x0), xy_bits); + writer.write(static_cast(-glyph.y1), xy_bits); + writer.write(static_cast(width), wh_bits); + writer.write(static_cast(height), wh_bits); + + const size_t pixel_count = static_cast(width) * height; + if (pixel_count > 0) { + if (pixel_count > bitmap_capacity) { + memory_free(bitmap); + bitmap = static_cast(memory_alloc_with_policy(pixel_count, &EXTERNAL_PREFERRED)); + if (bitmap == nullptr) { + return ERROR_OUT_OF_MEMORY; + } + bitmap_capacity = pixel_count; + } + stbtt_MakeGlyphBitmap(&info, bitmap, width, height, width, scale, scale, glyph.ttfIndex); + for (size_t i = 0; i < pixel_count; i++) { + writer.write((bitmap[i] * max_value + 127) / 255, config->bpp); + } + } + writer.flush(); + } + memory_free(bitmap); + out.alignTo4(); + out.endRecord(glyf); + + return out.hasFailed() ? ERROR_OUT_OF_MEMORY : ERROR_NONE; +} + +} // namespace + +extern "C" { + +error_t binfont_generate(const BinFontGeneratorConfig* config, uint8_t** out_data, size_t* out_size) { + if (config->ttf_path == nullptr || config->size == 0 || config->bpp < 1 || config->bpp > 4 || config->codepoint_count == 0) { + return ERROR_INVALID_ARGUMENT; + } + + size_t ttf_size = 0; + uint8_t* ttf = read_file(config->ttf_path, ttf_size); + if (ttf == nullptr) { + return ERROR_NOT_FOUND; + } + + stbtt_fontinfo info; + const int font_offset = stbtt_GetFontOffsetForIndex(ttf, 0); + if (font_offset < 0 || stbtt_InitFont(&info, ttf, font_offset) == 0) { + memory_free(ttf); + return ERROR_NOT_SUPPORTED; + } + + auto* glyphs = static_cast(memory_alloc(config->codepoint_count * sizeof(GlyphInfo))); + if (glyphs == nullptr) { + memory_free(ttf); + return ERROR_OUT_OF_MEMORY; + } + + ByteBuffer out; + const error_t error = generate(config, info, glyphs, out); + memory_free(glyphs); + memory_free(ttf); + if (error != ERROR_NONE) { + return error; + } + + *out_size = out.getSize(); + *out_data = out.release(); + return ERROR_NONE; +} + +} diff --git a/Modules/binfont-module/source/module.c b/Modules/binfont-module/source/module.c new file mode 100644 index 000000000..b570fdcb1 --- /dev/null +++ b/Modules/binfont-module/source/module.c @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: Apache-2.0 +#include +#include +#include +#include + +static const struct ModuleSymbol SYMBOLS[] = { + // binfont + DEFINE_MODULE_SYMBOL(binfont_open_file), + DEFINE_MODULE_SYMBOL(binfont_open_memory), + DEFINE_MODULE_SYMBOL(binfont_close), + DEFINE_MODULE_SYMBOL(binfont_get_metrics), + DEFINE_MODULE_SYMBOL(binfont_get_glyph), + DEFINE_MODULE_SYMBOL(binfont_get_kerning_x16), + DEFINE_MODULE_SYMBOL(binfont_get_glyph_bitmap), + // generator + DEFINE_MODULE_SYMBOL(binfont_generate), + // render + DEFINE_MODULE_SYMBOL(binfont_draw_glyph_rgb565), + DEFINE_MODULE_SYMBOL(binfont_draw_text_rgb565), + MODULE_SYMBOL_TERMINATOR, +}; + +struct Module binfont_module = { + .name = "binfont", + .start = NULL, + .stop = NULL, + .drivers = NULL, + .symbols = SYMBOLS, + .internal = NULL, +}; diff --git a/Modules/binfont-module/source/render.cpp b/Modules/binfont-module/source/render.cpp new file mode 100644 index 000000000..f91f25c78 --- /dev/null +++ b/Modules/binfont-module/source/render.cpp @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: Apache-2.0 +#include + +#include + +namespace { + +constexpr size_t STACK_BITMAP_SIZE = 1024; + +uint16_t blend_rgb565(uint16_t foreground, uint16_t background, uint8_t alpha) { + const uint32_t inverse = 255U - alpha; + const uint32_t r = (((foreground >> 11) & 0x1FU) * alpha + ((background >> 11) & 0x1FU) * inverse + 127U) / 255U; + const uint32_t g = (((foreground >> 5) & 0x3FU) * alpha + ((background >> 5) & 0x3FU) * inverse + 127U) / 255U; + const uint32_t b = ((foreground & 0x1FU) * alpha + (background & 0x1FU) * inverse + 127U) / 255U; + return static_cast((r << 11) | (g << 5) | b); +} + +void draw_glyph(PixelBuffer* buffer, int x, int baselineY, BinFont* font, const BinFontGlyph& glyph, uint16_t color, PixelBufferConversion conversion) { + const size_t pixel_count = static_cast(glyph.width) * glyph.height; + if (pixel_count == 0) { + return; + } + + uint8_t stack_bitmap[STACK_BITMAP_SIZE]; + uint8_t* allocated = nullptr; + uint8_t* bitmap = stack_bitmap; + if (pixel_count > sizeof(stack_bitmap)) { + allocated = static_cast(memory_alloc(pixel_count)); + if (allocated == nullptr) { + return; + } + bitmap = allocated; + } + + if (binfont_get_glyph_bitmap(font, &glyph, bitmap, glyph.width) == ERROR_NONE) { + const int left = x + glyph.x; + const int top = baselineY - glyph.y - glyph.height; + for (int row = 0; row < glyph.height; row++) { + const uint8_t* line = bitmap + row * glyph.width; + for (int column = 0; column < glyph.width; column++) { + const uint8_t alpha = line[column]; + if (alpha == 0) { + continue; + } + const int pixel_x = left + column; + const int pixel_y = top + row; + const uint16_t pixel = (alpha == 255) ? color : blend_rgb565(color, pixel_buffer_get_pixel_rgb565(buffer, pixel_x, pixel_y), alpha); + pixel_buffer_set_pixel_rgb565(buffer, pixel_x, pixel_y, pixel, conversion); + } + } + } + + memory_free(allocated); +} + +/** Decodes one UTF-8 codepoint and advances text. Invalid sequences decode as U+FFFD. */ +uint32_t next_codepoint(const char*& text) { + const auto* bytes = reinterpret_cast(text); + const uint8_t lead = bytes[0]; + int length; + uint32_t codepoint; + if (lead < 0x80) { + length = 1; + codepoint = lead; + } else if ((lead & 0xE0) == 0xC0) { + length = 2; + codepoint = lead & 0x1FU; + } else if ((lead & 0xF0) == 0xE0) { + length = 3; + codepoint = lead & 0x0FU; + } else if ((lead & 0xF8) == 0xF0) { + length = 4; + codepoint = lead & 0x07U; + } else { + text++; + return 0xFFFD; + } + for (int i = 1; i < length; i++) { + if ((bytes[i] & 0xC0) != 0x80) { + text += i; + return 0xFFFD; + } + codepoint = (codepoint << 6) | (bytes[i] & 0x3FU); + } + text += length; + return codepoint; +} + +} // namespace + +extern "C" { + +int binfont_draw_glyph_rgb565(PixelBuffer* buffer, int x, int baseline_y, BinFont* font, uint32_t codepoint, uint16_t color, PixelBufferConversion conversion) { + BinFontGlyph glyph; + if (!binfont_get_glyph(font, codepoint, &glyph)) { + return 0; + } + draw_glyph(buffer, x, baseline_y, font, glyph, color, conversion); + return static_cast((glyph.advance_x16 + 8) >> 4); +} + +int binfont_draw_text_rgb565(PixelBuffer* buffer, int x, int baseline_y, BinFont* font, const char* text, uint16_t color, PixelBufferConversion conversion) { + int32_t pen_x16 = 0; + uint32_t previous_glyph_id = 0; + while (*text != '\0') { + BinFontGlyph glyph; + if (!binfont_get_glyph(font, next_codepoint(text), &glyph)) { + previous_glyph_id = 0; + continue; + } + if (previous_glyph_id != 0) { + pen_x16 += binfont_get_kerning_x16(font, previous_glyph_id, glyph.glyph_id); + } + draw_glyph(buffer, x + ((pen_x16 + 8) >> 4), baseline_y, font, glyph, color, conversion); + pen_x16 += static_cast(glyph.advance_x16); + previous_glyph_id = glyph.glyph_id; + } + return (pen_x16 + 8) >> 4; +} + +} diff --git a/Modules/binfont-module/tests/CMakeLists.txt b/Modules/binfont-module/tests/CMakeLists.txt new file mode 100644 index 000000000..5059cff9c --- /dev/null +++ b/Modules/binfont-module/tests/CMakeLists.txt @@ -0,0 +1,22 @@ +project(BinFontModuleTests) + +enable_language(C CXX ASM) + +file(GLOB_RECURSE TEST_SOURCES CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/source/*.cpp) +add_executable(BinFontModuleTests EXCLUDE_FROM_ALL ${TEST_SOURCES}) + +target_include_directories(BinFontModuleTests PRIVATE ${DOCTESTINC}) + +target_compile_definitions(BinFontModuleTests PRIVATE + "BINFONT_TEST_FIXTURES_DIR=\"${PROJECT_SOURCE_DIR}/fixtures\"" + "BINFONT_TEST_ICON_TTF=\"${CMAKE_SOURCE_DIR}/Data/system/fonts/MaterialSymbolsRounded.ttf\"" +) + +add_test(NAME BinFontModuleTests COMMAND BinFontModuleTests) + +target_link_libraries(BinFontModuleTests PUBLIC + binfont-module + graphics-module + TactilityKernel + freertos_kernel +) diff --git a/Modules/binfont-module/tests/fixtures/icons_raw_2.bin b/Modules/binfont-module/tests/fixtures/icons_raw_2.bin new file mode 100644 index 0000000000000000000000000000000000000000..dcad40cb8d97c8038c80e4750fc3945dec449383 GIT binary patch literal 548 zcma)3Jxjw-6g^4WM(mL4P(%w6ad2w=0i{XNO+oM*D0F%>obu zo?md{vNhfbzoS}pV2uax5?BfF2m~R56oa2|Q0?`cTFFWQ{xx6`*t~URNCEi+s_2XK z;EIr_+4F-a8!7O2FWq|V_Ma0^=p(LuH70HDy!GOvD_1~X2_hgyw!EV|aX6-@$Y@8^j*2>~OFV19+a4|y3%;&kA4 n%6t^3;s?V@{#Bxh^(JwwL2q?Ix3JmikQO9bKub+Ur}Fp*0;94g literal 0 HcmV?d00001 diff --git a/Modules/binfont-module/tests/fixtures/icons_raw_4.bin b/Modules/binfont-module/tests/fixtures/icons_raw_4.bin new file mode 100644 index 0000000000000000000000000000000000000000..e9cfb08342a0ed671b19344a49bc448775115d89 GIT binary patch literal 960 zcmcIiO=uHA6#jN+(-o{%yOM}j5GyEzLZQbXvj-1?2;#+aX#D|O;?+}@(qp9F(t{U4 z=}9~kkrHsC^pJ~CB!?b)P%OC692BY;b~n%WHrb?jwr^*?@0&Mo-n^ZeSpX03l@}~# zg|o=R#yRu|%y}N4Vm}-wCnR>2`}|V*vBXbtU;heBx)yT08n|dpId$i>3tkBC7qL6VljzZhi^oQyvs;Riq@y4MeiBoAbv}o8143}SehGP^O^Xlkf`eOc_&{Ci$@TC{q2wk#OC_+81iL=+@96awtTlF? zm(@LArfpVi2QpCRR||J_++=Od2u^-s_}2>W{h`ayPNwTb3l7*uFz&}(KFsgJ^J^li2uSLGA$^V z`G5Zt`}>L$?oWsjU$5|mU%cr{#UAPF>)H1o{QaRmuKDXP{`eQBkB={iV{bqFU{95d z`3w76_U{Y+2Uw^qk^jm6`~QOf6_)>heyIHakE8yhJ^O#*4|u5mKmGrIoZ!+TuTazY z`Gf%%B@v;Q9T zAN2n}Sorn-pMdi}9nb!0{v!W}`x8(-{}Yblx(QF&&jTH`{{Msa-=8G^$Uk%b?C}5X zzUKcEfAaq`{>A^#{)zpM_Y3|rC@p1v{h|H?Q0;>~{On)PFQ^P_t)EbTuyTjx=fZ+Y z$M@nB)}IJ(td##?=kzK5$tUTP^^;G8PyEmPWKV0I)1DZ)fa(LE3#!i^*ndL*L-u@! UPiy(lGavka=wI{y);j(J0PI-Rr~m)} literal 0 HcmV?d00001 diff --git a/Modules/binfont-module/tests/fixtures/icons_rle_4.bin b/Modules/binfont-module/tests/fixtures/icons_rle_4.bin new file mode 100644 index 0000000000000000000000000000000000000000..4114699ea4460d5ace11e5f8ae24a871c8131748 GIT binary patch literal 704 zcma)!Ur19?9LIlWXV;rV^vC>{#vK+VM5qw-M`;U$dXTbu=%u<2(|XVfA|hm+V^qwL z93fZ_LmvtQixs_0BsX%wB4ScO5yCc85)Es&+^+8K{yMwid*^V@_xt;OKfhls09|HT<4m zD8SJ!FZ=^(#MQ8Se?0xsC+iD{-FHbcfaZ=eyB}Xnx@?`yNH|w|sZodhp((ByRk7bB z$lIRb)gW(gk>AJh13?v$Hqvb9>kJgf^sw{(6xB`xOMf1BIrUk5K(RNpBJ7*Iz4uBZ zX4PXj*q1#*@uoB9QjE=6TMmr9&mU@l2h>{0X*L%yo#Q*zQRxq;ZXp+6+dxUhG&qSq zTOcK2e<=pZ;4HkH+=bEdd9teN@*$SxkR<;SQFfIH2bVPV$iGSOY&*i)zTrllL;Fi+_9ez_li3VZ4m)WaUdYXN zOvWzZzd^kgkIEAHpZvf0SIGb2e^LLFe}?^qy80jX{~!MU&;M`x|BsC9|D{}7_s=<)?#xgP19OIqNsVNK|?BrL@Wv0d?%FcgMA32J=mZr zX(}@9OU##{eW^u8BPg#SVScLy`a#XD1WS-bDhtP+uJarYfBxtHJKv5806JP7El5xb zav%#tpn)U-L9+y}6!t*VVmJbXG78h&Q70MpybzoNj zyGQuyr#^)9r&aTbP2E1rOoA?=Nc!Dm4eLt4ErSQQ$)-|4;tWYpWIB(KMf3_tR0fwk zst~4k^{Aq+rUQG^huM(#FxwFeJN_ ziY-t(4`+FrQ~b89=;1{}Id&I>n4cjak(c+e`_Hl`7wZ!3uz|=Ymuyp)Xqu4NnV2B} z7oQwjDAIcdslgq)uG-U5v5k+MQmG331*_-4fhl$_S6?c%I;|4hsL^6Mzp`{9IJ2{w zH+~Wdm!6ry2Cb5CCcXgYYP`jKEnj981%Pbb#E-DcFRsgYct^@>aLz=HeOsg&uEd#G zZuY(7);))f3+!s4`8}82Yn{-u<{lF-q8nsNa0-r1`}&WoHlErpV+egqWQ4fzYySZl Cr2eA- literal 0 HcmV?d00001 diff --git a/Modules/binfont-module/tests/fixtures/text_kern_classes.bin b/Modules/binfont-module/tests/fixtures/text_kern_classes.bin new file mode 100644 index 0000000000000000000000000000000000000000..627c09e9c02a8a79c20afda983e565ac0ac2e99f GIT binary patch literal 3600 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 literal 0 HcmV?d00001 diff --git a/Modules/binfont-module/tests/fixtures/text_kern_pairs.bin b/Modules/binfont-module/tests/fixtures/text_kern_pairs.bin new file mode 100644 index 0000000000000000000000000000000000000000..b0ba3cc67d045da534a62deb1b69ad184f19d218 GIT binary patch literal 3460 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 Ks2nFJ;Qs(bYs|a= literal 0 HcmV?d00001 diff --git a/Modules/binfont-module/tests/source/binfont_test.cpp b/Modules/binfont-module/tests/source/binfont_test.cpp new file mode 100644 index 000000000..073fe1e25 --- /dev/null +++ b/Modules/binfont-module/tests/source/binfont_test.cpp @@ -0,0 +1,286 @@ +#include "doctest.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace { + +constexpr uint32_t ICON_CODEPOINTS[] = { 0xE5C3, 0xE8B8, 0xE2C7, 0xE63E, 0xE1A7 }; + +std::string fixture(const char* name) { + return std::string(BINFONT_TEST_FIXTURES_DIR) + "/" + name; +} + +/** Loads a file into memory allocated with memory_alloc() */ +uint8_t* load_file(const std::string& path, size_t& size) { + FILE* file = fopen(path.c_str(), "rb"); + REQUIRE(file != nullptr); + fseek(file, 0, SEEK_END); + size = static_cast(ftell(file)); + fseek(file, 0, SEEK_SET); + auto* data = static_cast(memory_alloc(size)); + REQUIRE(fread(data, 1, size, file) == size); + fclose(file); + return data; +} + +BinFont* open_fixture_in_memory(const char* name) { + size_t size; + uint8_t* data = load_file(fixture(name), size); + BinFont* font = nullptr; + REQUIRE(binfont_open_memory(data, size, true, &font) == ERROR_NONE); + return font; +} + +std::vector decode(BinFont* font, const BinFontGlyph& glyph) { + std::vector bitmap(static_cast(glyph.width) * glyph.height); + REQUIRE(binfont_get_glyph_bitmap(font, &glyph, bitmap.data(), glyph.width) == ERROR_NONE); + return bitmap; +} + +uint32_t sum(const std::vector& bitmap) { + uint32_t total = 0; + for (uint8_t value : bitmap) { + total += value; + } + return total; +} + +void check_same_glyph(const BinFontGlyph& a, const BinFontGlyph& b) { + CHECK_EQ(a.glyph_id, b.glyph_id); + CHECK_EQ(a.advance_x16, b.advance_x16); + CHECK_EQ(a.x, b.x); + CHECK_EQ(a.y, b.y); + CHECK_EQ(a.width, b.width); + CHECK_EQ(a.height, b.height); +} + +} // namespace + +TEST_CASE("binfont_open_file returns ERROR_NOT_FOUND for a missing file") { + BinFont* font = nullptr; + CHECK_EQ(binfont_open_file(fixture("missing.bin").c_str(), &font), ERROR_NOT_FOUND); +} + +TEST_CASE("binfont_open_memory rejects data that is not a font") { + const uint8_t data[64] = { 1, 2, 3, 4 }; + BinFont* font = nullptr; + CHECK_EQ(binfont_open_memory(data, sizeof(data), false, &font), ERROR_NOT_SUPPORTED); +} + +TEST_CASE("binfont reads metrics, glyphs and bitmaps that match lv_font_conv's C output") { + BinFont* font = open_fixture_in_memory("text_kern_pairs.bin"); + + BinFontMetrics metrics; + binfont_get_metrics(font, &metrics); + CHECK_EQ(metrics.size, 20); + CHECK_EQ(metrics.line_height, 20); + CHECK_EQ(metrics.base_line, 5); + CHECK_EQ(metrics.ascent, 15); + CHECK_EQ(metrics.descent, -5); + CHECK_EQ(metrics.underline_position, 1); + CHECK_EQ(metrics.underline_thickness, 0); + CHECK_EQ(metrics.bpp, 4); + + BinFontGlyph glyph; + REQUIRE(binfont_get_glyph(font, 'A', &glyph)); + CHECK_EQ(glyph.glyph_id, 1); + CHECK_EQ(glyph.advance_x16, 195); + CHECK_EQ(glyph.x, 0); + CHECK_EQ(glyph.y, 0); + CHECK_EQ(glyph.width, 13); + CHECK_EQ(glyph.height, 14); + + const auto bitmap = decode(font, glyph); + const std::vector first_row = { 0, 0, 0, 0, 0, 238, 255, 17, 0, 0, 0, 0, 0 }; + const std::vector last_row = { 221, 255, 0, 0, 0, 0, 0, 0, 0, 0, 238, 238, 0 }; + CHECK(std::vector(bitmap.begin(), bitmap.begin() + 13) == first_row); + CHECK(std::vector(bitmap.end() - 13, bitmap.end()) == last_row); + CHECK_EQ(sum(bitmap), 13974); + + REQUIRE(binfont_get_glyph(font, 'V', &glyph)); + CHECK_EQ(glyph.glyph_id, 22); + REQUIRE(binfont_get_glyph(font, 'z', &glyph)); + CHECK_EQ(glyph.glyph_id, 52); + + CHECK_FALSE(binfont_get_glyph(font, '0', &glyph)); + CHECK_FALSE(binfont_get_glyph(font, 0x5B, &glyph)); + CHECK_FALSE(binfont_get_glyph(font, 0x10FFFF, &glyph)); + + binfont_close(font); +} + +TEST_CASE("binfont kerning is the same for the pairs and the classes format") { + BinFont* pairs = open_fixture_in_memory("text_kern_pairs.bin"); + BinFont* classes = open_fixture_in_memory("text_kern_classes.bin"); + + CHECK_EQ(binfont_get_kerning_x16(pairs, 1, 22), -10); + CHECK_EQ(binfont_get_kerning_x16(classes, 1, 22), -10); + + int non_zero = 0; + for (uint32_t left = 1; left <= 52; left++) { + for (uint32_t right = 1; right <= 52; right++) { + const int32_t value = binfont_get_kerning_x16(pairs, left, right); + CHECK_EQ(value, binfont_get_kerning_x16(classes, left, right)); + if (value != 0) { + non_zero++; + } + } + } + CHECK(non_zero > 0); + CHECK_EQ(binfont_get_kerning_x16(pairs, 1, 1000), 0); + CHECK_EQ(binfont_get_kerning_x16(classes, 1, 1000), 0); + + binfont_close(pairs); + binfont_close(classes); +} + +TEST_CASE("binfont decodes identical bitmaps for raw, RLE and RLE with prefilter") { + for (const char* bpp : { "2", "4" }) { + CAPTURE(bpp); + BinFont* raw = open_fixture_in_memory((std::string("icons_raw_") + bpp + ".bin").c_str()); + BinFont* rle = open_fixture_in_memory((std::string("icons_rle_") + bpp + ".bin").c_str()); + BinFont* prefiltered = open_fixture_in_memory((std::string("icons_rlepf_") + bpp + ".bin").c_str()); + + for (uint32_t codepoint : ICON_CODEPOINTS) { + CAPTURE(codepoint); + BinFontGlyph raw_glyph, rle_glyph, prefiltered_glyph; + REQUIRE(binfont_get_glyph(raw, codepoint, &raw_glyph)); + REQUIRE(binfont_get_glyph(rle, codepoint, &rle_glyph)); + REQUIRE(binfont_get_glyph(prefiltered, codepoint, &prefiltered_glyph)); + check_same_glyph(raw_glyph, rle_glyph); + check_same_glyph(raw_glyph, prefiltered_glyph); + + const auto raw_bitmap = decode(raw, raw_glyph); + CHECK(sum(raw_bitmap) > 0); + CHECK(decode(rle, rle_glyph) == raw_bitmap); + CHECK(decode(prefiltered, prefiltered_glyph) == raw_bitmap); + } + + binfont_close(raw); + binfont_close(rle); + binfont_close(prefiltered); + } +} + +TEST_CASE("binfont gives the same results when streaming from a file") { + BinFont* memory_font = open_fixture_in_memory("icons_rlepf_4.bin"); + BinFont* file_font = nullptr; + REQUIRE(binfont_open_file(fixture("icons_rlepf_4.bin").c_str(), &file_font) == ERROR_NONE); + + for (uint32_t codepoint : ICON_CODEPOINTS) { + BinFontGlyph memory_glyph, file_glyph; + REQUIRE(binfont_get_glyph(memory_font, codepoint, &memory_glyph)); + REQUIRE(binfont_get_glyph(file_font, codepoint, &file_glyph)); + check_same_glyph(memory_glyph, file_glyph); + CHECK(decode(memory_font, memory_glyph) == decode(file_font, file_glyph)); + } + + binfont_close(memory_font); + binfont_close(file_font); +} + +TEST_CASE("binfont_get_glyph_bitmap rejects a stride smaller than the glyph width") { + BinFont* font = open_fixture_in_memory("icons_raw_2.bin"); + BinFontGlyph glyph; + REQUIRE(binfont_get_glyph(font, ICON_CODEPOINTS[0], &glyph)); + std::vector bitmap(static_cast(glyph.width) * glyph.height); + CHECK_EQ(binfont_get_glyph_bitmap(font, &glyph, bitmap.data(), glyph.width - 1), ERROR_INVALID_ARGUMENT); + binfont_close(font); +} + +TEST_CASE("binfont_generate rasterizes a TTF close to lv_font_conv") { + uint32_t codepoints[] = { 0xE8B8, 0xE5C3, 0x41, 0xE1A7, 0xE2C7, 0xE63E, 0xE5C3 }; // unsorted, duplicate and missing entries + const BinFontGeneratorConfig config = { + .ttf_path = BINFONT_TEST_ICON_TTF, + .size = 24, + .bpp = 4, + .codepoints = codepoints, + .codepoint_count = sizeof(codepoints) / sizeof(codepoints[0]), + }; + uint8_t* data = nullptr; + size_t size = 0; + REQUIRE(binfont_generate(&config, &data, &size) == ERROR_NONE); + + BinFont* generated = nullptr; + REQUIRE(binfont_open_memory(data, size, true, &generated) == ERROR_NONE); + BinFont* reference = open_fixture_in_memory("icons_raw_4.bin"); + + BinFontMetrics generated_metrics, reference_metrics; + binfont_get_metrics(generated, &generated_metrics); + binfont_get_metrics(reference, &reference_metrics); + CHECK_EQ(generated_metrics.size, 24); + CHECK_EQ(generated_metrics.bpp, 4); + CHECK_EQ(generated_metrics.ascent, reference_metrics.ascent); + CHECK_EQ(generated_metrics.descent, reference_metrics.descent); + + BinFontGlyph glyph; + CHECK_FALSE(binfont_get_glyph(generated, 0x41, &glyph)); + + for (uint32_t codepoint : ICON_CODEPOINTS) { + CAPTURE(codepoint); + BinFontGlyph generated_glyph, reference_glyph; + REQUIRE(binfont_get_glyph(generated, codepoint, &generated_glyph)); + REQUIRE(binfont_get_glyph(reference, codepoint, &reference_glyph)); + CHECK(std::abs(static_cast(generated_glyph.advance_x16) - static_cast(reference_glyph.advance_x16)) <= 16); + CHECK(std::abs(generated_glyph.x - reference_glyph.x) <= 1); + CHECK(std::abs(generated_glyph.y - reference_glyph.y) <= 1); + CHECK(std::abs(generated_glyph.width - reference_glyph.width) <= 1); + CHECK(std::abs(generated_glyph.height - reference_glyph.height) <= 1); + + const auto generated_sum = static_cast(sum(decode(generated, generated_glyph))); + const auto reference_sum = static_cast(sum(decode(reference, reference_glyph))); + CHECK(generated_sum > reference_sum * 0.9); + CHECK(generated_sum < reference_sum * 1.1); + } + + binfont_close(generated); + binfont_close(reference); +} + +TEST_CASE("binfont_generate fails for a missing TTF") { + const uint32_t codepoint = 0xE5C3; + const BinFontGeneratorConfig config = { + .ttf_path = BINFONT_TEST_FIXTURES_DIR "/missing.ttf", + .size = 24, + .bpp = 2, + .codepoints = &codepoint, + .codepoint_count = 1, + }; + uint8_t* data = nullptr; + size_t size = 0; + CHECK_EQ(binfont_generate(&config, &data, &size), ERROR_NOT_FOUND); +} + +TEST_CASE("binfont draws glyphs and text into a PixelBuffer") { + BinFont* font = open_fixture_in_memory("text_kern_pairs.bin"); + PixelBuffer* buffer = pixel_buffer_create(DISPLAY_COLOR_FORMAT_RGB565, 64, 24); + REQUIRE(buffer != nullptr); + pixel_buffer_clear(buffer); + + const int advance = binfont_draw_glyph_rgb565(buffer, 0, 18, font, 'A', 0xFFFF, PIXEL_BUFFER_CONVERSION_EXACT_BLACK); + CHECK_EQ(advance, (195 + 8) >> 4); + // Top of 'A' (row 0 of the glyph, column 6 is fully opaque) sits 14 rows above the baseline + CHECK_EQ(pixel_buffer_get_pixel_rgb565(buffer, 6, 18 - 14), 0xFFFF); + CHECK_EQ(pixel_buffer_get_pixel_rgb565(buffer, 0, 0), 0x0000); + + CHECK_EQ(binfont_draw_glyph_rgb565(buffer, 0, 18, font, '0', 0xFFFF, PIXEL_BUFFER_CONVERSION_EXACT_BLACK), 0); + + // "AV" is kerned: 195 - 10 + V's advance + BinFontGlyph v; + REQUIRE(binfont_get_glyph(font, 'V', &v)); + pixel_buffer_clear(buffer); + const int width = binfont_draw_text_rgb565(buffer, 0, 18, font, "AV", 0xFFFF, PIXEL_BUFFER_CONVERSION_EXACT_BLACK); + CHECK_EQ(width, static_cast((195 - 10 + v.advance_x16 + 8) >> 4)); + + pixel_buffer_free(buffer); + binfont_close(font); +} diff --git a/Modules/binfont-module/tests/source/main.cpp b/Modules/binfont-module/tests/source/main.cpp new file mode 100644 index 000000000..beedf9f8b --- /dev/null +++ b/Modules/binfont-module/tests/source/main.cpp @@ -0,0 +1,64 @@ +#define DOCTEST_CONFIG_IMPLEMENT +#include "doctest.h" +#include +#include + +#include "FreeRTOS.h" +#include "task.h" + +typedef struct { + int argc; + char** argv; + int result; +} TestTaskData; + +void test_task(void* parameter) { + auto* data = (TestTaskData*)parameter; + + doctest::Context context; + + context.applyCommandLine(data->argc, data->argv); + + // overrides + context.setOption("no-breaks", true); // don't break in the debugger when assertions fail + + data->result = context.run(); + + vTaskEndScheduler(); + + vTaskDelete(nullptr); +} + +int main(int argc, char** argv) { + TestTaskData data = { + .argc = argc, + .argv = argv, + .result = 0 + }; + + BaseType_t task_result = xTaskCreate( + test_task, + "test_task", + 8192, + &data, + 1, + nullptr + ); + + if (task_result != pdPASS) { + return 1; + } + + vTaskStartScheduler(); + + return data.result; +} + +// NOTE: This is normally provided by the platform kernel module, but that's not loaded for binfont-module +extern "C" { +// Required for FreeRTOS +void vAssertCalled(unsigned long line, const char* const file) { + std::fprintf(stderr, "assert failed at %s:%lu\n", file, line); + std::abort(); +} +} diff --git a/Modules/lvgl-module/CMakeLists.txt b/Modules/lvgl-module/CMakeLists.txt index 62d92db84..06337ee1d 100644 --- a/Modules/lvgl-module/CMakeLists.txt +++ b/Modules/lvgl-module/CMakeLists.txt @@ -70,14 +70,10 @@ endif () # Regular source files file(GLOB_RECURSE SOURCE_FILES "source/*.c*") -# Font source files -list(APPEND SOURCE_FILES "source-fonts/material_symbols_statusbar_${statusbar_symbol_size}.c") -list(APPEND SOURCE_FILES "source-fonts/material_symbols_launcher_${launcher_symbol_size}.c") -list(APPEND SOURCE_FILES "source-fonts/material_symbols_shared_${shared_symbol_size}.c") -list(APPEND SOURCE_FILES "source-fonts/material_symbols_shared_${shared_symbol_2x_size}.c") list(APPEND REQUIRES_LIST TactilityKernel + binfont-module lvgl ) @@ -118,13 +114,9 @@ target_compile_definitions(${MODULE_NAME} PUBLIC "-DTT_LVGL_TEXT_FONT_LARGE_SYMBOL=lv_font_montserrat_${font_size_large}" # Icon fonts "-DTT_LVGL_STATUSBAR_FONT_ICON_SIZE=${statusbar_symbol_size}" - "-DTT_LVGL_STATUSBAR_FONT_ICON_SYMBOL=material_symbols_statusbar_${statusbar_symbol_size}" "-DTT_LVGL_LAUNCHER_FONT_ICON_SIZE=${launcher_symbol_size}" - "-DTT_LVGL_LAUNCHER_FONT_ICON_SYMBOL=material_symbols_launcher_${launcher_symbol_size}" "-DTT_LVGL_SHARED_FONT_ICON_SIZE=${shared_symbol_size}" - "-DTT_LVGL_SHARED_FONT_ICON_SYMBOL=material_symbols_shared_${shared_symbol_size}" "-DTT_LVGL_SHARED_FONT_ICON_2X_SIZE=${shared_symbol_2x_size}" - "-DTT_LVGL_SHARED_FONT_ICON_2X_SYMBOL=material_symbols_shared_${shared_symbol_2x_size}" # UiDensity "-DTT_LVGL_UI_DENSITY=${ui_density_variable}" ) diff --git a/Modules/lvgl-module/README.md b/Modules/lvgl-module/README.md index 2db25aacb..aa74b87bb 100644 --- a/Modules/lvgl-module/README.md +++ b/Modules/lvgl-module/README.md @@ -35,7 +35,9 @@ Font sizes and symbols are configurable: - **On ESP32 (IDF)**: Sizes can be updated via `menuconfig` or by editing `sdkconfig`. Look for `CONFIG_TT_LVGL_FONT_SIZE_*` and `CONFIG_TT_LVGL_*_ICON_SIZE` parameters. - **On Simulator/POSIX**: Default sizes are defined in `Modules/lvgl-module/CMakeLists.txt`. -If you change an icon font size, ensure that a corresponding C file exists in `source-fonts/` (e.g., `material_symbols_shared_24.c`). These files are generated from TTF/OTF fonts using the LVGL font converter. +Icon fonts are rasterized on device at startup from `Data/system/fonts/MaterialSymbolsRounded.ttf` (a subset with only the used icons) and cached as `.bin` files in the data path, so any icon size works. +The icons per font are listed by name and resolved through `Data/system/fonts/MaterialSymbolsRounded.codepoints`. +To add an icon, add its name to `generate-icons.py` and run it (requires `pip install fonttools`). This regenerates the TTF subset, the codepoints file and the name lists. ## Custom memory allocator diff --git a/Modules/lvgl-module/generate-icons.py b/Modules/lvgl-module/generate-icons.py index 5123923ea..4d794fc4e 100755 --- a/Modules/lvgl-module/generate-icons.py +++ b/Modules/lvgl-module/generate-icons.py @@ -1,6 +1,22 @@ #!/usr/bin/env python3 +""" +Generates the Material Symbols icon resources: +- include/lvgl/icons/*.h: UTF-8 string defines per icon +- include/lvgl/icons/names.h and source/icon_names.c: icon name lists per icon font +- Data/system/fonts/MaterialSymbolsRounded.ttf: TTF subset with only the used icons +- Data/system/fonts/MaterialSymbolsRounded.codepoints: name to codepoint map of the used icons + +The icon fonts are rasterized from the TTF subset on device at startup. + +Requires the fonttools package: pip install fonttools +""" import os import urllib.request +import zlib + +from fontTools import subset +from fontTools.ttLib import TTFont +from fontTools.varLib import instancer def download_file(url: str, filename: str): if not os.path.exists(filename): @@ -9,15 +25,6 @@ def download_file(url: str, filename: str): else: print(f"{filename} already exists, skipping download.") -def generate(bpp, size, font_file: str, symbols: list, output: str): - output_file_name = f"{output}_{size}.c" - output_path = os.path.join("source-fonts", output_file_name) - print(f"Generating {output_file_name}") - cmd = "lv_font_conv --no-compress --no-prefilter --bpp {} --size {} --font {} -r {} --format lvgl -o {} --force-fast-kern-format".format(bpp, size, font_file, ",".join(symbols), output_path) - ret = os.system(cmd) - if ret != 0: - raise RuntimeError(f"Font generation failed for {output_file_name} (exit code {ret})") - def read_code_points_map(file_path: str): codepoints = {} with open(file_path, 'r') as f: @@ -40,9 +47,62 @@ def get_code_points(codepoints, names: list) -> list: result.append(f"0x{codepoints[safe_name].upper()}") return result -def generate_icon_fonts(font_file, font_sizes, symbols, output): - for size in font_sizes: - generate(2, size, font_file, symbols, output) +def generate_subset_ttf(font_file: str, codepoints: list, output_path: str) -> bytes: + print(f"Generating {output_path}") + font = TTFont(font_file, recalcTimestamp=False) + if "fvar" in font: + # Pin all axes to their defaults, which are the outlines lv_font_conv used to render + font = instancer.instantiateVariableFont(font, {axis.axisTag: None for axis in font["fvar"].axes}) + options = subset.Options() + options.layout_features = [] + options.drop_tables += ["GSUB", "GPOS", "GDEF"] + options.hinting = False + options.notdef_outline = True + subsetter = subset.Subsetter(options) + subsetter.populate(unicodes=codepoints) + subsetter.subset(font) + os.makedirs(os.path.dirname(output_path), exist_ok=True) + font.save(output_path) + with open(output_path, "rb") as f: + return f.read() + +def generate_codepoints_file(codepoint_map: dict, names: list, output_path: str) -> bytes: + print(f"Generating {output_path}") + content = "".join(f"{name} {codepoint_map[name]}\n" for name in names) + with open(output_path, "w") as f: + f.write(content) + return content.encode("utf-8") + +def generate_icon_name_lists(icon_sets: list, version_input: bytes): + version = zlib.crc32(version_input + repr(icon_sets).encode("utf-8")) & 0xFFFFFFFF + + header_path = os.path.join("include", "lvgl", "icons", "names.h") + print(f"Generating {header_path}") + with open(header_path, "w") as f: + f.write("// SPDX-License-Identifier: Apache-2.0\n\n") + f.write("#pragma once\n\n") + f.write("#include \n\n") + f.write("#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n") + f.write("/** Changes whenever the icon TTF subset, its codepoints file or the icon name lists change */\n") + f.write(f"#define LVGL_ICON_FONT_VERSION 0x{version:08X}u\n\n") + f.write("// Icon names per icon font, resolved through the .codepoints file next to the TTF\n") + for name, _ in icon_sets: + f.write(f"extern const char* const lvgl_icon_{name}_names[];\n") + f.write(f"extern const size_t lvgl_icon_{name}_name_count;\n\n") + f.write("#ifdef __cplusplus\n}\n#endif\n") + + source_path = os.path.join("source", "icon_names.c") + print(f"Generating {source_path}") + with open(source_path, "w") as f: + f.write("// SPDX-License-Identifier: Apache-2.0\n") + f.write("// Generated by generate-icons.py\n\n") + f.write("#include \n\n") + for name, names in icon_sets: + f.write(f"const char* const lvgl_icon_{name}_names[] = {{\n") + for icon_name in names: + f.write(f" \"{icon_name.lower()}\",\n") + f.write("};\n\n") + f.write(f"const size_t lvgl_icon_{name}_name_count = sizeof(lvgl_icon_{name}_names) / sizeof(lvgl_icon_{name}_names[0]);\n\n") def generate_icon_names(codepoint_map: dict, codepoint_names: list, variable_name: str): filename = f"{variable_name}.h" @@ -161,33 +221,6 @@ def generate_icon_names(codepoint_map: dict, codepoint_names: list, variable_nam "settings" ] -shared_symbol_sizes = [ - 12, - 16, # T-Deck reference, with montserrat 14 in lv_list as icon with text - 20, - 24, - 32, - 40, - 48, - 64 -] - -statusbar_symbol_sizes = [ - 12, - 16, # T-Deck reference - 20, - 30 -] - -launcher_symbol_sizes = [ - 30, - 36, # T-Deck reference - 42, - 48, - 64, - 72 -] - # Resolve file path relative to this script so it can be executed from any CWD base_dir = os.path.dirname(__file__) if base_dir: @@ -198,6 +231,8 @@ def generate_icon_names(codepoint_map: dict, codepoint_names: list, variable_nam codepoints_filename = "MaterialSymbolsRounded.codepoints" ttf_filename = "MaterialSymbolsRounded.ttf" +subset_ttf_path = os.path.join("..", "..", "Data", "system", "fonts", "MaterialSymbolsRounded.ttf") +subset_codepoints_path = os.path.join("..", "..", "Data", "system", "fonts", "MaterialSymbolsRounded.codepoints") download_file(codepoints_url, codepoints_filename) download_file(ttf_url, ttf_filename) @@ -205,18 +240,17 @@ def generate_icon_names(codepoint_map: dict, codepoint_names: list, variable_nam codepoints_map_path = codepoints_filename codepoints_map = read_code_points_map(codepoints_map_path) -# Shared symbols -shared_symbol_code_points = get_code_points(codepoints_map, shared_symbol_code_point_names) -generate_icon_fonts(ttf_filename, shared_symbol_sizes, shared_symbol_code_points, "material_symbols_shared") -generate_icon_names(codepoints_map, shared_symbol_code_point_names, "shared") - -# Statusbar symbols -statusbar_symbol_code_points = get_code_points(codepoints_map, statusbar_symbol_code_point_names) -generate_icon_fonts(ttf_filename, statusbar_symbol_sizes, statusbar_symbol_code_points, "material_symbols_statusbar") -generate_icon_names(codepoints_map, statusbar_symbol_code_point_names, "statusbar") +icon_sets = [ + ("shared", shared_symbol_code_point_names), + ("statusbar", statusbar_symbol_code_point_names), + ("launcher", launcher_symbol_code_point_names), +] -# Launcher symbols -launcher_symbol_code_points = get_code_points(codepoints_map, launcher_symbol_code_point_names) -generate_icon_fonts(ttf_filename, launcher_symbol_sizes, launcher_symbol_code_points, "material_symbols_launcher") -generate_icon_names(codepoints_map, launcher_symbol_code_point_names, "launcher") +for variable_name, names in icon_sets: + generate_icon_names(codepoints_map, names, variable_name) +all_names = sorted({name.lower() for _, names in icon_sets for name in names}) +all_codepoints = [int(cp, 16) for cp in get_code_points(codepoints_map, all_names)] +subset_data = generate_subset_ttf(ttf_filename, all_codepoints, subset_ttf_path) +codepoints_data = generate_codepoints_file(codepoints_map, all_names, subset_codepoints_path) +generate_icon_name_lists(icon_sets, subset_data + codepoints_data) diff --git a/Modules/lvgl-module/include/lvgl/binfont.h b/Modules/lvgl-module/include/lvgl/binfont.h new file mode 100644 index 000000000..565fbefbd --- /dev/null +++ b/Modules/lvgl-module/include/lvgl/binfont.h @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct BinFont; + +/** + * @brief Creates an LVGL font that renders glyphs from a BinFont. + * @param[in] font the source font, which must outlive the returned font + * @return the LVGL font, or NULL when memory allocation failed + */ +lv_font_t* lvgl_binfont_create(struct BinFont* font); + +/** Destroys a font from lvgl_binfont_create(). The BinFont is not closed. */ +void lvgl_binfont_destroy(lv_font_t* font); + +#ifdef __cplusplus +} +#endif diff --git a/Modules/lvgl-module/include/lvgl/fonts.h b/Modules/lvgl-module/include/lvgl/fonts.h index c4cf25d9e..3efc17651 100644 --- a/Modules/lvgl-module/include/lvgl/fonts.h +++ b/Modules/lvgl-module/include/lvgl/fonts.h @@ -14,6 +14,19 @@ enum LvglFontSize { FONT_SIZE_LARGE, }; +enum LvglIconFont { + LVGL_ICON_FONT_STATUSBAR, + LVGL_ICON_FONT_LAUNCHER, + LVGL_ICON_FONT_SHARED, + LVGL_ICON_FONT_SHARED_2X, +}; + +/** + * @brief Sets the font that is returned by the getter of an icon font. + * Until an icon font is set, its getter returns the default text font. + */ +void lvgl_set_icon_font(enum LvglIconFont icon_font, const lv_font_t* font); + const lv_font_t* lvgl_get_shared_icon_font(void); uint32_t lvgl_get_shared_icon_font_height(void); diff --git a/Modules/lvgl-module/include/lvgl/icons/names.h b/Modules/lvgl-module/include/lvgl/icons/names.h new file mode 100644 index 000000000..59b8a0001 --- /dev/null +++ b/Modules/lvgl-module/include/lvgl/icons/names.h @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Changes whenever the icon TTF subset, its codepoints file or the icon name lists change */ +#define LVGL_ICON_FONT_VERSION 0x977A6A66u + +// Icon names per icon font, resolved through the .codepoints file next to the TTF +extern const char* const lvgl_icon_shared_names[]; +extern const size_t lvgl_icon_shared_name_count; + +extern const char* const lvgl_icon_statusbar_names[]; +extern const size_t lvgl_icon_statusbar_name_count; + +extern const char* const lvgl_icon_launcher_names[]; +extern const size_t lvgl_icon_launcher_name_count; + +#ifdef __cplusplus +} +#endif diff --git a/Modules/lvgl-module/source-fonts/material_symbols_launcher_30.c b/Modules/lvgl-module/source-fonts/material_symbols_launcher_30.c deleted file mode 100644 index 4e371498c..000000000 --- a/Modules/lvgl-module/source-fonts/material_symbols_launcher_30.c +++ /dev/null @@ -1,176 +0,0 @@ -/******************************************************************************* - * Size: 30 px - * Bpp: 2 - * Opts: --no-compress --no-prefilter --bpp 2 --size 30 --font MaterialSymbolsRounded.ttf -r 0xE5C3,0xE2C7,0xE8B8 --format lvgl -o source-fonts/material_symbols_launcher_30.c --force-fast-kern-format - ******************************************************************************/ - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -#ifndef MATERIAL_SYMBOLS_LAUNCHER_30 -#define MATERIAL_SYMBOLS_LAUNCHER_30 1 -#endif - -#if MATERIAL_SYMBOLS_LAUNCHER_30 - -/*----------------- - * BITMAPS - *----------------*/ - -/*Store the image of the glyphs*/ -static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { - /* U+E2C7 "" */ - 0x1f, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x3, 0xff, - 0xff, 0xf0, 0x0, 0x0, 0x0, 0x7e, 0xaa, 0xaf, - 0xea, 0xaa, 0xa9, 0xb, 0xc0, 0x0, 0xbf, 0xff, - 0xff, 0xfc, 0xbc, 0x0, 0x2, 0xff, 0xff, 0xff, - 0xdb, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0xbc, - 0x0, 0x0, 0x0, 0x0, 0x3, 0xeb, 0xc0, 0x0, - 0x0, 0x0, 0x0, 0x3e, 0xbc, 0x0, 0x0, 0x0, - 0x0, 0x3, 0xeb, 0xc0, 0x0, 0x0, 0x0, 0x0, - 0x3e, 0xbc, 0x0, 0x0, 0x0, 0x0, 0x3, 0xeb, - 0xc0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0xbc, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xeb, 0xc0, 0x0, 0x0, - 0x0, 0x0, 0x3e, 0xbc, 0x0, 0x0, 0x0, 0x0, - 0x3, 0xeb, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x3e, - 0xbc, 0x0, 0x0, 0x0, 0x0, 0x3, 0xe7, 0xea, - 0xaa, 0xaa, 0xaa, 0xaa, 0xbd, 0x3f, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xc1, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xf4, - - /* U+E5C3 "" */ - 0x2e, 0x0, 0xbd, 0x1, 0xf4, 0xbf, 0x81, 0xff, - 0x3, 0xfd, 0xff, 0xc2, 0xff, 0x7, 0xfe, 0xbf, - 0x81, 0xff, 0x3, 0xfd, 0x2e, 0x0, 0xbd, 0x1, - 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x7f, 0x40, 0xfe, 0x2, 0xf8, 0xff, 0xc2, 0xff, - 0x7, 0xfd, 0xff, 0xc2, 0xff, 0x7, 0xfd, 0xbf, - 0x81, 0xff, 0x3, 0xfc, 0x19, 0x0, 0x68, 0x0, - 0xa0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2e, 0x0, 0xbd, 0x1, 0xf4, - 0xbf, 0x81, 0xff, 0x3, 0xfd, 0xff, 0xc2, 0xff, - 0x7, 0xfe, 0xbf, 0x81, 0xff, 0x3, 0xfd, 0x2e, - 0x0, 0xbd, 0x1, 0xf4, - - /* U+E8B8 "" */ - 0x0, 0x0, 0x1, 0xa4, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xff, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x2f, - 0xff, 0x80, 0x0, 0x0, 0x0, 0x3, 0xe0, 0xbc, - 0x0, 0x0, 0x0, 0x90, 0x3e, 0xb, 0xc0, 0x60, - 0x0, 0x3f, 0xff, 0xd0, 0x7f, 0xff, 0xc0, 0xb, - 0xff, 0xf8, 0x2, 0xff, 0xfe, 0x1, 0xf8, 0xbc, - 0x0, 0x3, 0xe2, 0xf4, 0x3f, 0x0, 0x0, 0x50, - 0x0, 0xf, 0xc3, 0xf4, 0x0, 0xbf, 0xe0, 0x1, - 0xfc, 0x1f, 0xe0, 0x2f, 0xff, 0x80, 0xbf, 0x40, - 0x7f, 0x43, 0xff, 0xfc, 0x1f, 0xd0, 0x1, 0xf0, - 0x7f, 0xff, 0xd0, 0xf4, 0x0, 0x1f, 0x7, 0xff, - 0xfd, 0xf, 0x40, 0x7, 0xf4, 0x3f, 0xff, 0xc1, - 0xfd, 0x1, 0xfe, 0x2, 0xff, 0xf8, 0xb, 0xf4, - 0x3f, 0x40, 0xb, 0xfe, 0x0, 0x1f, 0xc3, 0xf0, - 0x0, 0x5, 0x0, 0x0, 0xf8, 0x1f, 0x8b, 0xc0, - 0x0, 0x3e, 0x2f, 0x40, 0xbf, 0xff, 0x80, 0x2f, - 0xff, 0xe0, 0x3, 0xff, 0xfd, 0x7, 0xff, 0xfc, - 0x0, 0x9, 0x3, 0xe0, 0xbc, 0xa, 0x0, 0x0, - 0x0, 0x3e, 0xb, 0xc0, 0x0, 0x0, 0x0, 0x2, - 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, - 0x40, 0x0, 0x0, 0x0, 0x0, 0x1a, 0x40, 0x0, - 0x0 -}; - - -/*--------------------- - * GLYPH DESCRIPTION - *--------------------*/ - -static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { - {.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */, - {.bitmap_index = 0, .adv_w = 480, .box_w = 26, .box_h = 20, .ofs_x = 2, .ofs_y = 5}, - {.bitmap_index = 130, .adv_w = 480, .box_w = 20, .box_h = 20, .ofs_x = 5, .ofs_y = 5}, - {.bitmap_index = 230, .adv_w = 480, .box_w = 26, .box_h = 26, .ofs_x = 2, .ofs_y = 2} -}; - -/*--------------------- - * CHARACTER MAPPING - *--------------------*/ - -static const uint16_t unicode_list_0[] = { - 0x0, 0x2fc, 0x5f1 -}; - -/*Collect the unicode lists and glyph_id offsets*/ -static const lv_font_fmt_txt_cmap_t cmaps[] = -{ - { - .range_start = 58055, .range_length = 1522, .glyph_id_start = 1, - .unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 3, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY - } -}; - - - -/*-------------------- - * ALL CUSTOM DATA - *--------------------*/ - -#if LVGL_VERSION_MAJOR == 8 -/*Store all the custom data of the font*/ -static lv_font_fmt_txt_glyph_cache_t cache; -#endif - -#if LVGL_VERSION_MAJOR >= 8 -static const lv_font_fmt_txt_dsc_t font_dsc = { -#else -static lv_font_fmt_txt_dsc_t font_dsc = { -#endif - .glyph_bitmap = glyph_bitmap, - .glyph_dsc = glyph_dsc, - .cmaps = cmaps, - .kern_dsc = NULL, - .kern_scale = 0, - .cmap_num = 1, - .bpp = 2, - .kern_classes = 0, - .bitmap_format = 0, -#if LVGL_VERSION_MAJOR == 8 - .cache = &cache -#endif -}; - - - -/*----------------- - * PUBLIC FONT - *----------------*/ - -/*Initialize a public general font descriptor*/ -#if LVGL_VERSION_MAJOR >= 8 -const lv_font_t material_symbols_launcher_30 = { -#else -lv_font_t material_symbols_launcher_30 = { -#endif - .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ - .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ - .line_height = 26, /*The maximum line height required by the font*/ - .base_line = -2, /*Baseline measured from the bottom of the line*/ -#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) - .subpx = LV_FONT_SUBPX_NONE, -#endif -#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 - .underline_position = 0, - .underline_thickness = 0, -#endif - .dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ -#if LV_VERSION_CHECK(8, 2, 0) || LVGL_VERSION_MAJOR >= 9 - .fallback = NULL, -#endif - .user_data = NULL, -}; - - - -#endif /*#if MATERIAL_SYMBOLS_LAUNCHER_30*/ - diff --git a/Modules/lvgl-module/source-fonts/material_symbols_launcher_36.c b/Modules/lvgl-module/source-fonts/material_symbols_launcher_36.c deleted file mode 100644 index 9d44dacda..000000000 --- a/Modules/lvgl-module/source-fonts/material_symbols_launcher_36.c +++ /dev/null @@ -1,194 +0,0 @@ -/******************************************************************************* - * Size: 36 px - * Bpp: 2 - * Opts: --no-compress --no-prefilter --bpp 2 --size 36 --font MaterialSymbolsRounded.ttf -r 0xE5C3,0xE2C7,0xE8B8 --format lvgl -o source-fonts/material_symbols_launcher_36.c --force-fast-kern-format - ******************************************************************************/ - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -#ifndef MATERIAL_SYMBOLS_LAUNCHER_36 -#define MATERIAL_SYMBOLS_LAUNCHER_36 1 -#endif - -#if MATERIAL_SYMBOLS_LAUNCHER_36 - -/*----------------- - * BITMAPS - *----------------*/ - -/*Store the image of the glyphs*/ -static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { - /* U+E2C7 "" */ - 0x2f, 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, 0xb, - 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0xff, 0xf8, 0x0, 0x0, 0x0, 0xf, 0xc0, - 0x0, 0x2f, 0xff, 0xff, 0xff, 0xf8, 0xfc, 0x0, - 0x0, 0xbf, 0xff, 0xff, 0xff, 0xef, 0xc0, 0x0, - 0x2, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xff, 0xc0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3f, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3, 0xff, 0xc0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0xfc, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, - 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, - 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, - 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfc, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xc0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfc, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xe2, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf8, - - /* U+E5C3 "" */ - 0x2f, 0x80, 0xb, 0xe0, 0x2, 0xf8, 0xbf, 0xe0, - 0x2f, 0xf8, 0xb, 0xfe, 0xff, 0xf0, 0x3f, 0xfc, - 0xf, 0xff, 0xff, 0xf0, 0x3f, 0xfc, 0xf, 0xff, - 0xbf, 0xe0, 0x2f, 0xf8, 0xb, 0xfe, 0x2f, 0x80, - 0xb, 0xe0, 0x2, 0xf8, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0x80, - 0xb, 0xe0, 0x2, 0xf8, 0xbf, 0xe0, 0x2f, 0xf8, - 0xb, 0xfe, 0xff, 0xf0, 0x3f, 0xfc, 0xf, 0xff, - 0xff, 0xf0, 0x3f, 0xfc, 0xf, 0xff, 0xbf, 0xe0, - 0x2f, 0xf8, 0xb, 0xfe, 0x2f, 0x80, 0xb, 0xe0, - 0x2, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x2f, 0x80, 0xb, 0xe0, - 0x2, 0xf8, 0xbf, 0xe0, 0x2f, 0xf8, 0xb, 0xfe, - 0xff, 0xf0, 0x3f, 0xfc, 0xf, 0xff, 0xff, 0xf0, - 0x3f, 0xfc, 0xf, 0xff, 0xbf, 0xe0, 0x2f, 0xf8, - 0xb, 0xfe, 0x2f, 0x80, 0xb, 0xe0, 0x2, 0xf8, - - /* U+E8B8 "" */ - 0x0, 0x0, 0x1, 0xff, 0xf4, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0xff, 0xc0, 0x0, 0x0, 0x0, - 0x0, 0x7, 0xff, 0xfd, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xbd, 0x7, 0xe0, 0x0, 0x0, 0x0, 0x10, - 0xb, 0xd0, 0x7e, 0x0, 0x40, 0x0, 0x2f, 0xe7, - 0xfc, 0x3, 0xfd, 0xbf, 0x80, 0x7, 0xff, 0xff, - 0xc0, 0x3f, 0xff, 0xfd, 0x0, 0xff, 0xff, 0xe0, - 0x0, 0xbf, 0xff, 0xf0, 0x2f, 0xc2, 0xf0, 0x0, - 0x0, 0xf8, 0x3f, 0x83, 0xf4, 0x0, 0x0, 0x0, - 0x0, 0x1, 0xfc, 0x3f, 0x40, 0x0, 0xbf, 0xe0, - 0x0, 0xf, 0xc3, 0xfe, 0x0, 0x3f, 0xff, 0xc0, - 0x7, 0xfc, 0xf, 0xfc, 0xb, 0xff, 0xfe, 0x2, - 0xff, 0x0, 0x2f, 0xc0, 0xff, 0xff, 0xf0, 0x3f, - 0xc0, 0x0, 0xfc, 0xf, 0xff, 0xff, 0x43, 0xf4, - 0x0, 0xf, 0xc0, 0xff, 0xff, 0xf4, 0x3f, 0x0, - 0x2, 0xfc, 0xf, 0xff, 0xff, 0x3, 0xf8, 0x0, - 0xff, 0x80, 0xbf, 0xff, 0xe0, 0x2f, 0xf0, 0x3f, - 0xd0, 0x3, 0xff, 0xfc, 0x0, 0x7f, 0xc3, 0xf4, - 0x0, 0xb, 0xfe, 0x0, 0x0, 0xfc, 0x3f, 0x40, - 0x0, 0x0, 0x0, 0x0, 0x1f, 0xc2, 0xfc, 0x2f, - 0x0, 0x0, 0xf, 0x83, 0xf8, 0xf, 0xff, 0xfe, - 0x0, 0xb, 0xff, 0xff, 0x0, 0x7f, 0xff, 0xfc, - 0x3, 0xff, 0xff, 0xd0, 0x2, 0xfe, 0x7f, 0xc0, - 0x3f, 0xdb, 0xf8, 0x0, 0x5, 0x0, 0xbd, 0x7, - 0xe0, 0x4, 0x0, 0x0, 0x0, 0xb, 0xd0, 0x7e, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0xd0, - 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xfc, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, 0x40, 0x0, - 0x0 -}; - - -/*--------------------- - * GLYPH DESCRIPTION - *--------------------*/ - -static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { - {.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */, - {.bitmap_index = 0, .adv_w = 576, .box_w = 30, .box_h = 24, .ofs_x = 3, .ofs_y = 6}, - {.bitmap_index = 180, .adv_w = 576, .box_w = 24, .box_h = 24, .ofs_x = 6, .ofs_y = 6}, - {.bitmap_index = 324, .adv_w = 576, .box_w = 30, .box_h = 30, .ofs_x = 3, .ofs_y = 3} -}; - -/*--------------------- - * CHARACTER MAPPING - *--------------------*/ - -static const uint16_t unicode_list_0[] = { - 0x0, 0x2fc, 0x5f1 -}; - -/*Collect the unicode lists and glyph_id offsets*/ -static const lv_font_fmt_txt_cmap_t cmaps[] = -{ - { - .range_start = 58055, .range_length = 1522, .glyph_id_start = 1, - .unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 3, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY - } -}; - - - -/*-------------------- - * ALL CUSTOM DATA - *--------------------*/ - -#if LVGL_VERSION_MAJOR == 8 -/*Store all the custom data of the font*/ -static lv_font_fmt_txt_glyph_cache_t cache; -#endif - -#if LVGL_VERSION_MAJOR >= 8 -static const lv_font_fmt_txt_dsc_t font_dsc = { -#else -static lv_font_fmt_txt_dsc_t font_dsc = { -#endif - .glyph_bitmap = glyph_bitmap, - .glyph_dsc = glyph_dsc, - .cmaps = cmaps, - .kern_dsc = NULL, - .kern_scale = 0, - .cmap_num = 1, - .bpp = 2, - .kern_classes = 0, - .bitmap_format = 0, -#if LVGL_VERSION_MAJOR == 8 - .cache = &cache -#endif -}; - - - -/*----------------- - * PUBLIC FONT - *----------------*/ - -/*Initialize a public general font descriptor*/ -#if LVGL_VERSION_MAJOR >= 8 -const lv_font_t material_symbols_launcher_36 = { -#else -lv_font_t material_symbols_launcher_36 = { -#endif - .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ - .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ - .line_height = 30, /*The maximum line height required by the font*/ - .base_line = -3, /*Baseline measured from the bottom of the line*/ -#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) - .subpx = LV_FONT_SUBPX_NONE, -#endif -#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 - .underline_position = 0, - .underline_thickness = 0, -#endif - .dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ -#if LV_VERSION_CHECK(8, 2, 0) || LVGL_VERSION_MAJOR >= 9 - .fallback = NULL, -#endif - .user_data = NULL, -}; - - - -#endif /*#if MATERIAL_SYMBOLS_LAUNCHER_36*/ - diff --git a/Modules/lvgl-module/source-fonts/material_symbols_launcher_42.c b/Modules/lvgl-module/source-fonts/material_symbols_launcher_42.c deleted file mode 100644 index ce16f18b9..000000000 --- a/Modules/lvgl-module/source-fonts/material_symbols_launcher_42.c +++ /dev/null @@ -1,220 +0,0 @@ -/******************************************************************************* - * Size: 42 px - * Bpp: 2 - * Opts: --no-compress --no-prefilter --bpp 2 --size 42 --font MaterialSymbolsRounded.ttf -r 0xE5C3,0xE2C7,0xE8B8 --format lvgl -o source-fonts/material_symbols_launcher_42.c --force-fast-kern-format - ******************************************************************************/ - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -#ifndef MATERIAL_SYMBOLS_LAUNCHER_42 -#define MATERIAL_SYMBOLS_LAUNCHER_42 1 -#endif - -#if MATERIAL_SYMBOLS_LAUNCHER_42 - -/*----------------- - * BITMAPS - *----------------*/ - -/*Store the image of the glyphs*/ -static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { - /* U+E2C7 "" */ - 0xb, 0xff, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7f, 0xff, 0xff, 0xff, 0xc0, 0x0, - 0x0, 0x0, 0x0, 0x7f, 0xaa, 0xaa, 0xbf, 0xfa, - 0xaa, 0xaa, 0xaa, 0x40, 0xbf, 0x0, 0x0, 0xf, - 0xff, 0xff, 0xff, 0xff, 0xf4, 0xbf, 0x0, 0x0, - 0x3, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xbf, 0x0, - 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xbf, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, - 0xbf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xfe, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xfe, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xfe, 0xbf, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xfe, 0xbf, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xfe, 0xbf, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, 0xbf, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, 0xbf, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, - 0xbf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xfe, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xfe, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xfe, 0xbf, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xfe, 0xbf, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xfe, 0xbf, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, 0xbf, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, 0xbf, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, - 0x7f, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xfd, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfd, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfc, 0xb, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xe0, - - /* U+E5C3 "" */ - 0x1f, 0xd0, 0x0, 0xbe, 0x0, 0xb, 0xe0, 0x7f, - 0xf4, 0x3, 0xff, 0x80, 0x3f, 0xfc, 0xff, 0xfc, - 0xb, 0xff, 0xc0, 0x7f, 0xfd, 0xff, 0xfc, 0xb, - 0xff, 0xd0, 0x7f, 0xfe, 0xff, 0xfc, 0xb, 0xff, - 0xc0, 0x7f, 0xfd, 0x7f, 0xf4, 0x3, 0xff, 0x80, - 0x3f, 0xfc, 0x1f, 0xd0, 0x0, 0xbe, 0x0, 0xb, - 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xe0, 0x1, - 0xff, 0x0, 0xf, 0xf4, 0xbf, 0xf8, 0x3, 0xff, - 0xc0, 0x3f, 0xfc, 0xff, 0xfc, 0xb, 0xff, 0xc0, - 0x7f, 0xfd, 0xff, 0xfc, 0xb, 0xff, 0xc0, 0x7f, - 0xfe, 0xbf, 0xf8, 0x7, 0xff, 0xc0, 0x3f, 0xfd, - 0x3f, 0xf0, 0x3, 0xff, 0x40, 0x2f, 0xf8, 0xa, - 0x80, 0x0, 0x68, 0x0, 0x6, 0x90, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x1f, 0xd0, 0x0, 0xbe, 0x0, - 0xb, 0xe0, 0x7f, 0xf4, 0x3, 0xff, 0x80, 0x3f, - 0xfc, 0xff, 0xfc, 0xb, 0xff, 0xc0, 0x7f, 0xfd, - 0xff, 0xfc, 0xb, 0xff, 0xd0, 0x7f, 0xfe, 0xff, - 0xfc, 0xb, 0xff, 0xc0, 0x7f, 0xfd, 0x7f, 0xf4, - 0x3, 0xff, 0x80, 0x3f, 0xfc, 0x1f, 0xd0, 0x0, - 0xbe, 0x0, 0xb, 0xe0, - - /* U+E8B8 "" */ - 0x0, 0x0, 0x0, 0x6, 0xa9, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7, 0xff, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x1, 0xfc, 0x3, 0xf4, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xc0, 0x3f, - 0x40, 0x0, 0x0, 0x1, 0xfe, 0x7, 0xfc, 0x3, - 0xfd, 0xb, 0xf4, 0x0, 0x3f, 0xff, 0xff, 0xc0, - 0x3f, 0xff, 0xff, 0xc0, 0xf, 0xff, 0xff, 0xf8, - 0x2, 0xff, 0xff, 0xff, 0x1, 0xff, 0xff, 0xf8, - 0x0, 0x2, 0xff, 0xff, 0xf4, 0x3f, 0xc1, 0xbc, - 0x0, 0x0, 0x3, 0xe4, 0x3f, 0xc7, 0xf8, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x2, 0xfd, 0xbf, 0x0, - 0x0, 0xb, 0xfe, 0x0, 0x0, 0x1f, 0xe7, 0xfd, - 0x0, 0x3, 0xff, 0xfd, 0x0, 0x7, 0xfd, 0x3f, - 0xf8, 0x0, 0xff, 0xff, 0xf0, 0x2, 0xff, 0xc0, - 0xbf, 0xe0, 0x1f, 0xff, 0xff, 0x80, 0xbf, 0xe0, - 0x2, 0xfd, 0x3, 0xff, 0xff, 0xfc, 0xb, 0xf8, - 0x0, 0xf, 0xd0, 0x3f, 0xff, 0xff, 0xc0, 0x7f, - 0x0, 0x0, 0xfd, 0x3, 0xff, 0xff, 0xfc, 0x7, - 0xf0, 0x0, 0x2f, 0xd0, 0x3f, 0xff, 0xff, 0xc0, - 0xbf, 0x40, 0xb, 0xfe, 0x1, 0xff, 0xff, 0xf8, - 0xb, 0xfe, 0x3, 0xff, 0x80, 0xf, 0xff, 0xff, - 0x0, 0x2f, 0xfc, 0x7f, 0xd0, 0x0, 0x3f, 0xff, - 0xd0, 0x0, 0x7f, 0xdb, 0xf0, 0x0, 0x0, 0xbf, - 0xe0, 0x0, 0x1, 0xfe, 0x7f, 0x80, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xd3, 0xfc, 0x1b, 0xc0, - 0x0, 0x0, 0x3e, 0x43, 0xfc, 0x1f, 0xff, 0xff, - 0x40, 0x0, 0x1f, 0xff, 0xff, 0x40, 0xff, 0xff, - 0xff, 0x80, 0x2f, 0xff, 0xff, 0xe0, 0x3, 0xff, - 0xff, 0xfc, 0x3, 0xff, 0xff, 0xfc, 0x0, 0x1f, - 0xe0, 0x7f, 0xc0, 0x3f, 0xd0, 0xbf, 0x0, 0x0, - 0x0, 0x1, 0xfc, 0x3, 0xf4, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x1f, 0xc0, 0x3f, 0x40, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x6a, 0x90, 0x0, - 0x0, 0x0 -}; - - -/*--------------------- - * GLYPH DESCRIPTION - *--------------------*/ - -static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { - {.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */, - {.bitmap_index = 0, .adv_w = 672, .box_w = 36, .box_h = 28, .ofs_x = 3, .ofs_y = 7}, - {.bitmap_index = 252, .adv_w = 672, .box_w = 28, .box_h = 28, .ofs_x = 7, .ofs_y = 7}, - {.bitmap_index = 448, .adv_w = 672, .box_w = 34, .box_h = 36, .ofs_x = 4, .ofs_y = 3} -}; - -/*--------------------- - * CHARACTER MAPPING - *--------------------*/ - -static const uint16_t unicode_list_0[] = { - 0x0, 0x2fc, 0x5f1 -}; - -/*Collect the unicode lists and glyph_id offsets*/ -static const lv_font_fmt_txt_cmap_t cmaps[] = -{ - { - .range_start = 58055, .range_length = 1522, .glyph_id_start = 1, - .unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 3, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY - } -}; - - - -/*-------------------- - * ALL CUSTOM DATA - *--------------------*/ - -#if LVGL_VERSION_MAJOR == 8 -/*Store all the custom data of the font*/ -static lv_font_fmt_txt_glyph_cache_t cache; -#endif - -#if LVGL_VERSION_MAJOR >= 8 -static const lv_font_fmt_txt_dsc_t font_dsc = { -#else -static lv_font_fmt_txt_dsc_t font_dsc = { -#endif - .glyph_bitmap = glyph_bitmap, - .glyph_dsc = glyph_dsc, - .cmaps = cmaps, - .kern_dsc = NULL, - .kern_scale = 0, - .cmap_num = 1, - .bpp = 2, - .kern_classes = 0, - .bitmap_format = 0, -#if LVGL_VERSION_MAJOR == 8 - .cache = &cache -#endif -}; - - - -/*----------------- - * PUBLIC FONT - *----------------*/ - -/*Initialize a public general font descriptor*/ -#if LVGL_VERSION_MAJOR >= 8 -const lv_font_t material_symbols_launcher_42 = { -#else -lv_font_t material_symbols_launcher_42 = { -#endif - .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ - .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ - .line_height = 36, /*The maximum line height required by the font*/ - .base_line = -3, /*Baseline measured from the bottom of the line*/ -#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) - .subpx = LV_FONT_SUBPX_NONE, -#endif -#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 - .underline_position = 0, - .underline_thickness = 0, -#endif - .dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ -#if LV_VERSION_CHECK(8, 2, 0) || LVGL_VERSION_MAJOR >= 9 - .fallback = NULL, -#endif - .user_data = NULL, -}; - - - -#endif /*#if MATERIAL_SYMBOLS_LAUNCHER_42*/ - diff --git a/Modules/lvgl-module/source-fonts/material_symbols_launcher_48.c b/Modules/lvgl-module/source-fonts/material_symbols_launcher_48.c deleted file mode 100644 index bfdc63c76..000000000 --- a/Modules/lvgl-module/source-fonts/material_symbols_launcher_48.c +++ /dev/null @@ -1,246 +0,0 @@ -/******************************************************************************* - * Size: 48 px - * Bpp: 2 - * Opts: --no-compress --no-prefilter --bpp 2 --size 48 --font MaterialSymbolsRounded.ttf -r 0xE5C3,0xE2C7,0xE8B8 --format lvgl -o source-fonts/material_symbols_launcher_48.c --force-fast-kern-format - ******************************************************************************/ - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -#ifndef MATERIAL_SYMBOLS_LAUNCHER_48 -#define MATERIAL_SYMBOLS_LAUNCHER_48 1 -#endif - -#if MATERIAL_SYMBOLS_LAUNCHER_48 - -/*----------------- - * BITMAPS - *----------------*/ - -/*Store the image of the glyphs*/ -static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { - /* U+E2C7 "" */ - 0xb, 0xff, 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0xff, 0xff, 0xff, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xbf, 0xff, 0xff, 0xff, - 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, - 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0x0, 0x0, 0x3, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xe0, 0xff, 0x0, 0x0, 0x0, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfc, 0xff, 0x0, 0x0, 0x0, - 0x3f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x0, - 0x0, 0x0, 0xf, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xb, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, - - /* U+E5C3 "" */ - 0xb, 0xe0, 0x0, 0xb, 0xe0, 0x0, 0xb, 0xe0, - 0x3f, 0xfc, 0x0, 0x3f, 0xfc, 0x0, 0x3f, 0xfc, - 0xbf, 0xfe, 0x0, 0xbf, 0xfe, 0x0, 0xbf, 0xfe, - 0xff, 0xff, 0x0, 0xff, 0xff, 0x0, 0xff, 0xff, - 0xff, 0xff, 0x0, 0xff, 0xff, 0x0, 0xff, 0xff, - 0xbf, 0xfe, 0x0, 0xbf, 0xfe, 0x0, 0xbf, 0xfe, - 0x3f, 0xfc, 0x0, 0x3f, 0xfc, 0x0, 0x3f, 0xfc, - 0xb, 0xe0, 0x0, 0xb, 0xe0, 0x0, 0xb, 0xe0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xb, 0xe0, 0x0, 0xb, 0xe0, 0x0, 0xb, 0xe0, - 0x3f, 0xfc, 0x0, 0x3f, 0xfc, 0x0, 0x3f, 0xfc, - 0xbf, 0xfe, 0x0, 0xbf, 0xfe, 0x0, 0xbf, 0xfe, - 0xff, 0xff, 0x0, 0xff, 0xff, 0x0, 0xff, 0xff, - 0xff, 0xff, 0x0, 0xff, 0xff, 0x0, 0xff, 0xff, - 0xbf, 0xfe, 0x0, 0xbf, 0xfe, 0x0, 0xbf, 0xfe, - 0x3f, 0xfc, 0x0, 0x3f, 0xfc, 0x0, 0x3f, 0xfc, - 0xb, 0xe0, 0x0, 0xb, 0xe0, 0x0, 0xb, 0xe0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xb, 0xe0, 0x0, 0xb, 0xe0, 0x0, 0xb, 0xe0, - 0x3f, 0xfc, 0x0, 0x3f, 0xfc, 0x0, 0x3f, 0xfc, - 0xbf, 0xfe, 0x0, 0xbf, 0xfe, 0x0, 0xbf, 0xfe, - 0xff, 0xff, 0x0, 0xff, 0xff, 0x0, 0xff, 0xff, - 0xff, 0xff, 0x0, 0xff, 0xff, 0x0, 0xff, 0xff, - 0xbf, 0xfe, 0x0, 0xbf, 0xfe, 0x0, 0xbf, 0xfe, - 0x3f, 0xfc, 0x0, 0x3f, 0xfc, 0x0, 0x3f, 0xfc, - 0xb, 0xe0, 0x0, 0xb, 0xe0, 0x0, 0xb, 0xe0, - - /* U+E8B8 "" */ - 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xff, - 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, - 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xf0, 0xf, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf0, 0xf, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x1e, 0x40, 0x2f, - 0xe0, 0xb, 0xf8, 0x1, 0xb4, 0x0, 0x0, 0xff, - 0xf9, 0xff, 0xe0, 0xb, 0xff, 0x6f, 0xff, 0x0, - 0x2, 0xff, 0xff, 0xff, 0xd0, 0x7, 0xff, 0xff, - 0xff, 0x80, 0x3, 0xff, 0xff, 0xff, 0x80, 0x2, - 0xff, 0xff, 0xff, 0xc0, 0xb, 0xfd, 0xff, 0xf4, - 0x0, 0x0, 0x1f, 0xff, 0x7f, 0xe0, 0xf, 0xf4, - 0x1b, 0xc0, 0x0, 0x0, 0x3, 0xe4, 0x1f, 0xf0, - 0x2f, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xf8, 0x3f, 0xd0, 0x0, 0x0, 0x2f, 0xf8, - 0x0, 0x0, 0x7, 0xfc, 0x3f, 0xf4, 0x0, 0x1, - 0xff, 0xff, 0x40, 0x0, 0x1f, 0xfc, 0x2f, 0xfe, - 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0xbf, 0xf8, - 0xb, 0xff, 0xc0, 0xf, 0xff, 0xff, 0xf0, 0x3, - 0xff, 0xe0, 0x1, 0xff, 0xd0, 0x1f, 0xff, 0xff, - 0xf8, 0x7, 0xff, 0x40, 0x0, 0x7f, 0xc0, 0x2f, - 0xff, 0xff, 0xfc, 0x3, 0xfd, 0x0, 0x0, 0x3f, - 0xc0, 0x3f, 0xff, 0xff, 0xfc, 0x3, 0xfc, 0x0, - 0x0, 0x3f, 0xc0, 0x3f, 0xff, 0xff, 0xfc, 0x3, - 0xfc, 0x0, 0x0, 0x7f, 0xc0, 0x2f, 0xff, 0xff, - 0xfc, 0x3, 0xfc, 0x0, 0x1, 0xff, 0xd0, 0x1f, - 0xff, 0xff, 0xf8, 0x7, 0xff, 0x40, 0xb, 0xff, - 0xc0, 0xf, 0xff, 0xff, 0xf0, 0x3, 0xff, 0xe0, - 0x2f, 0xfe, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, - 0xbf, 0xf4, 0x3f, 0xf4, 0x0, 0x1, 0xff, 0xff, - 0x40, 0x0, 0x1f, 0xfc, 0x3f, 0xd0, 0x0, 0x0, - 0x2f, 0xf8, 0x0, 0x0, 0x7, 0xfc, 0x2f, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf8, - 0xf, 0xf4, 0x1b, 0xc0, 0x0, 0x0, 0x3, 0xe4, - 0x1f, 0xf0, 0xb, 0xfd, 0xff, 0xf4, 0x0, 0x0, - 0x1f, 0xff, 0x7f, 0xe0, 0x3, 0xff, 0xff, 0xff, - 0x80, 0x2, 0xff, 0xff, 0xff, 0xc0, 0x2, 0xff, - 0xff, 0xff, 0xd0, 0x7, 0xff, 0xff, 0xff, 0x40, - 0x0, 0xff, 0xf9, 0xff, 0xe0, 0xb, 0xff, 0x6f, - 0xfe, 0x0, 0x0, 0x2e, 0x40, 0x2f, 0xe0, 0xb, - 0xf8, 0x1, 0xf4, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xf0, 0xf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xf0, 0xf, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0xff, - 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, - 0xff, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0 -}; - - -/*--------------------- - * GLYPH DESCRIPTION - *--------------------*/ - -static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { - {.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */, - {.bitmap_index = 0, .adv_w = 768, .box_w = 40, .box_h = 32, .ofs_x = 4, .ofs_y = 8}, - {.bitmap_index = 320, .adv_w = 768, .box_w = 32, .box_h = 32, .ofs_x = 8, .ofs_y = 8}, - {.bitmap_index = 576, .adv_w = 768, .box_w = 40, .box_h = 40, .ofs_x = 4, .ofs_y = 4} -}; - -/*--------------------- - * CHARACTER MAPPING - *--------------------*/ - -static const uint16_t unicode_list_0[] = { - 0x0, 0x2fc, 0x5f1 -}; - -/*Collect the unicode lists and glyph_id offsets*/ -static const lv_font_fmt_txt_cmap_t cmaps[] = -{ - { - .range_start = 58055, .range_length = 1522, .glyph_id_start = 1, - .unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 3, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY - } -}; - - - -/*-------------------- - * ALL CUSTOM DATA - *--------------------*/ - -#if LVGL_VERSION_MAJOR == 8 -/*Store all the custom data of the font*/ -static lv_font_fmt_txt_glyph_cache_t cache; -#endif - -#if LVGL_VERSION_MAJOR >= 8 -static const lv_font_fmt_txt_dsc_t font_dsc = { -#else -static lv_font_fmt_txt_dsc_t font_dsc = { -#endif - .glyph_bitmap = glyph_bitmap, - .glyph_dsc = glyph_dsc, - .cmaps = cmaps, - .kern_dsc = NULL, - .kern_scale = 0, - .cmap_num = 1, - .bpp = 2, - .kern_classes = 0, - .bitmap_format = 0, -#if LVGL_VERSION_MAJOR == 8 - .cache = &cache -#endif -}; - - - -/*----------------- - * PUBLIC FONT - *----------------*/ - -/*Initialize a public general font descriptor*/ -#if LVGL_VERSION_MAJOR >= 8 -const lv_font_t material_symbols_launcher_48 = { -#else -lv_font_t material_symbols_launcher_48 = { -#endif - .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ - .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ - .line_height = 40, /*The maximum line height required by the font*/ - .base_line = -4, /*Baseline measured from the bottom of the line*/ -#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) - .subpx = LV_FONT_SUBPX_NONE, -#endif -#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 - .underline_position = 0, - .underline_thickness = 0, -#endif - .dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ -#if LV_VERSION_CHECK(8, 2, 0) || LVGL_VERSION_MAJOR >= 9 - .fallback = NULL, -#endif - .user_data = NULL, -}; - - - -#endif /*#if MATERIAL_SYMBOLS_LAUNCHER_48*/ - diff --git a/Modules/lvgl-module/source-fonts/material_symbols_launcher_64.c b/Modules/lvgl-module/source-fonts/material_symbols_launcher_64.c deleted file mode 100644 index 52054873b..000000000 --- a/Modules/lvgl-module/source-fonts/material_symbols_launcher_64.c +++ /dev/null @@ -1,348 +0,0 @@ -/******************************************************************************* - * Size: 64 px - * Bpp: 2 - * Opts: --no-compress --no-prefilter --bpp 2 --size 64 --font MaterialSymbolsRounded.ttf -r 0xE5C3,0xE2C7,0xE8B8 --format lvgl -o source-fonts/material_symbols_launcher_64.c --force-fast-kern-format - ******************************************************************************/ - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -#ifndef MATERIAL_SYMBOLS_LAUNCHER_64 -#define MATERIAL_SYMBOLS_LAUNCHER_64 1 -#endif - -#if MATERIAL_SYMBOLS_LAUNCHER_64 - -/*----------------- - * BITMAPS - *----------------*/ - -/*Store the image of the glyphs*/ -static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { - /* U+E2C7 "" */ - 0x0, 0x15, 0x55, 0x55, 0x55, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, - 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, - 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xd0, 0x0, 0x0, 0x1, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, 0xf, 0xfd, - 0x0, 0x0, 0x0, 0x7, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xe0, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x8f, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x7f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, - 0xd0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xdf, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x1, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x5f, 0xfd, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xdf, - 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xfd, 0xff, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xdf, 0xfd, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xdf, 0xfd, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xfd, 0xff, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xdf, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0xff, 0xd0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xdf, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xfd, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xdf, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xfd, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xdf, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0xff, - 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xdf, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xfd, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xdf, - 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xfd, 0xff, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xdf, 0xfd, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xdf, 0xfd, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xfd, 0xff, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xdf, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0xff, 0xd0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xdf, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdb, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xc2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x7, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf8, 0x0, 0x1, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x54, 0x0, - - /* U+E5C3 "" */ - 0x0, 0x55, 0x0, 0x0, 0x0, 0x55, 0x0, 0x0, - 0x0, 0x55, 0x0, 0x3, 0xff, 0xd0, 0x0, 0x3, - 0xff, 0xd0, 0x0, 0x3, 0xff, 0xd0, 0xf, 0xff, - 0xf4, 0x0, 0xf, 0xff, 0xf4, 0x0, 0xf, 0xff, - 0xf4, 0x2f, 0xff, 0xfc, 0x0, 0x2f, 0xff, 0xfc, - 0x0, 0x2f, 0xff, 0xfc, 0x3f, 0xff, 0xfc, 0x0, - 0x3f, 0xff, 0xfc, 0x0, 0x3f, 0xff, 0xfc, 0x3f, - 0xff, 0xfd, 0x0, 0x3f, 0xff, 0xfd, 0x0, 0x3f, - 0xff, 0xfd, 0x3f, 0xff, 0xfd, 0x0, 0x3f, 0xff, - 0xfd, 0x0, 0x3f, 0xff, 0xfd, 0x3f, 0xff, 0xfc, - 0x0, 0x3f, 0xff, 0xfc, 0x0, 0x3f, 0xff, 0xfc, - 0x1f, 0xff, 0xf8, 0x0, 0x1f, 0xff, 0xf8, 0x0, - 0x1f, 0xff, 0xf8, 0xb, 0xff, 0xf0, 0x0, 0xb, - 0xff, 0xf0, 0x0, 0xb, 0xff, 0xf0, 0x1, 0xff, - 0x80, 0x0, 0x1, 0xff, 0x80, 0x0, 0x1, 0xff, - 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x55, 0x0, 0x0, 0x0, 0x55, 0x0, 0x0, - 0x0, 0x55, 0x0, 0x3, 0xff, 0xd0, 0x0, 0x3, - 0xff, 0xd0, 0x0, 0x3, 0xff, 0xd0, 0xf, 0xff, - 0xf4, 0x0, 0xf, 0xff, 0xf4, 0x0, 0xf, 0xff, - 0xf4, 0x2f, 0xff, 0xfc, 0x0, 0x2f, 0xff, 0xfc, - 0x0, 0x2f, 0xff, 0xfc, 0x3f, 0xff, 0xfc, 0x0, - 0x3f, 0xff, 0xfc, 0x0, 0x3f, 0xff, 0xfc, 0x3f, - 0xff, 0xfd, 0x0, 0x3f, 0xff, 0xfd, 0x0, 0x3f, - 0xff, 0xfd, 0x3f, 0xff, 0xfd, 0x0, 0x3f, 0xff, - 0xfd, 0x0, 0x3f, 0xff, 0xfd, 0x3f, 0xff, 0xfc, - 0x0, 0x3f, 0xff, 0xfc, 0x0, 0x3f, 0xff, 0xfc, - 0x1f, 0xff, 0xf8, 0x0, 0x1f, 0xff, 0xf8, 0x0, - 0x1f, 0xff, 0xf8, 0xb, 0xff, 0xf0, 0x0, 0xb, - 0xff, 0xf0, 0x0, 0xb, 0xff, 0xf0, 0x1, 0xff, - 0x80, 0x0, 0x1, 0xff, 0x80, 0x0, 0x1, 0xff, - 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x55, 0x0, 0x0, 0x0, 0x55, 0x0, 0x0, - 0x0, 0x55, 0x0, 0x3, 0xff, 0xd0, 0x0, 0x3, - 0xff, 0xd0, 0x0, 0x3, 0xff, 0xd0, 0xf, 0xff, - 0xf4, 0x0, 0xf, 0xff, 0xf4, 0x0, 0xf, 0xff, - 0xf4, 0x2f, 0xff, 0xfc, 0x0, 0x2f, 0xff, 0xfc, - 0x0, 0x2f, 0xff, 0xfc, 0x3f, 0xff, 0xfc, 0x0, - 0x3f, 0xff, 0xfc, 0x0, 0x3f, 0xff, 0xfc, 0x3f, - 0xff, 0xfd, 0x0, 0x3f, 0xff, 0xfd, 0x0, 0x3f, - 0xff, 0xfd, 0x3f, 0xff, 0xfd, 0x0, 0x3f, 0xff, - 0xfd, 0x0, 0x3f, 0xff, 0xfd, 0x3f, 0xff, 0xfc, - 0x0, 0x3f, 0xff, 0xfc, 0x0, 0x3f, 0xff, 0xfc, - 0x1f, 0xff, 0xf8, 0x0, 0x1f, 0xff, 0xf8, 0x0, - 0x1f, 0xff, 0xf8, 0xb, 0xff, 0xf0, 0x0, 0xb, - 0xff, 0xf0, 0x0, 0xb, 0xff, 0xf0, 0x1, 0xff, - 0x80, 0x0, 0x1, 0xff, 0x80, 0x0, 0x1, 0xff, - 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, - - /* U+E8B8 "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0x55, 0x50, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, - 0xff, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7, 0xff, 0xff, 0xff, 0xd0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xb, 0xff, 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, - 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xfd, 0x0, 0x7f, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xfc, 0x0, 0x3f, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x3f, - 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xfd, - 0x0, 0x7f, 0xfc, 0x0, 0x3f, 0xfd, 0x0, 0x7f, - 0xe0, 0x0, 0x0, 0x3f, 0xff, 0xe3, 0xff, 0xfc, - 0x0, 0x3f, 0xff, 0xcb, 0xff, 0xfc, 0x0, 0x0, - 0xff, 0xff, 0xff, 0xff, 0xf8, 0x0, 0x2f, 0xff, - 0xff, 0xff, 0xff, 0x0, 0x1, 0xff, 0xff, 0xff, - 0xff, 0xf8, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, - 0x40, 0x3, 0xff, 0xff, 0xff, 0xff, 0x90, 0x0, - 0x6, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xb, 0xff, - 0xaf, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x2f, 0xff, - 0xfa, 0xff, 0xe0, 0xf, 0xff, 0x1, 0xff, 0xd0, - 0x0, 0x0, 0x0, 0x7, 0xff, 0x40, 0xff, 0xf0, - 0x2f, 0xfe, 0x0, 0x1b, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xe4, 0x0, 0xbf, 0xf8, 0x3f, 0xfc, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3f, 0xfc, 0x7f, 0xf4, 0x0, 0x0, 0x0, 0x6, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x1f, 0xfd, 0x7f, - 0xfc, 0x0, 0x0, 0x0, 0x3f, 0xff, 0xfd, 0x0, - 0x0, 0x0, 0x3f, 0xfd, 0x3f, 0xff, 0x40, 0x0, - 0x1, 0xff, 0xff, 0xff, 0x80, 0x0, 0x1, 0xff, - 0xfc, 0x2f, 0xff, 0xe0, 0x0, 0x3, 0xff, 0xff, - 0xff, 0xd0, 0x0, 0xb, 0xff, 0xf8, 0xb, 0xff, - 0xfc, 0x0, 0xf, 0xff, 0xff, 0xff, 0xf0, 0x0, - 0x3f, 0xff, 0xe0, 0x1, 0xff, 0xff, 0x0, 0x1f, - 0xff, 0xff, 0xff, 0xf8, 0x0, 0xff, 0xff, 0x40, - 0x0, 0x7f, 0xfe, 0x0, 0x3f, 0xff, 0xff, 0xff, - 0xfc, 0x0, 0xbf, 0xfd, 0x0, 0x0, 0xf, 0xfd, - 0x0, 0x3f, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x7f, - 0xf0, 0x0, 0x0, 0xf, 0xfd, 0x0, 0x3f, 0xff, - 0xff, 0xff, 0xfd, 0x0, 0x7f, 0xf0, 0x0, 0x0, - 0xf, 0xfd, 0x0, 0x3f, 0xff, 0xff, 0xff, 0xfd, - 0x0, 0x7f, 0xf0, 0x0, 0x0, 0xf, 0xfd, 0x0, - 0x3f, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x7f, 0xf0, - 0x0, 0x0, 0x2f, 0xfe, 0x0, 0x3f, 0xff, 0xff, - 0xff, 0xfc, 0x0, 0xbf, 0xf8, 0x0, 0x0, 0xff, - 0xfe, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xfc, 0x0, - 0xbf, 0xfe, 0x0, 0x7, 0xff, 0xfe, 0x0, 0xf, - 0xff, 0xff, 0xff, 0xf4, 0x0, 0xbf, 0xff, 0xc0, - 0xf, 0xff, 0xf4, 0x0, 0xb, 0xff, 0xff, 0xff, - 0xf0, 0x0, 0x1f, 0xff, 0xf0, 0x3f, 0xff, 0xc0, - 0x0, 0x2, 0xff, 0xff, 0xff, 0xc0, 0x0, 0x3, - 0xff, 0xfc, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0xbf, - 0xff, 0xff, 0x0, 0x0, 0x0, 0xbf, 0xfc, 0x7f, - 0xf4, 0x0, 0x0, 0x0, 0x1f, 0xff, 0xf4, 0x0, - 0x0, 0x0, 0x1f, 0xfd, 0x7f, 0xf8, 0x0, 0x0, - 0x0, 0x0, 0x59, 0x0, 0x0, 0x0, 0x0, 0x2f, - 0xfc, 0x3f, 0xfd, 0x0, 0x5, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x40, 0x0, 0x7f, 0xfc, 0x1f, 0xff, - 0x0, 0x7f, 0x80, 0x0, 0x0, 0x0, 0x2, 0xfd, - 0x0, 0xff, 0xf4, 0xf, 0xff, 0x4b, 0xff, 0xf0, - 0x0, 0x0, 0x0, 0xf, 0xff, 0xe1, 0xff, 0xe0, - 0x3, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, - 0xbf, 0xff, 0xff, 0xff, 0xc0, 0x2, 0xff, 0xff, - 0xff, 0xff, 0xf4, 0x0, 0x1f, 0xff, 0xff, 0xff, - 0xff, 0x80, 0x0, 0xff, 0xff, 0xff, 0xff, 0xf8, - 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, - 0x7f, 0xff, 0xfb, 0xff, 0xf8, 0x0, 0x2f, 0xff, - 0xef, 0xff, 0xfd, 0x0, 0x0, 0x1f, 0xff, 0x40, - 0xff, 0xfc, 0x0, 0x3f, 0xff, 0x1, 0xff, 0xf4, - 0x0, 0x0, 0x2, 0xa0, 0x0, 0x2f, 0xfc, 0x0, - 0x3f, 0xf8, 0x0, 0x1a, 0x80, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x3f, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xfc, 0x0, 0x7f, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xfe, 0x55, 0xbf, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xff, 0xff, 0xff, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, - 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xff, 0xff, 0xff, 0xc0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xff, 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, - 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0 -}; - - -/*--------------------- - * GLYPH DESCRIPTION - *--------------------*/ - -static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { - {.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */, - {.bitmap_index = 0, .adv_w = 1024, .box_w = 54, .box_h = 44, .ofs_x = 5, .ofs_y = 10}, - {.bitmap_index = 594, .adv_w = 1024, .box_w = 44, .box_h = 44, .ofs_x = 10, .ofs_y = 10}, - {.bitmap_index = 1078, .adv_w = 1024, .box_w = 52, .box_h = 54, .ofs_x = 6, .ofs_y = 5} -}; - -/*--------------------- - * CHARACTER MAPPING - *--------------------*/ - -static const uint16_t unicode_list_0[] = { - 0x0, 0x2fc, 0x5f1 -}; - -/*Collect the unicode lists and glyph_id offsets*/ -static const lv_font_fmt_txt_cmap_t cmaps[] = -{ - { - .range_start = 58055, .range_length = 1522, .glyph_id_start = 1, - .unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 3, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY - } -}; - - - -/*-------------------- - * ALL CUSTOM DATA - *--------------------*/ - -#if LVGL_VERSION_MAJOR == 8 -/*Store all the custom data of the font*/ -static lv_font_fmt_txt_glyph_cache_t cache; -#endif - -#if LVGL_VERSION_MAJOR >= 8 -static const lv_font_fmt_txt_dsc_t font_dsc = { -#else -static lv_font_fmt_txt_dsc_t font_dsc = { -#endif - .glyph_bitmap = glyph_bitmap, - .glyph_dsc = glyph_dsc, - .cmaps = cmaps, - .kern_dsc = NULL, - .kern_scale = 0, - .cmap_num = 1, - .bpp = 2, - .kern_classes = 0, - .bitmap_format = 0, -#if LVGL_VERSION_MAJOR == 8 - .cache = &cache -#endif -}; - - - -/*----------------- - * PUBLIC FONT - *----------------*/ - -/*Initialize a public general font descriptor*/ -#if LVGL_VERSION_MAJOR >= 8 -const lv_font_t material_symbols_launcher_64 = { -#else -lv_font_t material_symbols_launcher_64 = { -#endif - .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ - .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ - .line_height = 54, /*The maximum line height required by the font*/ - .base_line = -5, /*Baseline measured from the bottom of the line*/ -#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) - .subpx = LV_FONT_SUBPX_NONE, -#endif -#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 - .underline_position = 0, - .underline_thickness = 0, -#endif - .dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ -#if LV_VERSION_CHECK(8, 2, 0) || LVGL_VERSION_MAJOR >= 9 - .fallback = NULL, -#endif - .user_data = NULL, -}; - - - -#endif /*#if MATERIAL_SYMBOLS_LAUNCHER_64*/ - diff --git a/Modules/lvgl-module/source-fonts/material_symbols_launcher_72.c b/Modules/lvgl-module/source-fonts/material_symbols_launcher_72.c deleted file mode 100644 index ee936c791..000000000 --- a/Modules/lvgl-module/source-fonts/material_symbols_launcher_72.c +++ /dev/null @@ -1,397 +0,0 @@ -/******************************************************************************* - * Size: 72 px - * Bpp: 2 - * Opts: --no-compress --no-prefilter --bpp 2 --size 72 --font MaterialSymbolsRounded.ttf -r 0xE5C3,0xE2C7,0xE8B8 --format lvgl -o source-fonts/material_symbols_launcher_72.c --force-fast-kern-format - ******************************************************************************/ - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -#ifndef MATERIAL_SYMBOLS_LAUNCHER_72 -#define MATERIAL_SYMBOLS_LAUNCHER_72 1 -#endif - -#if MATERIAL_SYMBOLS_LAUNCHER_72 - -/*----------------- - * BITMAPS - *----------------*/ - -/*Store the image of the glyphs*/ -static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { - /* U+E2C7 "" */ - 0x1, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xf8, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xf0, 0x0, 0x0, 0x0, 0xf, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x40, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x3, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, - 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, - 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xff, 0xff, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, - 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xff, 0xff, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, - 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xff, 0xff, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, - 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfd, 0x3f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfc, 0xf, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xf0, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x40, - - /* U+E5C3 "" */ - 0x1, 0xff, 0x40, 0x0, 0x0, 0x1f, 0xf4, 0x0, - 0x0, 0x1, 0xff, 0x40, 0xf, 0xff, 0xf0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0xf, 0xff, 0xf0, - 0x3f, 0xff, 0xfc, 0x0, 0x3, 0xff, 0xff, 0xc0, - 0x0, 0x3f, 0xff, 0xfc, 0x7f, 0xff, 0xfd, 0x0, - 0x7, 0xff, 0xff, 0xd0, 0x0, 0x7f, 0xff, 0xfd, - 0xff, 0xff, 0xff, 0x0, 0xf, 0xff, 0xff, 0xf0, - 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, - 0xf, 0xff, 0xff, 0xf0, 0x0, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x0, 0xf, 0xff, 0xff, 0xf0, - 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, - 0xf, 0xff, 0xff, 0xf0, 0x0, 0xff, 0xff, 0xff, - 0x7f, 0xff, 0xfd, 0x0, 0x7, 0xff, 0xff, 0xd0, - 0x0, 0x7f, 0xff, 0xfd, 0x3f, 0xff, 0xfc, 0x0, - 0x3, 0xff, 0xff, 0xc0, 0x0, 0x3f, 0xff, 0xfc, - 0xf, 0xff, 0xf0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0xf, 0xff, 0xf0, 0x1, 0xff, 0x40, 0x0, - 0x0, 0x1f, 0xf4, 0x0, 0x0, 0x1, 0xff, 0x40, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xff, 0x40, 0x0, 0x0, 0x1f, 0xf4, 0x0, - 0x0, 0x1, 0xff, 0x40, 0xf, 0xff, 0xf0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0xf, 0xff, 0xf0, - 0x3f, 0xff, 0xfc, 0x0, 0x3, 0xff, 0xff, 0xc0, - 0x0, 0x3f, 0xff, 0xfc, 0x7f, 0xff, 0xfd, 0x0, - 0x7, 0xff, 0xff, 0xd0, 0x0, 0x7f, 0xff, 0xfd, - 0xff, 0xff, 0xff, 0x0, 0xf, 0xff, 0xff, 0xf0, - 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, - 0xf, 0xff, 0xff, 0xf0, 0x0, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x0, 0xf, 0xff, 0xff, 0xf0, - 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, - 0xf, 0xff, 0xff, 0xf0, 0x0, 0xff, 0xff, 0xff, - 0x7f, 0xff, 0xfd, 0x0, 0x7, 0xff, 0xff, 0xd0, - 0x0, 0x7f, 0xff, 0xfd, 0x3f, 0xff, 0xfc, 0x0, - 0x3, 0xff, 0xff, 0xc0, 0x0, 0x3f, 0xff, 0xfc, - 0xf, 0xff, 0xf0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0xf, 0xff, 0xf0, 0x1, 0xff, 0x40, 0x0, - 0x0, 0x1f, 0xf4, 0x0, 0x0, 0x1, 0xff, 0x40, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xff, 0x40, 0x0, 0x0, 0x1f, 0xf4, 0x0, - 0x0, 0x1, 0xff, 0x40, 0xf, 0xff, 0xf0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0xf, 0xff, 0xf0, - 0x3f, 0xff, 0xfc, 0x0, 0x3, 0xff, 0xff, 0xc0, - 0x0, 0x3f, 0xff, 0xfc, 0x7f, 0xff, 0xfd, 0x0, - 0x7, 0xff, 0xff, 0xd0, 0x0, 0x7f, 0xff, 0xfd, - 0xff, 0xff, 0xff, 0x0, 0xf, 0xff, 0xff, 0xf0, - 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, - 0xf, 0xff, 0xff, 0xf0, 0x0, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x0, 0xf, 0xff, 0xff, 0xf0, - 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, - 0xf, 0xff, 0xff, 0xf0, 0x0, 0xff, 0xff, 0xff, - 0x7f, 0xff, 0xfd, 0x0, 0x7, 0xff, 0xff, 0xd0, - 0x0, 0x7f, 0xff, 0xfd, 0x3f, 0xff, 0xfc, 0x0, - 0x3, 0xff, 0xff, 0xc0, 0x0, 0x3f, 0xff, 0xfc, - 0xf, 0xff, 0xf0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0xf, 0xff, 0xf0, 0x1, 0xff, 0x40, 0x0, - 0x0, 0x1f, 0xf4, 0x0, 0x0, 0x1, 0xff, 0x40, - - /* U+E8B8 "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xff, - 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xfe, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xb, 0xff, 0xff, 0xff, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3f, 0xff, 0xff, 0xff, 0xf8, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, 0xc0, - 0x3, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfe, 0x0, 0xf, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xbf, 0xf8, 0x0, 0x3f, 0xfc, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xa8, - 0x0, 0x3, 0xff, 0xd0, 0x0, 0xff, 0xf4, 0x0, - 0x6, 0xe4, 0x0, 0x0, 0x0, 0x7f, 0xff, 0x40, - 0x7f, 0xff, 0x40, 0x2, 0xff, 0xfc, 0x2, 0xff, - 0xf8, 0x0, 0x0, 0x3, 0xff, 0xff, 0xef, 0xff, - 0xfc, 0x0, 0xb, 0xff, 0xfe, 0xbf, 0xff, 0xfc, - 0x0, 0x0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xf0, - 0x0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x0, - 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0, - 0x7f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0, 0xf, - 0xff, 0xff, 0xff, 0xff, 0xe4, 0x0, 0x0, 0x2f, - 0xff, 0xff, 0xff, 0xff, 0xe0, 0x0, 0xbf, 0xfe, - 0xff, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xef, 0xff, 0xc0, 0x3, 0xff, 0xf0, 0x6f, - 0xff, 0x40, 0x0, 0x0, 0x0, 0x2, 0xff, 0xf8, - 0x1f, 0xff, 0x80, 0x2f, 0xff, 0x40, 0xb, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x1, 0xfd, 0x0, 0x2f, - 0xff, 0x41, 0xff, 0xf8, 0x0, 0x1, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x1, 0x40, 0x0, 0x3f, 0xff, - 0xb, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x15, - 0x40, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xfc, 0x3f, - 0xfe, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, 0xf4, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xf4, 0xbf, 0xfe, - 0x0, 0x0, 0x0, 0x7, 0xff, 0xff, 0xfc, 0x0, - 0x0, 0x0, 0x1f, 0xff, 0xc1, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x7f, 0xff, 0xff, 0xfd, 0x0, 0x0, - 0x2, 0xff, 0xff, 0x3, 0xff, 0xff, 0x40, 0x0, - 0x7, 0xff, 0xff, 0xff, 0xfc, 0x0, 0x0, 0x3f, - 0xff, 0xf4, 0x3, 0xff, 0xff, 0x80, 0x0, 0x3f, - 0xff, 0xff, 0xff, 0xfc, 0x0, 0x7, 0xff, 0xff, - 0x80, 0x3, 0xff, 0xff, 0xc0, 0x2, 0xff, 0xff, - 0xff, 0xff, 0xf4, 0x0, 0x3f, 0xff, 0xf4, 0x0, - 0x2, 0xff, 0xfe, 0x0, 0xf, 0xff, 0xff, 0xff, - 0xff, 0xf0, 0x0, 0xff, 0xff, 0x40, 0x0, 0x1, - 0xff, 0xf4, 0x0, 0x7f, 0xff, 0xff, 0xff, 0xff, - 0xc0, 0x3, 0xff, 0xe0, 0x0, 0x0, 0x2, 0xff, - 0xd0, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0x40, - 0xf, 0xff, 0x0, 0x0, 0x0, 0xb, 0xff, 0x40, - 0xb, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x3f, - 0xfd, 0x0, 0x0, 0x0, 0x2f, 0xfd, 0x0, 0x2f, - 0xff, 0xff, 0xff, 0xff, 0xf4, 0x0, 0xff, 0xf4, - 0x0, 0x0, 0x0, 0xbf, 0xf4, 0x0, 0x7f, 0xff, - 0xff, 0xff, 0xff, 0xd0, 0x3, 0xff, 0xc0, 0x0, - 0x0, 0x7, 0xff, 0xd0, 0x1, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x0, 0xf, 0xff, 0x80, 0x0, 0x0, - 0xbf, 0xff, 0x80, 0x3, 0xff, 0xff, 0xff, 0xff, - 0xfc, 0x0, 0x3f, 0xff, 0xc0, 0x0, 0xf, 0xff, - 0xff, 0x0, 0xb, 0xff, 0xff, 0xff, 0xff, 0xd0, - 0x0, 0xff, 0xff, 0xd0, 0x0, 0xff, 0xff, 0xe0, - 0x0, 0xf, 0xff, 0xff, 0xff, 0xff, 0x0, 0x1, - 0xff, 0xff, 0xe0, 0xf, 0xff, 0xfd, 0x0, 0x0, - 0x1f, 0xff, 0xff, 0xff, 0xf0, 0x0, 0x0, 0xff, - 0xff, 0xd0, 0x7f, 0xff, 0xc0, 0x0, 0x0, 0x1f, - 0xff, 0xff, 0xff, 0x40, 0x0, 0x0, 0xbf, 0xff, - 0xc2, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x1f, 0xff, - 0xff, 0xf0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0xf, - 0xff, 0x80, 0x0, 0x0, 0x0, 0xb, 0xff, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfc, 0x2f, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x55, 0x0, 0x0, - 0x0, 0x0, 0x2, 0xff, 0xf0, 0x7f, 0xfe, 0x0, - 0x0, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, - 0x0, 0xf, 0xff, 0x80, 0xbf, 0xfd, 0x0, 0x2f, - 0xc0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xf4, 0x0, - 0xbf, 0xfc, 0x0, 0xff, 0xfc, 0x1b, 0xff, 0xd0, - 0x0, 0x0, 0x0, 0x0, 0xbf, 0xfe, 0x7, 0xff, - 0xe0, 0x2, 0xff, 0xfb, 0xff, 0xff, 0xe0, 0x0, - 0x0, 0x0, 0x1f, 0xff, 0xff, 0xbf, 0xff, 0x0, - 0x3, 0xff, 0xff, 0xff, 0xff, 0xf9, 0x0, 0x0, - 0xb, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x0, 0x7, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x1, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0, 0xf, 0xff, - 0xff, 0xff, 0xff, 0xfc, 0x0, 0x7, 0xff, 0xff, - 0xff, 0xff, 0xfd, 0x0, 0x0, 0xf, 0xff, 0xff, - 0xbf, 0xff, 0xf0, 0x0, 0x2f, 0xff, 0xfa, 0xff, - 0xff, 0xe0, 0x0, 0x0, 0x1f, 0xff, 0xd0, 0x1f, - 0xff, 0xc0, 0x0, 0xbf, 0xff, 0x0, 0xbf, 0xfe, - 0x0, 0x0, 0x0, 0x6, 0xa0, 0x0, 0xf, 0xff, - 0x40, 0x3, 0xff, 0xd0, 0x0, 0x1b, 0x90, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xfd, 0x0, - 0xf, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7f, 0xf8, 0x0, 0x3f, - 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x1, 0xff, 0xe0, 0x0, 0xff, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, - 0xff, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xff, - 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0xff, - 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0x80, - 0x0, 0x0, 0x0, 0x0, 0x0 -}; - - -/*--------------------- - * GLYPH DESCRIPTION - *--------------------*/ - -static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { - {.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */, - {.bitmap_index = 0, .adv_w = 1152, .box_w = 60, .box_h = 48, .ofs_x = 6, .ofs_y = 12}, - {.bitmap_index = 720, .adv_w = 1152, .box_w = 48, .box_h = 48, .ofs_x = 12, .ofs_y = 12}, - {.bitmap_index = 1296, .adv_w = 1152, .box_w = 59, .box_h = 60, .ofs_x = 6, .ofs_y = 6} -}; - -/*--------------------- - * CHARACTER MAPPING - *--------------------*/ - -static const uint16_t unicode_list_0[] = { - 0x0, 0x2fc, 0x5f1 -}; - -/*Collect the unicode lists and glyph_id offsets*/ -static const lv_font_fmt_txt_cmap_t cmaps[] = -{ - { - .range_start = 58055, .range_length = 1522, .glyph_id_start = 1, - .unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 3, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY - } -}; - - - -/*-------------------- - * ALL CUSTOM DATA - *--------------------*/ - -#if LVGL_VERSION_MAJOR == 8 -/*Store all the custom data of the font*/ -static lv_font_fmt_txt_glyph_cache_t cache; -#endif - -#if LVGL_VERSION_MAJOR >= 8 -static const lv_font_fmt_txt_dsc_t font_dsc = { -#else -static lv_font_fmt_txt_dsc_t font_dsc = { -#endif - .glyph_bitmap = glyph_bitmap, - .glyph_dsc = glyph_dsc, - .cmaps = cmaps, - .kern_dsc = NULL, - .kern_scale = 0, - .cmap_num = 1, - .bpp = 2, - .kern_classes = 0, - .bitmap_format = 0, -#if LVGL_VERSION_MAJOR == 8 - .cache = &cache -#endif -}; - - - -/*----------------- - * PUBLIC FONT - *----------------*/ - -/*Initialize a public general font descriptor*/ -#if LVGL_VERSION_MAJOR >= 8 -const lv_font_t material_symbols_launcher_72 = { -#else -lv_font_t material_symbols_launcher_72 = { -#endif - .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ - .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ - .line_height = 60, /*The maximum line height required by the font*/ - .base_line = -6, /*Baseline measured from the bottom of the line*/ -#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) - .subpx = LV_FONT_SUBPX_NONE, -#endif -#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 - .underline_position = 0, - .underline_thickness = 0, -#endif - .dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ -#if LV_VERSION_CHECK(8, 2, 0) || LVGL_VERSION_MAJOR >= 9 - .fallback = NULL, -#endif - .user_data = NULL, -}; - - - -#endif /*#if MATERIAL_SYMBOLS_LAUNCHER_72*/ - diff --git a/Modules/lvgl-module/source-fonts/material_symbols_shared_12.c b/Modules/lvgl-module/source-fonts/material_symbols_shared_12.c deleted file mode 100644 index cd1c3b0fd..000000000 --- a/Modules/lvgl-module/source-fonts/material_symbols_shared_12.c +++ /dev/null @@ -1,415 +0,0 @@ -/******************************************************************************* - * Size: 12 px - * Bpp: 2 - * Opts: --no-compress --no-prefilter --bpp 2 --size 12 --font MaterialSymbolsRounded.ttf -r 0xE145,0xE5C3,0xE770,0xEF40,0xEBCC,0xEFE6,0xEF4A,0xE5CD,0xF15C,0xE668,0xE92E,0xE326,0xEB97,0xE745,0xEC1C,0xE2C7,0xF720,0xF090,0xE8AF,0xE30F,0xE8FD,0xE9F4,0xE3F4,0xE316,0xE90F,0xEA07,0xE9B9,0xE159,0xE5D2,0xE28D,0xE5D4,0xE405,0xE89C,0xF8C7,0xE5D5,0xEF7A,0xE8B8,0xE9F7,0xE55D,0xF028,0xE1E0,0xE63E,0xE1A7,0xEB8E,0xEAD6,0xE3AF,0xFFF75 --format lvgl -o source-fonts/material_symbols_shared_12.c --force-fast-kern-format - ******************************************************************************/ - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -#ifndef MATERIAL_SYMBOLS_SHARED_12 -#define MATERIAL_SYMBOLS_SHARED_12 1 -#endif - -#if MATERIAL_SYMBOLS_SHARED_12 - -/*----------------- - * BITMAPS - *----------------*/ - -/*Store the image of the glyphs*/ -static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { - /* U+E145 "" */ - 0x0, 0x0, 0x2, 0x40, 0x2, 0x40, 0x17, 0x54, - 0x6b, 0xe8, 0x2, 0x40, 0x2, 0x40, 0x1, 0x0, - - /* U+E159 "" */ - 0xff, 0xff, 0xfe, 0x0, 0xb, 0xdd, 0x7, 0x7c, - 0x2f, 0x83, 0xc0, 0x0, 0x3c, 0x0, 0x3, 0xc0, - 0x0, 0x3f, 0xff, 0xff, - - /* U+E1A7 "" */ - 0x1, 0x40, 0xb, 0x47, 0x2b, 0x7, 0xec, 0x7, - 0xc0, 0x1f, 0x1, 0xfb, 0x1c, 0x9d, 0x2, 0xd0, - 0x9, 0x0, - - /* U+E1E0 "" */ - 0x2, 0x0, 0x7, 0x80, 0x3, 0x0, 0x73, 0x3c, - 0xb3, 0x3c, 0x33, 0x18, 0x3f, 0xf4, 0x3, 0x0, - 0x3, 0x40, 0x3, 0x40, - - /* U+E28D "" */ - 0x0, 0x0, 0x0, 0x2, 0xf0, 0x0, 0xc, 0xc0, - 0x0, 0x33, 0x0, 0x0, 0xcc, 0x0, 0x1b, 0xba, - 0x42, 0xaa, 0xab, 0x9, 0x55, 0x5c, 0x3a, 0xaa, - 0xb4, 0xc4, 0x85, 0xa6, 0x67, 0x69, 0x8a, 0xaa, - 0xa9, - - /* U+E2C7 "" */ - 0xff, 0x40, 0xc, 0xf, 0xff, 0xc0, 0x0, 0x3c, - 0x0, 0x3, 0xc0, 0x0, 0x3c, 0x0, 0x3, 0xc0, - 0x0, 0x3f, 0xff, 0xff, - - /* U+E30F "" */ - 0x2, 0xf0, 0x0, 0x26, 0x40, 0x2, 0x74, 0x1, - 0xe, 0x4, 0xed, 0xb, 0xbd, 0xb0, 0xd7, 0xa8, - 0xe2, 0xa0, 0x2b, 0x0, 0x2, 0x64, 0x0, 0x2f, - 0x0, - - /* U+E316 "" */ - 0x5, 0x1, 0xf8, 0x70, 0xd4, 0x1, - - /* U+E326 "" */ - 0x7f, 0xff, 0xda, 0x0, 0x0, 0xa0, 0xf, 0xfa, - 0x0, 0xc3, 0xa0, 0xc, 0x37, 0xa4, 0xc3, 0x1a, - 0x4c, 0x3f, 0xfc, 0xff, - - /* U+E3AF "" */ - 0x6, 0xf9, 0x2, 0xd2, 0x78, 0x74, 0x50, 0xd9, - 0x8e, 0xaa, 0xc3, 0xf4, 0x3c, 0x1f, 0xc3, 0xaa, - 0xb2, 0x67, 0x5, 0x1d, 0x2d, 0x87, 0x80, 0x6f, - 0x90, - - /* U+E3F4 "" */ - 0x15, 0x55, 0xb, 0xaa, 0xac, 0x90, 0x0, 0xc9, - 0x0, 0xc, 0x90, 0x0, 0xc9, 0x1, 0xc, 0x97, - 0x3c, 0xc9, 0xaa, 0x8c, 0x95, 0x55, 0xc6, 0xaa, - 0xa8, - - /* U+E405 "" */ - 0x0, 0x40, 0x3f, 0x3, 0xa0, 0x30, 0x3, 0x0, - 0x30, 0xbf, 0xf, 0xf0, 0xff, 0x2, 0x80, - - /* U+E55D "" */ - 0x0, 0x0, 0x2, 0x80, 0x3, 0xc0, 0xa, 0xa0, - 0xc, 0x30, 0x18, 0x24, 0x30, 0xc, 0x77, 0xdd, - 0xf8, 0x2f, 0x40, 0x1, - - /* U+E5C3 "" */ - 0xf3, 0xcf, 0xf3, 0xcf, 0x0, 0x0, 0xf3, 0xcf, - 0xf3, 0xcf, 0x0, 0x0, 0xf3, 0xcf, 0xf3, 0xcf, - - /* U+E5CD "" */ - 0x10, 0x0, 0x34, 0x1c, 0xd, 0x70, 0x3, 0xc0, - 0x7, 0xd0, 0x1c, 0x34, 0x30, 0xc, 0x0, 0x0, - - /* U+E5D2 "" */ - 0xbf, 0xff, 0xc0, 0x0, 0x0, 0x15, 0x55, 0x46, - 0xaa, 0xa8, 0x0, 0x0, 0xb, 0xff, 0xfc, - - /* U+E5D4 "" */ - 0xff, 0xf, 0xf0, 0xff, - - /* U+E5D5 "" */ - 0xb, 0xe3, 0x34, 0x2f, 0x90, 0x1b, 0xc0, 0x6a, - 0xc0, 0x0, 0x90, 0x5, 0x34, 0x1c, 0xb, 0xe0, - - /* U+E63E "" */ - 0x6, 0xff, 0x80, 0x2f, 0xaa, 0xf8, 0xb4, 0x0, - 0x2d, 0x1, 0xfe, 0x40, 0xb, 0xeb, 0xd0, 0x0, - 0x0, 0x40, 0x0, 0x3c, 0x0, 0x0, 0x7c, 0x0, - 0x0, 0x14, 0x0, - - /* U+E668 "" */ - 0x0, 0x2, 0x0, 0xd, 0x0, 0x34, 0xa0, 0xd0, - 0x2b, 0x40, 0x9, 0x0, - - /* U+E745 "" */ - 0xff, 0xc0, 0x0, 0x0, 0xf, 0xfc, 0x0, 0x0, - 0x4, 0xfd, 0xb, 0xc0, 0xa, 0xd0, 0x9, 0x90, - 0x2, 0xd0, - - /* U+E770 "" */ - 0x0, 0xa0, 0x0, 0x2a, 0xd0, 0x57, 0x6, 0xcb, - 0xd0, 0xc, 0x94, 0x90, 0xc9, 0x1f, 0x8c, 0xbb, - 0xff, 0xcb, 0xff, 0xfc, 0x0, 0x0, 0x0, - - /* U+E89C "" */ - 0xff, 0xd0, 0xc0, 0xb8, 0xc0, 0xbd, 0xc0, 0x2b, - 0xc1, 0x43, 0xc6, 0x93, 0xc6, 0x93, 0xc1, 0x43, - 0xc0, 0x3, 0xff, 0xff, - - /* U+E8AF "" */ - 0xff, 0xfc, 0xc, 0x0, 0x90, 0xc0, 0x9, 0x6c, - 0x0, 0x9b, 0xc5, 0x5d, 0xbf, 0xaa, 0x8b, 0x8a, - 0xaa, 0xf0, 0xff, 0xff, 0x0, 0x0, 0xb0, 0x0, - 0x0, - - /* U+E8B8 "" */ - 0x1, 0xf4, 0x1, 0x25, 0x84, 0x7e, 0xb, 0xda, - 0xa, 0xa, 0x36, 0xf9, 0xc3, 0x2f, 0x9c, 0xa0, - 0xa0, 0xa7, 0xe0, 0xbd, 0x12, 0x58, 0x40, 0x1f, - 0x40, - - /* U+E8FD "" */ - 0x6, 0xf9, 0x2, 0xd0, 0x78, 0x70, 0xf4, 0xd9, - 0x1, 0x86, 0xc0, 0x24, 0x3c, 0x6, 0x3, 0x90, - 0x0, 0x67, 0x9, 0xd, 0x2d, 0x7, 0x80, 0x6f, - 0x90, - - /* U+E90F "" */ - 0xb, 0xe0, 0x34, 0x1c, 0xa0, 0xa, 0x90, 0x6, - 0x90, 0x6, 0x70, 0xd, 0x1f, 0xf4, 0x6, 0x90, - 0x6, 0x90, 0x3, 0xc0, - - /* U+E92E "" */ - 0x2, 0x80, 0xff, 0xff, 0xa0, 0xa, 0xa5, 0x5a, - 0xa5, 0x5a, 0xa5, 0x5a, 0xa5, 0x5a, 0xa5, 0x5a, - 0x65, 0x59, 0x2a, 0xa8, - - /* U+E9B9 "" */ - 0xf3, 0xff, 0xff, 0x3f, 0xff, 0x0, 0x0, 0xf, - 0x3f, 0xff, 0xf3, 0xff, 0xf0, 0x0, 0x0, 0xf3, - 0xff, 0xff, 0x3f, 0xff, - - /* U+E9F4 "" */ - 0x0, 0x7c, 0x0, 0x0, 0x9c, 0x0, 0x0, 0x38, - 0x0, 0x74, 0x20, 0x1d, 0xdc, 0xbd, 0x37, 0xbb, - 0xc3, 0xae, 0x1, 0x83, 0x0, 0x0, 0xea, 0x0, - 0x1, 0xab, 0x40, 0x1f, 0x2, 0xf4, 0x1b, 0x2, - 0xa4, 0xa, 0x0, 0xa0, - - /* U+E9F7 "" */ - 0x15, 0x55, 0x7, 0xaa, 0xac, 0xa0, 0x0, 0x9b, - 0xff, 0xfd, 0xa0, 0x0, 0x9a, 0x0, 0x9, 0xa0, - 0x0, 0x9a, 0x0, 0x9, 0x65, 0x55, 0xd2, 0xaa, - 0xa8, - - /* U+EA07 "" */ - 0x6, 0xf9, 0x2, 0xea, 0xb8, 0x73, 0x1c, 0xdb, - 0xff, 0xfe, 0xc3, 0xc, 0x3c, 0x30, 0xc3, 0xbf, - 0xff, 0xe7, 0x31, 0xcd, 0x2e, 0xab, 0x80, 0x6f, - 0x90, - - /* U+EAD6 "" */ - 0x15, 0x55, 0x7, 0xaa, 0xac, 0xa0, 0x0, 0x9a, - 0x4, 0x9, 0xa6, 0x86, 0x9a, 0x68, 0xd9, 0xa9, - 0x94, 0x9a, 0x0, 0x9, 0x65, 0x55, 0xd2, 0xaa, - 0xa8, - - /* U+EB8E "" */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0, 0x3c, - 0xa0, 0x3, 0xc3, 0x40, 0x3c, 0xa1, 0x93, 0xc0, - 0x19, 0x3f, 0xff, 0xff, - - /* U+EB97 "" */ - 0x15, 0x55, 0x4e, 0xaa, 0xab, 0xc0, 0x0, 0x3c, - 0xaa, 0x63, 0xc1, 0x0, 0x3c, 0xdf, 0xf3, 0xc1, - 0x0, 0x3d, 0x55, 0x57, 0x6b, 0xfe, 0x90, 0x2a, - 0x80, - - /* U+EBCC "" */ - 0x8, 0x2, 0x7, 0xff, 0xfc, 0x90, 0x0, 0xcb, - 0xff, 0xfc, 0x90, 0x0, 0xc9, 0x88, 0x8c, 0x90, - 0x0, 0xc9, 0x88, 0x8c, 0x90, 0x0, 0xc7, 0xff, - 0xfc, - - /* U+EC1C "" */ - 0x0, 0x30, 0x0, 0xe0, 0x3, 0xc0, 0xf, 0xc0, - 0x36, 0xfe, 0xbf, 0x9c, 0x3, 0xf0, 0x3, 0xc0, - 0xb, 0x0, 0xc, 0x0, - - /* U+EF40 "" */ - 0xf3, 0xcf, 0x3c, 0xf3, 0xc0, 0x0, 0x3, 0xcf, - 0x4, 0xf3, 0xcb, 0xc0, 0xa, 0xef, 0x6, 0xa3, - 0xc1, 0xe0, - - /* U+EF4A "" */ - 0x6, 0xf9, 0x2, 0xd0, 0x78, 0x70, 0x0, 0xd9, - 0x0, 0x6, 0xc0, 0x0, 0x3c, 0x0, 0x3, 0x90, - 0x0, 0x67, 0x0, 0xd, 0x2d, 0x7, 0x80, 0x6f, - 0x90, - - /* U+EF7A "" */ - 0x0, 0x0, 0x2, 0xfe, 0x0, 0x70, 0x34, 0x9, - 0x1, 0x80, 0x90, 0x18, 0x3, 0x47, 0x40, 0x1f, - 0xec, 0x0, 0x0, 0x70, 0x0, 0x1, 0xc0, 0x0, - 0x0, - - /* U+EFE6 "" */ - 0x0, 0x1, 0x1, 0xf8, 0x78, 0x24, 0xcf, 0xc2, - 0x4c, 0xfc, 0x24, 0xc3, 0x2, 0x4c, 0x30, 0x7c, - 0xc3, 0xb, 0xdc, 0x30, 0x7c, 0xa7, 0x2, 0x42, - 0x80, - - /* U+F028 "" */ - 0x7f, 0xff, 0xfc, 0x90, 0x0, 0xc, 0x98, 0x88, - 0x8c, 0x90, 0x0, 0xc, 0x98, 0x88, 0x8c, 0x90, - 0x54, 0xc, 0x90, 0x54, 0xc, 0x7f, 0xff, 0xfc, - - /* U+F090 "" */ - 0x2, 0x0, 0x2, 0x40, 0x2, 0x40, 0x1a, 0x70, - 0xb, 0xd0, 0x42, 0x41, 0xc0, 0x3, 0xff, 0xff, - - /* U+F15C "" */ - 0x0, 0xbd, 0x0, 0x3, 0x43, 0x40, 0x9, 0x0, - 0xc0, 0x38, 0x0, 0xd0, 0xa0, 0x0, 0x68, 0x90, - 0x0, 0xc, 0x70, 0x0, 0xc, 0x1f, 0xff, 0xf4, - - /* U+F720 "" */ - 0x1, 0xe0, 0x7, 0x8b, 0x47, 0x40, 0x3a, 0xf0, - 0x2f, 0x97, 0xb4, 0xe4, 0x30, 0x39, 0xc, 0xd, - 0xd3, 0xe, 0x1e, 0xed, 0x0, 0xb8, 0x0, - - /* U+F8C7 "" */ - 0x0, 0x80, 0x0, 0x9, 0x0, 0x70, 0x91, 0xcd, - 0x9, 0xd, 0xc0, 0x90, 0xac, 0x4, 0x6, 0xd0, - 0x0, 0x97, 0x0, 0x1c, 0x2c, 0x7, 0x0, 0x7f, - 0x80, - - /* U+FFF75 "󿽵" */ - 0xff, 0xff, 0xec, 0x41, 0x13, 0xd5, 0x55, 0x7a, - 0xaf, 0xef, 0xb, 0xd1, 0x3b, 0x81, 0x2e, 0xd5, - 0x7f, 0x5e, 0xaa, 0xab, 0xc4, 0x11, 0x3b, 0xff, - 0xff -}; - - -/*--------------------- - * GLYPH DESCRIPTION - *--------------------*/ - -static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { - {.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */, - {.bitmap_index = 0, .adv_w = 192, .box_w = 8, .box_h = 8, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 16, .adv_w = 192, .box_w = 10, .box_h = 8, .ofs_x = 1, .ofs_y = 2}, - {.bitmap_index = 36, .adv_w = 192, .box_w = 7, .box_h = 10, .ofs_x = 2, .ofs_y = 1}, - {.bitmap_index = 54, .adv_w = 192, .box_w = 8, .box_h = 10, .ofs_x = 2, .ofs_y = 1}, - {.bitmap_index = 74, .adv_w = 192, .box_w = 11, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 107, .adv_w = 192, .box_w = 10, .box_h = 8, .ofs_x = 1, .ofs_y = 2}, - {.bitmap_index = 127, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 152, .adv_w = 192, .box_w = 6, .box_h = 4, .ofs_x = 3, .ofs_y = 4}, - {.bitmap_index = 158, .adv_w = 192, .box_w = 10, .box_h = 8, .ofs_x = 1, .ofs_y = 2}, - {.bitmap_index = 178, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 203, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 228, .adv_w = 192, .box_w = 6, .box_h = 10, .ofs_x = 3, .ofs_y = 1}, - {.bitmap_index = 243, .adv_w = 192, .box_w = 8, .box_h = 10, .ofs_x = 2, .ofs_y = 1}, - {.bitmap_index = 263, .adv_w = 192, .box_w = 8, .box_h = 8, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 279, .adv_w = 192, .box_w = 8, .box_h = 8, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 295, .adv_w = 192, .box_w = 10, .box_h = 6, .ofs_x = 1, .ofs_y = 3}, - {.bitmap_index = 310, .adv_w = 192, .box_w = 2, .box_h = 8, .ofs_x = 5, .ofs_y = 2}, - {.bitmap_index = 314, .adv_w = 192, .box_w = 8, .box_h = 8, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 330, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 357, .adv_w = 192, .box_w = 8, .box_h = 6, .ofs_x = 2, .ofs_y = 3}, - {.bitmap_index = 369, .adv_w = 192, .box_w = 9, .box_h = 8, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 387, .adv_w = 192, .box_w = 10, .box_h = 9, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 410, .adv_w = 192, .box_w = 8, .box_h = 10, .ofs_x = 2, .ofs_y = 1}, - {.bitmap_index = 430, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 455, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 480, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 505, .adv_w = 192, .box_w = 8, .box_h = 10, .ofs_x = 2, .ofs_y = 1}, - {.bitmap_index = 525, .adv_w = 192, .box_w = 8, .box_h = 10, .ofs_x = 2, .ofs_y = 1}, - {.bitmap_index = 545, .adv_w = 192, .box_w = 10, .box_h = 8, .ofs_x = 1, .ofs_y = 2}, - {.bitmap_index = 565, .adv_w = 192, .box_w = 12, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 601, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 626, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 651, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 676, .adv_w = 192, .box_w = 10, .box_h = 8, .ofs_x = 1, .ofs_y = 2}, - {.bitmap_index = 696, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 721, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 746, .adv_w = 192, .box_w = 8, .box_h = 10, .ofs_x = 2, .ofs_y = 1}, - {.bitmap_index = 766, .adv_w = 192, .box_w = 9, .box_h = 8, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 784, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 809, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 834, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 859, .adv_w = 192, .box_w = 12, .box_h = 8, .ofs_x = 0, .ofs_y = 2}, - {.bitmap_index = 883, .adv_w = 192, .box_w = 8, .box_h = 8, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 899, .adv_w = 192, .box_w = 12, .box_h = 8, .ofs_x = 0, .ofs_y = 2}, - {.bitmap_index = 923, .adv_w = 192, .box_w = 9, .box_h = 10, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 946, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 971, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1} -}; - -/*--------------------- - * CHARACTER MAPPING - *--------------------*/ - -static const uint16_t unicode_list_0[] = { - 0x0, 0x14, 0x62, 0x9b, 0x148, 0x182, 0x1ca, 0x1d1, - 0x1e1, 0x26a, 0x2af, 0x2c0, 0x418, 0x47e, 0x488, 0x48d, - 0x48f, 0x490, 0x4f9, 0x523, 0x600, 0x62b, 0x757, 0x76a, - 0x773, 0x7b8, 0x7ca, 0x7e9, 0x874, 0x8af, 0x8b2, 0x8c2, - 0x991, 0xa49, 0xa52, 0xa87, 0xad7, 0xdfb, 0xe05, 0xe35, - 0xea1, 0xee3, 0xf4b, 0x1017, 0x15db, 0x1782 -}; - -/*Collect the unicode lists and glyph_id offsets*/ -static const lv_font_fmt_txt_cmap_t cmaps[] = -{ - { - .range_start = 57669, .range_length = 6019, .glyph_id_start = 1, - .unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 46, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY - }, - { - .range_start = 1048437, .range_length = 1, .glyph_id_start = 47, - .unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY - } -}; - - - -/*-------------------- - * ALL CUSTOM DATA - *--------------------*/ - -#if LVGL_VERSION_MAJOR == 8 -/*Store all the custom data of the font*/ -static lv_font_fmt_txt_glyph_cache_t cache; -#endif - -#if LVGL_VERSION_MAJOR >= 8 -static const lv_font_fmt_txt_dsc_t font_dsc = { -#else -static lv_font_fmt_txt_dsc_t font_dsc = { -#endif - .glyph_bitmap = glyph_bitmap, - .glyph_dsc = glyph_dsc, - .cmaps = cmaps, - .kern_dsc = NULL, - .kern_scale = 0, - .cmap_num = 2, - .bpp = 2, - .kern_classes = 0, - .bitmap_format = 0, -#if LVGL_VERSION_MAJOR == 8 - .cache = &cache -#endif -}; - - - -/*----------------- - * PUBLIC FONT - *----------------*/ - -/*Initialize a public general font descriptor*/ -#if LVGL_VERSION_MAJOR >= 8 -const lv_font_t material_symbols_shared_12 = { -#else -lv_font_t material_symbols_shared_12 = { -#endif - .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ - .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ - .line_height = 12, /*The maximum line height required by the font*/ - .base_line = 0, /*Baseline measured from the bottom of the line*/ -#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) - .subpx = LV_FONT_SUBPX_NONE, -#endif -#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 - .underline_position = 0, - .underline_thickness = 0, -#endif - .dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ -#if LV_VERSION_CHECK(8, 2, 0) || LVGL_VERSION_MAJOR >= 9 - .fallback = NULL, -#endif - .user_data = NULL, -}; - - - -#endif /*#if MATERIAL_SYMBOLS_SHARED_12*/ - diff --git a/Modules/lvgl-module/source-fonts/material_symbols_shared_16.c b/Modules/lvgl-module/source-fonts/material_symbols_shared_16.c deleted file mode 100644 index 6e9205b61..000000000 --- a/Modules/lvgl-module/source-fonts/material_symbols_shared_16.c +++ /dev/null @@ -1,521 +0,0 @@ -/******************************************************************************* - * Size: 16 px - * Bpp: 2 - * Opts: --no-compress --no-prefilter --bpp 2 --size 16 --font MaterialSymbolsRounded.ttf -r 0xE145,0xE5C3,0xE770,0xEF40,0xEBCC,0xEFE6,0xEF4A,0xE5CD,0xF15C,0xE668,0xE92E,0xE326,0xEB97,0xE745,0xEC1C,0xE2C7,0xF720,0xF090,0xE8AF,0xE30F,0xE8FD,0xE9F4,0xE3F4,0xE316,0xE90F,0xEA07,0xE9B9,0xE159,0xE5D2,0xE28D,0xE5D4,0xE405,0xE89C,0xF8C7,0xE5D5,0xEF7A,0xE8B8,0xE9F7,0xE55D,0xF028,0xE1E0,0xE63E,0xE1A7,0xEB8E,0xEAD6,0xE3AF,0xFFF75 --format lvgl -o source-fonts/material_symbols_shared_16.c --force-fast-kern-format - ******************************************************************************/ - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -#ifndef MATERIAL_SYMBOLS_SHARED_16 -#define MATERIAL_SYMBOLS_SHARED_16 1 -#endif - -#if MATERIAL_SYMBOLS_SHARED_16 - -/*----------------- - * BITMAPS - *----------------*/ - -/*Store the image of the glyphs*/ -static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { - /* U+E145 "" */ - 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0xe0, 0x0, - 0xe, 0x0, 0x15, 0xf5, 0x4b, 0xff, 0xfd, 0x0, - 0xe0, 0x0, 0xe, 0x0, 0x0, 0xe0, 0x0, 0x9, - 0x0, - - /* U+E159 "" */ - 0x15, 0x55, 0x55, 0xb, 0xff, 0xff, 0xfd, 0xf4, - 0x0, 0x2, 0xde, 0xe0, 0x1, 0xed, 0xd2, 0xd0, - 0xf4, 0xdd, 0x7, 0xf8, 0xd, 0xd0, 0x4, 0x0, - 0xdd, 0x0, 0x0, 0xd, 0xd0, 0x0, 0x0, 0xdd, - 0x0, 0x0, 0xd, 0xbf, 0xff, 0xff, 0xd1, 0x55, - 0x55, 0x50, - - /* U+E1A7 "" */ - 0x0, 0x40, 0x0, 0x3c, 0x1, 0xf, 0xc1, 0xd3, - 0x6c, 0x1d, 0xef, 0x1, 0xff, 0x0, 0x1f, 0x0, - 0xf, 0xd0, 0xf, 0xfd, 0xf, 0x36, 0xcb, 0xe, - 0xe0, 0x3, 0xe0, 0x0, 0xe0, 0x0, 0x0, 0x0, - - /* U+E1E0 "" */ - 0x0, 0x0, 0x0, 0xe, 0x0, 0x2, 0xf0, 0x0, - 0xe, 0x0, 0x10, 0xd1, 0x5b, 0xcd, 0x3e, 0x78, - 0xd3, 0xe3, 0x4d, 0x1c, 0x39, 0xe6, 0xc2, 0xff, - 0xf4, 0x0, 0xd0, 0x0, 0xe, 0x0, 0x1, 0xf0, - 0x0, 0xe, 0x0, - - /* U+E28D "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xe0, 0x0, - 0x0, 0xd, 0x70, 0x0, 0x0, 0xd, 0x70, 0x0, - 0x0, 0xd, 0x70, 0x0, 0x0, 0xd, 0x70, 0x0, - 0x0, 0xd, 0x70, 0x0, 0x6, 0xaf, 0xfa, 0x90, - 0xf, 0xaa, 0xaa, 0xf0, 0xd, 0x0, 0x0, 0x70, - 0xf, 0xff, 0xff, 0xf0, 0x1d, 0x55, 0x55, 0x74, - 0x28, 0xc2, 0x83, 0x28, 0x34, 0xd2, 0x87, 0x1c, - 0x3f, 0xff, 0xff, 0xfc, 0x5, 0x55, 0x55, 0x50, - - /* U+E2C7 "" */ - 0x15, 0x40, 0x0, 0xb, 0xff, 0x40, 0x0, 0xd0, - 0x2f, 0xff, 0xcd, 0x0, 0x55, 0x5d, 0xd0, 0x0, - 0x0, 0xdd, 0x0, 0x0, 0xd, 0xd0, 0x0, 0x0, - 0xdd, 0x0, 0x0, 0xd, 0xd0, 0x0, 0x0, 0xdd, - 0x0, 0x0, 0xd, 0xbf, 0xff, 0xff, 0xd1, 0x55, - 0x55, 0x50, - - /* U+E30F "" */ - 0x0, 0x15, 0x40, 0x0, 0x3, 0xfc, 0x0, 0x0, - 0x31, 0xc0, 0x0, 0x3, 0x2c, 0x0, 0x0, 0x3f, - 0x80, 0xf, 0xf4, 0xe2, 0xfd, 0xe6, 0xd0, 0xb5, - 0xde, 0x6d, 0xb, 0x5d, 0xff, 0x44, 0x2f, 0xd0, - 0x2, 0xf0, 0x0, 0x0, 0x36, 0xc0, 0x0, 0x3, - 0x1c, 0x0, 0x0, 0x3a, 0xc0, 0x0, 0x3, 0xf8, - 0x0, - - /* U+E316 "" */ - 0x0, 0x0, 0x7, 0xc0, 0x1e, 0xb0, 0x78, 0x2c, - 0xa0, 0xa, - - /* U+E326 "" */ - 0x5, 0x55, 0x55, 0x3, 0xff, 0xff, 0xfc, 0x34, - 0x0, 0x0, 0x3, 0x40, 0x1, 0x54, 0x34, 0x0, - 0xff, 0xd3, 0x40, 0xd, 0x4d, 0x34, 0x0, 0xd0, - 0xd3, 0x40, 0xd, 0xd, 0x3f, 0xfc, 0xd0, 0xd0, - 0x55, 0xd, 0xd, 0xbf, 0xfc, 0xff, 0xd1, 0x55, - 0x1, 0x54, - - /* U+E3AF "" */ - 0x0, 0x15, 0x40, 0x0, 0x1f, 0xff, 0x40, 0xb, - 0x42, 0x2e, 0x2, 0xd0, 0x50, 0x34, 0x36, 0xc, - 0x1, 0xcb, 0x1a, 0xfe, 0xad, 0xa0, 0xbf, 0xc0, - 0xea, 0x3, 0xfd, 0xe, 0xba, 0xbf, 0x60, 0xd7, - 0x0, 0x30, 0x9c, 0x3c, 0x9, 0xb, 0x80, 0xf4, - 0x80, 0xf0, 0x3, 0xfa, 0xfc, 0x0, 0x6, 0xf9, - 0x0, - - /* U+E3F4 "" */ - 0xbf, 0xff, 0xfe, 0xe5, 0x55, 0x5b, 0xd0, 0x0, - 0x7, 0xd0, 0x0, 0x7, 0xd0, 0x0, 0x7, 0xd0, - 0x0, 0x7, 0xd0, 0x2, 0x7, 0xd2, 0x8b, 0x87, - 0xd7, 0xef, 0xd7, 0xd1, 0x55, 0x47, 0xe5, 0x55, - 0x5b, 0xbf, 0xff, 0xfe, - - /* U+E405 "" */ - 0x0, 0xff, 0x0, 0xff, 0x0, 0xfa, 0x0, 0xd0, - 0x0, 0xd0, 0x0, 0xd0, 0x4, 0xd0, 0x3f, 0xd0, - 0xff, 0xd0, 0xff, 0xd0, 0xbf, 0xc0, 0x2f, 0x0, - - /* U+E55D "" */ - 0x0, 0x14, 0x0, 0x0, 0x3c, 0x0, 0x0, 0x7d, - 0x0, 0x0, 0xeb, 0x0, 0x1, 0xc3, 0x40, 0x2, - 0x82, 0x80, 0x3, 0x41, 0xc0, 0xb, 0x0, 0xe0, - 0xd, 0x14, 0x70, 0x2d, 0xff, 0x78, 0x3f, 0x82, - 0xfc, 0x34, 0x0, 0x1c, - - /* U+E5C3 "" */ - 0x14, 0x14, 0x14, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, - 0x3c, 0x0, 0x0, 0x0, 0x14, 0x14, 0x14, 0x3d, - 0x3d, 0x3d, 0x3c, 0x3c, 0x3c, 0x0, 0x0, 0x0, - 0x14, 0x14, 0x14, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, - 0x3c, 0x0, 0x0, 0x0, - - /* U+E5CD "" */ - 0x20, 0x0, 0x43, 0xc0, 0x1d, 0xf, 0x7, 0x40, - 0x3e, 0xd0, 0x0, 0xf4, 0x0, 0x1f, 0xc0, 0x7, - 0x4f, 0x1, 0xd0, 0x3c, 0x34, 0x0, 0xd0, 0x0, - 0x0, - - /* U+E5D2 "" */ - 0xff, 0xff, 0xff, 0x15, 0x55, 0x54, 0x0, 0x0, - 0x0, 0x55, 0x55, 0x55, 0xff, 0xff, 0xfe, 0x0, - 0x0, 0x0, 0x15, 0x55, 0x54, 0xff, 0xff, 0xff, - - /* U+E5D4 "" */ - 0x14, 0x3d, 0x3c, 0x0, 0x14, 0x3d, 0x3c, 0x0, - 0x14, 0x3d, 0x3c, 0x0, - - /* U+E5D5 "" */ - 0x0, 0x14, 0x0, 0x2, 0xff, 0x8d, 0xf, 0x41, - 0xfd, 0x2c, 0x0, 0x3d, 0x34, 0x3, 0xfd, 0x70, - 0x1, 0x54, 0x70, 0x0, 0x0, 0x34, 0x0, 0x4, - 0x2c, 0x0, 0x38, 0xf, 0x41, 0xf0, 0x2, 0xff, - 0x80, 0x0, 0x14, 0x0, - - /* U+E63E "" */ - 0x0, 0x0, 0x0, 0x0, 0x1, 0xbf, 0xfe, 0x0, - 0xf, 0xff, 0xff, 0xe0, 0x7f, 0x40, 0x6, 0xfc, - 0xb8, 0x0, 0x0, 0x3d, 0x0, 0x7f, 0xf8, 0x0, - 0x2, 0xff, 0xff, 0x40, 0x2, 0xd0, 0xb, 0x40, - 0x0, 0x1, 0x0, 0x0, 0x0, 0xb, 0xc0, 0x0, - 0x0, 0xf, 0xd0, 0x0, 0x0, 0x7, 0xc0, 0x0, - - /* U+E668 "" */ - 0x0, 0x0, 0x8, 0x0, 0x0, 0x3c, 0x0, 0x0, - 0xf0, 0x10, 0x3, 0xc0, 0x38, 0xf, 0x0, 0xe, - 0x3c, 0x0, 0x3, 0xf0, 0x0, 0x0, 0x80, 0x0, - - /* U+E745 "" */ - 0x15, 0x55, 0x0, 0xf, 0xff, 0xc0, 0x0, 0x0, - 0x0, 0x0, 0x55, 0x54, 0x0, 0x3f, 0xff, 0x0, - 0x0, 0x0, 0x1, 0x43, 0xfd, 0x1, 0xf8, 0x55, - 0x1, 0xfe, 0x0, 0x1, 0xce, 0x0, 0x0, 0xce, - 0x0, 0x0, 0x3e, 0x0, 0x0, 0x0, 0x0, - - /* U+E770 "" */ - 0x0, 0x4, 0x0, 0x0, 0x3f, 0x0, 0x0, 0xf3, - 0xd4, 0x82, 0xc0, 0xbf, 0xfb, 0x40, 0x7, 0xee, - 0x0, 0x7, 0xd0, 0x2c, 0x7, 0xd0, 0x7f, 0x47, - 0xf4, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x55, 0x55, 0x55, - - /* U+E89C "" */ - 0x15, 0x54, 0x0, 0x3f, 0xff, 0x40, 0x70, 0x7, - 0xd0, 0x70, 0x7, 0xf4, 0x70, 0x7, 0xfc, 0x70, - 0x0, 0xd, 0x70, 0x28, 0xd, 0x70, 0x28, 0xd, - 0x72, 0xff, 0x8d, 0x70, 0x28, 0xd, 0x70, 0x28, - 0xd, 0x70, 0x0, 0xd, 0x75, 0x55, 0x5d, 0x2f, - 0xff, 0xf8, - - /* U+E8AF "" */ - 0x15, 0x55, 0x40, 0xf, 0xff, 0xff, 0x0, 0xd0, - 0x0, 0x30, 0xd, 0x0, 0x3, 0x28, 0xd0, 0x0, - 0x33, 0xcd, 0x0, 0x3, 0x3c, 0xd5, 0x55, 0xb3, - 0xcf, 0xff, 0xfe, 0x3c, 0xf0, 0x0, 0x3, 0xc0, - 0x7f, 0xff, 0xfc, 0x3, 0xff, 0xff, 0xc0, 0x0, - 0x0, 0x3c, 0x0, 0x0, 0x0, 0x80, - - /* U+E8B8 "" */ - 0x0, 0x5, 0x0, 0x0, 0x3, 0xfc, 0x0, 0x4, - 0x35, 0xc1, 0x2, 0xff, 0xf, 0xf8, 0x35, 0x40, - 0x15, 0xc3, 0x81, 0xf4, 0x2c, 0x1d, 0x3f, 0xc7, - 0x40, 0xd3, 0xfd, 0x70, 0x3c, 0x3f, 0xc3, 0xc7, - 0x0, 0x50, 0xd, 0x3f, 0xd0, 0x7f, 0xc0, 0xeb, - 0xe, 0xb0, 0x0, 0x3a, 0xc0, 0x0, 0x2, 0xf8, - 0x0, - - /* U+E8FD "" */ - 0x0, 0x15, 0x40, 0x0, 0x2f, 0xff, 0x40, 0xb, - 0x40, 0x2e, 0x2, 0xc1, 0xa4, 0x74, 0x34, 0x20, - 0xc1, 0xcb, 0x0, 0x1c, 0xd, 0xa0, 0x3, 0x40, - 0xea, 0x0, 0xa0, 0xe, 0xa0, 0x0, 0x0, 0xd7, - 0x0, 0x90, 0x1c, 0x38, 0xe, 0x3, 0x80, 0xe0, - 0x0, 0xf0, 0x3, 0xea, 0xbc, 0x0, 0x6, 0xf9, - 0x0, - - /* U+E90F "" */ - 0x0, 0x50, 0x0, 0xff, 0xf0, 0x3c, 0x3, 0xcb, - 0x0, 0xe, 0xd0, 0x0, 0x7d, 0x0, 0x7, 0xd0, - 0x0, 0x7b, 0x0, 0xe, 0x39, 0x57, 0xc0, 0xff, - 0xf0, 0x1, 0x54, 0x0, 0xbf, 0xd0, 0x0, 0x50, - 0x0, 0xe, 0x0, - - /* U+E92E "" */ - 0x15, 0xff, 0x54, 0x3f, 0xff, 0xfd, 0x28, 0x0, - 0x28, 0x28, 0x82, 0x28, 0x28, 0xd7, 0x28, 0x28, - 0xd7, 0x28, 0x28, 0xd7, 0x28, 0x28, 0xd7, 0x28, - 0x28, 0xd7, 0x28, 0x28, 0x0, 0x28, 0x2d, 0x55, - 0x68, 0x1f, 0xff, 0xf4, - - /* U+E9B9 "" */ - 0x10, 0x1a, 0xaa, 0x4b, 0xcb, 0xff, 0xfd, 0x78, - 0x7f, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x10, 0x1a, - 0xaa, 0x4b, 0xcb, 0xff, 0xfd, 0x78, 0x7f, 0xff, - 0xd0, 0x0, 0x0, 0x0, 0x10, 0x1a, 0xaa, 0x4b, - 0xcb, 0xff, 0xfd, 0x78, 0x7f, 0xff, 0xd0, 0x0, - 0x0, 0x0, - - /* U+E9F4 "" */ - 0x0, 0x7, 0xd0, 0x0, 0x0, 0xe, 0xb0, 0x0, - 0x0, 0xe, 0xb0, 0x0, 0x0, 0x7, 0xd0, 0x0, - 0x28, 0x2, 0x80, 0x28, 0xff, 0x3, 0xc0, 0xff, - 0xd7, 0x5f, 0xf5, 0xd7, 0xbe, 0xb8, 0x2e, 0xbe, - 0x0, 0x34, 0x1c, 0x0, 0x0, 0x3c, 0x3c, 0x0, - 0x0, 0x1f, 0xf4, 0x0, 0x1, 0x75, 0x5d, 0x40, - 0xb, 0xf0, 0xf, 0xe0, 0xd, 0x70, 0xd, 0x70, - 0xb, 0xe0, 0xb, 0xe0, 0x0, 0x0, 0x0, 0x0, - - /* U+E9F7 "" */ - 0xbf, 0xff, 0xfe, 0xe5, 0x55, 0x5b, 0xd0, 0x0, - 0x7, 0xe5, 0x55, 0x5b, 0xff, 0xff, 0xff, 0xd0, - 0x0, 0x7, 0xd0, 0x0, 0x7, 0xd0, 0x0, 0x7, - 0xd0, 0x0, 0x7, 0xd0, 0x0, 0x7, 0xe5, 0x55, - 0x5b, 0xbf, 0xff, 0xfe, - - /* U+EA07 "" */ - 0x0, 0x15, 0x0, 0x0, 0x1f, 0xff, 0x40, 0xb, - 0xba, 0xee, 0x2, 0xc7, 0xc, 0x74, 0x39, 0xf5, - 0xe7, 0xcb, 0xff, 0xff, 0xfd, 0xa0, 0xd0, 0x70, - 0xea, 0xc, 0x7, 0xe, 0xb5, 0xe5, 0xb5, 0xd7, - 0xff, 0xff, 0xfc, 0x3c, 0xb0, 0xd3, 0x80, 0xe7, - 0x5c, 0xf0, 0x3, 0xff, 0xfc, 0x0, 0x6, 0xf9, - 0x0, - - /* U+EAD6 "" */ - 0xbf, 0xff, 0xfe, 0xe5, 0x55, 0x5b, 0xd0, 0x0, - 0x7, 0xd0, 0x0, 0x7, 0xdf, 0x7a, 0x27, 0xdc, - 0xa1, 0x77, 0xdc, 0xa0, 0xe7, 0xdf, 0x78, 0xc7, - 0xd0, 0x0, 0x7, 0xd0, 0x0, 0x7, 0xe5, 0x55, - 0x5b, 0xbf, 0xff, 0xfe, - - /* U+EB8E "" */ - 0x2a, 0xaa, 0xaa, 0x4f, 0xff, 0xff, 0xfd, 0xff, - 0xff, 0xff, 0xde, 0x0, 0x0, 0xd, 0xd2, 0x40, - 0x0, 0xdd, 0x1d, 0x0, 0xd, 0xd0, 0xb0, 0x0, - 0xdd, 0x1e, 0x0, 0xd, 0xd2, 0x83, 0xf8, 0xdd, - 0x0, 0x15, 0xd, 0xbf, 0xff, 0xff, 0xd1, 0x55, - 0x55, 0x50, - - /* U+EB97 "" */ - 0x7f, 0xff, 0xff, 0xce, 0x55, 0x55, 0x5d, 0xd0, - 0x0, 0x0, 0xdd, 0x15, 0x53, 0x4d, 0xd1, 0x55, - 0x30, 0xdd, 0x8, 0x0, 0xd, 0xd3, 0xdf, 0xf8, - 0xdd, 0x1c, 0x55, 0xd, 0xd0, 0x0, 0x0, 0xde, - 0x55, 0x55, 0x5d, 0x7f, 0xff, 0xff, 0xc0, 0xf, - 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, - - /* U+EBCC "" */ - 0x8, 0x0, 0x20, 0x1e, 0x55, 0xb4, 0xff, 0xff, - 0xff, 0xd0, 0x0, 0x7, 0xe5, 0x55, 0x5b, 0xff, - 0xff, 0xff, 0xd0, 0x0, 0x7, 0xd3, 0x24, 0xc7, - 0xd0, 0x0, 0x7, 0xd0, 0x0, 0x7, 0xd3, 0x24, - 0xc7, 0xd0, 0x0, 0x7, 0xe5, 0x55, 0x5b, 0xbf, - 0xff, 0xfe, - - /* U+EC1C "" */ - 0x0, 0x0, 0x80, 0x0, 0x7, 0x80, 0x0, 0x1f, - 0x0, 0x0, 0x7e, 0x0, 0x1, 0xfc, 0x0, 0x7, - 0xbe, 0x50, 0x1e, 0x2b, 0xfc, 0x3f, 0xe8, 0x74, - 0x5, 0xbe, 0xd0, 0x0, 0x3f, 0x40, 0x0, 0xbd, - 0x0, 0x0, 0xf4, 0x0, 0x2, 0xd0, 0x0, 0x2, - 0x0, 0x0, - - /* U+EF40 "" */ - 0x14, 0x14, 0x14, 0xf, 0x4f, 0x4f, 0x43, 0xc3, - 0xc3, 0xc0, 0x0, 0x0, 0x0, 0x14, 0x14, 0x0, - 0xf, 0x4f, 0x42, 0x83, 0xc3, 0xc2, 0xf8, 0x0, - 0x2, 0xfd, 0x14, 0x2, 0x8d, 0xf, 0x40, 0xcd, - 0x3, 0xc0, 0x3d, 0x0, 0x0, 0x0, 0x0, - - /* U+EF4A "" */ - 0x0, 0x15, 0x40, 0x0, 0x2f, 0xff, 0x40, 0xb, - 0x40, 0x2e, 0x2, 0xc0, 0x0, 0x74, 0x34, 0x0, - 0x1, 0xcb, 0x0, 0x0, 0xd, 0xa0, 0x0, 0x0, - 0xea, 0x0, 0x0, 0xe, 0xa0, 0x0, 0x0, 0xd7, - 0x0, 0x0, 0x1c, 0x38, 0x0, 0x3, 0x80, 0xe0, - 0x0, 0xf0, 0x3, 0xea, 0xbc, 0x0, 0x6, 0xf9, - 0x0, - - /* U+EF7A "" */ - 0xb, 0xf4, 0x0, 0x3d, 0x6d, 0x0, 0xb0, 0x7, - 0x0, 0xe0, 0x3, 0x40, 0xd0, 0x3, 0x80, 0xe0, - 0x3, 0x40, 0xb0, 0xb, 0x0, 0x3e, 0xbf, 0x0, - 0x7, 0xe2, 0xc0, 0x0, 0x0, 0xb0, 0x0, 0x0, - 0x2c, 0x0, 0x0, 0x9, - - /* U+EFE6 "" */ - 0xb, 0xd0, 0x3c, 0x1d, 0xb0, 0xbe, 0x28, 0x34, - 0xff, 0x28, 0x34, 0xff, 0x28, 0x34, 0xbe, 0x28, - 0x34, 0x28, 0x28, 0x34, 0x28, 0xbe, 0x34, 0x28, - 0xff, 0x34, 0x28, 0xff, 0x38, 0x28, 0xbe, 0x2d, - 0xb4, 0x3c, 0xb, 0xd0, - - /* U+F028 "" */ - 0x5, 0x55, 0x55, 0x50, 0x3f, 0xff, 0xff, 0xfc, - 0x70, 0x0, 0x0, 0xd, 0x71, 0x48, 0x11, 0x4d, - 0x71, 0x48, 0x21, 0x4d, 0x70, 0x0, 0x0, 0xd, - 0x72, 0x8c, 0x72, 0x8d, 0x70, 0x0, 0x0, 0xd, - 0x70, 0x2f, 0xf8, 0xd, 0x70, 0x5, 0x50, 0xd, - 0x3f, 0xff, 0xff, 0xfc, 0x5, 0x55, 0x55, 0x50, - - /* U+F090 "" */ - 0x0, 0x0, 0x0, 0x0, 0x34, 0x0, 0x0, 0x34, - 0x0, 0x0, 0x34, 0x0, 0x0, 0x34, 0x0, 0x3, - 0xbb, 0x80, 0x1, 0xff, 0x0, 0x0, 0xbc, 0x0, - 0x30, 0x10, 0xc, 0x70, 0x0, 0xd, 0x3f, 0xff, - 0xfc, 0x5, 0x55, 0x50, - - /* U+F15C "" */ - 0x0, 0x1, 0x40, 0x0, 0x0, 0x2f, 0xf4, 0x0, - 0x0, 0xb4, 0x2d, 0x0, 0x1, 0xc0, 0xb, 0x0, - 0x7, 0xc0, 0x3, 0x40, 0x2e, 0x0, 0x3, 0xd0, - 0x34, 0x0, 0x2, 0xb8, 0x70, 0x0, 0x0, 0x1c, - 0x30, 0x0, 0x0, 0xd, 0x3c, 0x0, 0x0, 0x2c, - 0xf, 0xff, 0xff, 0xf4, 0x0, 0x55, 0x55, 0x40, - - /* U+F720 "" */ - 0x0, 0x10, 0x0, 0x1, 0xfe, 0x0, 0xb, 0x87, - 0xd0, 0x7c, 0x0, 0xbc, 0xf8, 0x0, 0x3e, 0xef, - 0x42, 0xee, 0xd2, 0xff, 0x4e, 0xd0, 0x38, 0xe, - 0xd0, 0x34, 0xe, 0xd0, 0x34, 0xe, 0xb4, 0x34, - 0x2d, 0x2f, 0x36, 0xf0, 0x2, 0xff, 0x40, 0x0, - 0x78, 0x0, - - /* U+F8C7 "" */ - 0x0, 0x4, 0x0, 0x0, 0x0, 0xd0, 0x0, 0x0, - 0xd, 0x0, 0x2, 0xc0, 0xd0, 0x70, 0x34, 0xd, - 0x3, 0x8b, 0x0, 0xd0, 0x1c, 0xa0, 0xd, 0x0, - 0xca, 0x0, 0x80, 0xc, 0xa0, 0x0, 0x0, 0xc7, - 0x0, 0x0, 0x2c, 0x38, 0x0, 0x3, 0x40, 0xe0, - 0x1, 0xe0, 0x3, 0xea, 0xf8, 0x0, 0x6, 0xf8, - 0x0, - - /* U+FFF75 "󿽵" */ - 0x55, 0x55, 0x55, 0xf, 0xff, 0xff, 0xfc, 0xd1, - 0x4, 0x4, 0xde, 0x55, 0x55, 0x5d, 0xff, 0xff, - 0xff, 0xd0, 0x7, 0xf4, 0xd, 0x1b, 0xe0, 0x21, - 0xd7, 0x90, 0x82, 0xf8, 0xe1, 0x7, 0xf8, 0xf, - 0xff, 0xff, 0xfd, 0xe5, 0x55, 0x55, 0xdd, 0x20, - 0x80, 0x8d, 0xb5, 0x55, 0x55, 0xd2, 0xff, 0xff, - 0xfd -}; - - -/*--------------------- - * GLYPH DESCRIPTION - *--------------------*/ - -static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { - {.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */, - {.bitmap_index = 0, .adv_w = 256, .box_w = 10, .box_h = 10, .ofs_x = 3, .ofs_y = 3}, - {.bitmap_index = 25, .adv_w = 256, .box_w = 14, .box_h = 12, .ofs_x = 1, .ofs_y = 2}, - {.bitmap_index = 67, .adv_w = 256, .box_w = 9, .box_h = 14, .ofs_x = 3, .ofs_y = 1}, - {.bitmap_index = 99, .adv_w = 256, .box_w = 10, .box_h = 14, .ofs_x = 3, .ofs_y = 1}, - {.bitmap_index = 134, .adv_w = 256, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 198, .adv_w = 256, .box_w = 14, .box_h = 12, .ofs_x = 1, .ofs_y = 2}, - {.bitmap_index = 240, .adv_w = 256, .box_w = 14, .box_h = 14, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 289, .adv_w = 256, .box_w = 8, .box_h = 5, .ofs_x = 4, .ofs_y = 6}, - {.bitmap_index = 299, .adv_w = 256, .box_w = 14, .box_h = 12, .ofs_x = 1, .ofs_y = 2}, - {.bitmap_index = 341, .adv_w = 256, .box_w = 14, .box_h = 14, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 390, .adv_w = 256, .box_w = 12, .box_h = 12, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 426, .adv_w = 256, .box_w = 8, .box_h = 12, .ofs_x = 4, .ofs_y = 2}, - {.bitmap_index = 450, .adv_w = 256, .box_w = 12, .box_h = 12, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 486, .adv_w = 256, .box_w = 12, .box_h = 12, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 522, .adv_w = 256, .box_w = 10, .box_h = 10, .ofs_x = 3, .ofs_y = 3}, - {.bitmap_index = 547, .adv_w = 256, .box_w = 12, .box_h = 8, .ofs_x = 2, .ofs_y = 4}, - {.bitmap_index = 571, .adv_w = 256, .box_w = 4, .box_h = 12, .ofs_x = 6, .ofs_y = 2}, - {.bitmap_index = 583, .adv_w = 256, .box_w = 12, .box_h = 12, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 619, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 2}, - {.bitmap_index = 667, .adv_w = 256, .box_w = 12, .box_h = 8, .ofs_x = 2, .ofs_y = 4}, - {.bitmap_index = 691, .adv_w = 256, .box_w = 13, .box_h = 12, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 730, .adv_w = 256, .box_w = 12, .box_h = 12, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 766, .adv_w = 256, .box_w = 12, .box_h = 14, .ofs_x = 2, .ofs_y = 1}, - {.bitmap_index = 808, .adv_w = 256, .box_w = 14, .box_h = 13, .ofs_x = 1, .ofs_y = 2}, - {.bitmap_index = 854, .adv_w = 256, .box_w = 14, .box_h = 14, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 903, .adv_w = 256, .box_w = 14, .box_h = 14, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 952, .adv_w = 256, .box_w = 10, .box_h = 14, .ofs_x = 3, .ofs_y = 1}, - {.bitmap_index = 987, .adv_w = 256, .box_w = 12, .box_h = 12, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 1023, .adv_w = 256, .box_w = 14, .box_h = 12, .ofs_x = 1, .ofs_y = 2}, - {.bitmap_index = 1065, .adv_w = 256, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 1129, .adv_w = 256, .box_w = 12, .box_h = 12, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 1165, .adv_w = 256, .box_w = 14, .box_h = 14, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 1214, .adv_w = 256, .box_w = 12, .box_h = 12, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 1250, .adv_w = 256, .box_w = 14, .box_h = 12, .ofs_x = 1, .ofs_y = 2}, - {.bitmap_index = 1292, .adv_w = 256, .box_w = 14, .box_h = 13, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 1338, .adv_w = 256, .box_w = 12, .box_h = 14, .ofs_x = 2, .ofs_y = 1}, - {.bitmap_index = 1380, .adv_w = 256, .box_w = 12, .box_h = 14, .ofs_x = 2, .ofs_y = 1}, - {.bitmap_index = 1422, .adv_w = 256, .box_w = 13, .box_h = 12, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 1461, .adv_w = 256, .box_w = 14, .box_h = 14, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 1510, .adv_w = 256, .box_w = 12, .box_h = 12, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 1546, .adv_w = 256, .box_w = 12, .box_h = 12, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 1582, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 2}, - {.bitmap_index = 1630, .adv_w = 256, .box_w = 12, .box_h = 12, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 1666, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 2}, - {.bitmap_index = 1714, .adv_w = 256, .box_w = 12, .box_h = 14, .ofs_x = 2, .ofs_y = 1}, - {.bitmap_index = 1756, .adv_w = 256, .box_w = 14, .box_h = 14, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 1805, .adv_w = 256, .box_w = 14, .box_h = 14, .ofs_x = 1, .ofs_y = 1} -}; - -/*--------------------- - * CHARACTER MAPPING - *--------------------*/ - -static const uint16_t unicode_list_0[] = { - 0x0, 0x14, 0x62, 0x9b, 0x148, 0x182, 0x1ca, 0x1d1, - 0x1e1, 0x26a, 0x2af, 0x2c0, 0x418, 0x47e, 0x488, 0x48d, - 0x48f, 0x490, 0x4f9, 0x523, 0x600, 0x62b, 0x757, 0x76a, - 0x773, 0x7b8, 0x7ca, 0x7e9, 0x874, 0x8af, 0x8b2, 0x8c2, - 0x991, 0xa49, 0xa52, 0xa87, 0xad7, 0xdfb, 0xe05, 0xe35, - 0xea1, 0xee3, 0xf4b, 0x1017, 0x15db, 0x1782 -}; - -/*Collect the unicode lists and glyph_id offsets*/ -static const lv_font_fmt_txt_cmap_t cmaps[] = -{ - { - .range_start = 57669, .range_length = 6019, .glyph_id_start = 1, - .unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 46, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY - }, - { - .range_start = 1048437, .range_length = 1, .glyph_id_start = 47, - .unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY - } -}; - - - -/*-------------------- - * ALL CUSTOM DATA - *--------------------*/ - -#if LVGL_VERSION_MAJOR == 8 -/*Store all the custom data of the font*/ -static lv_font_fmt_txt_glyph_cache_t cache; -#endif - -#if LVGL_VERSION_MAJOR >= 8 -static const lv_font_fmt_txt_dsc_t font_dsc = { -#else -static lv_font_fmt_txt_dsc_t font_dsc = { -#endif - .glyph_bitmap = glyph_bitmap, - .glyph_dsc = glyph_dsc, - .cmaps = cmaps, - .kern_dsc = NULL, - .kern_scale = 0, - .cmap_num = 2, - .bpp = 2, - .kern_classes = 0, - .bitmap_format = 0, -#if LVGL_VERSION_MAJOR == 8 - .cache = &cache -#endif -}; - - - -/*----------------- - * PUBLIC FONT - *----------------*/ - -/*Initialize a public general font descriptor*/ -#if LVGL_VERSION_MAJOR >= 8 -const lv_font_t material_symbols_shared_16 = { -#else -lv_font_t material_symbols_shared_16 = { -#endif - .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ - .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ - .line_height = 16, /*The maximum line height required by the font*/ - .base_line = 0, /*Baseline measured from the bottom of the line*/ -#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) - .subpx = LV_FONT_SUBPX_NONE, -#endif -#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 - .underline_position = 0, - .underline_thickness = 0, -#endif - .dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ -#if LV_VERSION_CHECK(8, 2, 0) || LVGL_VERSION_MAJOR >= 9 - .fallback = NULL, -#endif - .user_data = NULL, -}; - - - -#endif /*#if MATERIAL_SYMBOLS_SHARED_16*/ - diff --git a/Modules/lvgl-module/source-fonts/material_symbols_shared_20.c b/Modules/lvgl-module/source-fonts/material_symbols_shared_20.c deleted file mode 100644 index 9f8ca64e8..000000000 --- a/Modules/lvgl-module/source-fonts/material_symbols_shared_20.c +++ /dev/null @@ -1,644 +0,0 @@ -/******************************************************************************* - * Size: 20 px - * Bpp: 2 - * Opts: --no-compress --no-prefilter --bpp 2 --size 20 --font MaterialSymbolsRounded.ttf -r 0xE145,0xE5C3,0xE770,0xEF40,0xEBCC,0xEFE6,0xEF4A,0xE5CD,0xF15C,0xE668,0xE92E,0xE326,0xEB97,0xE745,0xEC1C,0xE2C7,0xF720,0xF090,0xE8AF,0xE30F,0xE8FD,0xE9F4,0xE3F4,0xE316,0xE90F,0xEA07,0xE9B9,0xE159,0xE5D2,0xE28D,0xE5D4,0xE405,0xE89C,0xF8C7,0xE5D5,0xEF7A,0xE8B8,0xE9F7,0xE55D,0xF028,0xE1E0,0xE63E,0xE1A7,0xEB8E,0xEAD6,0xE3AF,0xFFF75 --format lvgl -o source-fonts/material_symbols_shared_20.c --force-fast-kern-format - ******************************************************************************/ - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -#ifndef MATERIAL_SYMBOLS_SHARED_20 -#define MATERIAL_SYMBOLS_SHARED_20 1 -#endif - -#if MATERIAL_SYMBOLS_SHARED_20 - -/*----------------- - * BITMAPS - *----------------*/ - -/*Store the image of the glyphs*/ -static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { - /* U+E145 "" */ - 0x0, 0x14, 0x0, 0x0, 0x3c, 0x0, 0x0, 0x3c, - 0x0, 0x0, 0x3c, 0x0, 0x0, 0x3c, 0x0, 0x7f, - 0xff, 0xfd, 0xbf, 0xff, 0xfe, 0x0, 0x3c, 0x0, - 0x0, 0x3c, 0x0, 0x0, 0x3c, 0x0, 0x0, 0x3c, - 0x0, 0x0, 0x28, 0x0, - - /* U+E159 "" */ - 0x1a, 0xaa, 0xaa, 0xaa, 0x83, 0xff, 0xff, 0xff, - 0xfd, 0x3d, 0x0, 0x0, 0x2, 0xe3, 0xfc, 0x0, - 0x1, 0xfe, 0x39, 0xf8, 0x0, 0xf8, 0xe3, 0x82, - 0xf4, 0xbc, 0xe, 0x38, 0x3, 0xfd, 0x0, 0xe3, - 0x80, 0x6, 0x0, 0xe, 0x38, 0x0, 0x0, 0x0, - 0xe3, 0x80, 0x0, 0x0, 0xe, 0x38, 0x0, 0x0, - 0x0, 0xe3, 0x80, 0x0, 0x0, 0xe, 0x3f, 0xff, - 0xff, 0xff, 0xd1, 0xaa, 0xaa, 0xaa, 0xa8, - - /* U+E1A7 "" */ - 0x0, 0x28, 0x0, 0x0, 0xf8, 0x1, 0x3, 0xf8, - 0x1e, 0xe, 0xb8, 0x2e, 0x38, 0xf0, 0x2e, 0xfb, - 0x80, 0x2f, 0xf8, 0x0, 0x2f, 0x80, 0x0, 0xbe, - 0x0, 0xb, 0xfe, 0x0, 0xbb, 0xee, 0xb, 0x8e, - 0x3c, 0x78, 0x3a, 0xe0, 0x40, 0xfe, 0x0, 0x3, - 0xe0, 0x0, 0xa, 0x0, - - /* U+E1E0 "" */ - 0x0, 0x0, 0x0, 0x0, 0x28, 0x0, 0x0, 0x7d, - 0x0, 0x0, 0xff, 0x0, 0x0, 0x38, 0x0, 0x10, - 0x38, 0x14, 0xbc, 0x38, 0x7f, 0xfd, 0x38, 0x7f, - 0x7c, 0x38, 0x7f, 0x38, 0x38, 0x2c, 0x3d, 0x7d, - 0x6c, 0x2f, 0xff, 0xfc, 0x5, 0x7d, 0x50, 0x0, - 0x38, 0x0, 0x0, 0x3c, 0x0, 0x0, 0xbe, 0x0, - 0x0, 0x7d, 0x0, 0x0, 0x0, 0x0, - - /* U+E28D "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xe0, - 0x0, 0x0, 0x0, 0x7f, 0xd0, 0x0, 0x0, 0x2, - 0xc3, 0x80, 0x0, 0x0, 0xb, 0xe, 0x0, 0x0, - 0x0, 0x2c, 0x38, 0x0, 0x0, 0x0, 0xb0, 0xe0, - 0x0, 0x0, 0x2, 0xc3, 0x80, 0x0, 0x0, 0xb, - 0xe, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xf8, 0x2, - 0xff, 0xff, 0xff, 0xf8, 0xb, 0x0, 0x0, 0x0, - 0xe0, 0x2e, 0xaa, 0xaa, 0xab, 0x80, 0xff, 0xff, - 0xff, 0xff, 0x3, 0x80, 0x0, 0x0, 0x2c, 0x1d, - 0x34, 0x3c, 0x1c, 0x74, 0xb0, 0xe0, 0xf0, 0xb0, - 0xe2, 0xeb, 0xeb, 0xeb, 0xeb, 0xc7, 0xff, 0xff, - 0xff, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, - - /* U+E2C7 "" */ - 0x1a, 0xa9, 0x0, 0x0, 0x3, 0xff, 0xf8, 0x0, - 0x0, 0x38, 0x2, 0xff, 0xff, 0xc3, 0x80, 0xa, - 0xaa, 0xae, 0x38, 0x0, 0x0, 0x0, 0xe3, 0x80, - 0x0, 0x0, 0xe, 0x38, 0x0, 0x0, 0x0, 0xe3, - 0x80, 0x0, 0x0, 0xe, 0x38, 0x0, 0x0, 0x0, - 0xe3, 0x80, 0x0, 0x0, 0xe, 0x38, 0x0, 0x0, - 0x0, 0xe3, 0x80, 0x0, 0x0, 0xe, 0x3f, 0xff, - 0xff, 0xff, 0xd1, 0xaa, 0xaa, 0xaa, 0xa8, - - /* U+E30F "" */ - 0x0, 0x1, 0xa8, 0x0, 0x0, 0x0, 0x3f, 0xe0, - 0x0, 0x0, 0x3, 0x8e, 0x0, 0x0, 0x0, 0x38, - 0xe0, 0x0, 0x0, 0x3, 0xce, 0x0, 0x0, 0x0, - 0x2f, 0xd0, 0x0, 0x2a, 0xa0, 0xb4, 0x2a, 0x83, - 0xff, 0x80, 0xf, 0xfe, 0x38, 0x2d, 0x3, 0xd0, - 0xe3, 0x82, 0xd0, 0x3d, 0xe, 0x3f, 0xf8, 0x20, - 0xff, 0xe1, 0xa9, 0xf, 0x82, 0xa8, 0x0, 0x3, - 0xfe, 0x0, 0x0, 0x0, 0x38, 0xe0, 0x0, 0x0, - 0x3, 0x8e, 0x0, 0x0, 0x0, 0x3e, 0xe0, 0x0, - 0x0, 0x3, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, - - /* U+E316 "" */ - 0x0, 0xe0, 0x0, 0x3f, 0x80, 0xf, 0x6e, 0x3, - 0xd0, 0xb8, 0xb4, 0x2, 0xd1, 0x0, 0x4, - - /* U+E326 "" */ - 0x6, 0xaa, 0xaa, 0xaa, 0x1, 0xff, 0xff, 0xff, - 0xf4, 0x2c, 0x0, 0x0, 0x0, 0x2, 0xc0, 0x0, - 0x1a, 0xa4, 0x2c, 0x0, 0x3, 0xff, 0xd2, 0xc0, - 0x0, 0x38, 0xe, 0x2c, 0x0, 0x3, 0x98, 0xe2, - 0xc0, 0x0, 0x38, 0xe, 0x2c, 0x0, 0x3, 0x80, - 0xe1, 0xea, 0xa4, 0x38, 0xe, 0xf, 0xff, 0xc3, - 0x80, 0xe0, 0x0, 0x0, 0x38, 0xe, 0x3f, 0xff, - 0xc3, 0xff, 0xe2, 0xaa, 0xa4, 0x1a, 0xa8, - - /* U+E3AF "" */ - 0x0, 0x1, 0x54, 0x0, 0x0, 0x2, 0xff, 0xfc, - 0x0, 0x1, 0xf9, 0x1e, 0xf4, 0x0, 0x7c, 0x2, - 0x3, 0xd0, 0xf, 0x80, 0x20, 0xf, 0x2, 0xd8, - 0x8, 0x0, 0x38, 0x3c, 0x21, 0xea, 0xab, 0xc3, - 0x82, 0x7f, 0xd0, 0x1d, 0x34, 0xf, 0xff, 0x1, - 0xd3, 0x40, 0xbf, 0xf4, 0x1d, 0x38, 0x7, 0xfc, - 0xc1, 0xc3, 0xea, 0xab, 0x46, 0x3c, 0x1d, 0x0, - 0x20, 0x3b, 0x80, 0xb0, 0x5, 0x1, 0xf0, 0x3, - 0xc0, 0x80, 0x7c, 0x0, 0xb, 0xaa, 0xbf, 0x0, - 0x0, 0x1b, 0xfe, 0x40, 0x0, 0x0, 0x0, 0x0, - 0x0, - - /* U+E3F4 "" */ - 0x1a, 0xaa, 0xaa, 0xa4, 0x7f, 0xff, 0xff, 0xfd, - 0xb0, 0x0, 0x0, 0xe, 0xb0, 0x0, 0x0, 0xe, - 0xb0, 0x0, 0x0, 0xe, 0xb0, 0x0, 0x0, 0xe, - 0xb0, 0x0, 0x0, 0xe, 0xb0, 0x0, 0x0, 0xe, - 0xb0, 0x0, 0x24, 0xe, 0xb0, 0x30, 0x7c, 0xe, - 0xb0, 0xf8, 0xfe, 0xe, 0xb1, 0xff, 0xff, 0x4e, - 0xb0, 0x55, 0x55, 0xe, 0xb0, 0x0, 0x0, 0xe, - 0x7f, 0xff, 0xff, 0xfd, 0x1a, 0xaa, 0xaa, 0xa4, - - /* U+E405 "" */ - 0x0, 0x5, 0x40, 0x3, 0xff, 0x0, 0x3f, 0xf0, - 0x3, 0xff, 0x0, 0x38, 0x0, 0x3, 0x80, 0x0, - 0x38, 0x0, 0x3, 0x80, 0x0, 0x38, 0x2, 0xff, - 0x80, 0x7f, 0xf8, 0xf, 0xff, 0x80, 0xff, 0xf8, - 0xb, 0xff, 0x40, 0x3f, 0xe0, 0x0, 0x54, 0x0, - - /* U+E55D "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf0, 0x0, 0x0, - 0x1f, 0x40, 0x0, 0x2, 0xf8, 0x0, 0x0, 0x3a, - 0xc0, 0x0, 0xb, 0xe, 0x0, 0x0, 0xf0, 0xf0, - 0x0, 0x1d, 0x7, 0x40, 0x3, 0xc0, 0x3c, 0x0, - 0x74, 0x1, 0xd0, 0xf, 0x0, 0xf, 0x1, 0xe0, - 0xa0, 0xb4, 0x2d, 0xff, 0xf7, 0x83, 0xfe, 0xb, - 0xfc, 0x7d, 0x0, 0x7, 0xd1, 0x0, 0x0, 0x4, - - /* U+E5C3 "" */ - 0x14, 0x5, 0x1, 0x4b, 0xd2, 0xf4, 0xbd, 0xbe, - 0x2f, 0x8b, 0xe3, 0x80, 0xe0, 0x38, 0x0, 0x0, - 0x0, 0x1, 0x40, 0x50, 0x14, 0xbd, 0x2f, 0x4b, - 0xdb, 0xe2, 0xf8, 0xbe, 0x38, 0xe, 0x3, 0x80, - 0x0, 0x0, 0x0, 0x14, 0x5, 0x1, 0x4b, 0xd2, - 0xf4, 0xbd, 0xbe, 0x2f, 0x8b, 0xe3, 0x80, 0xe0, - 0x38, - - /* U+E5CD "" */ - 0x20, 0x0, 0x9, 0x3c, 0x0, 0x2e, 0x1f, 0x0, - 0xb8, 0x7, 0xc2, 0xe0, 0x1, 0xfb, 0x80, 0x0, - 0x7e, 0x0, 0x0, 0xbf, 0x0, 0x2, 0xe7, 0xc0, - 0xb, 0x81, 0xf0, 0x2e, 0x0, 0x7c, 0x38, 0x0, - 0x1e, 0x0, 0x0, 0x0, - - /* U+E5D2 "" */ - 0xbf, 0xff, 0xff, 0xfc, 0x6a, 0xaa, 0xaa, 0xa8, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x6a, 0xaa, 0xaa, 0xa8, 0x7f, 0xff, 0xff, 0xfc, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x6a, 0xaa, 0xaa, 0xa8, 0xbf, 0xff, 0xff, 0xfc, - - /* U+E5D4 "" */ - 0x14, 0xbd, 0xbe, 0x38, 0x0, 0x14, 0xbd, 0xbe, - 0x38, 0x0, 0x14, 0xbd, 0xbe, 0x38, - - /* U+E5D5 "" */ - 0x0, 0x1a, 0x40, 0x50, 0x2f, 0xff, 0x8e, 0xf, - 0x80, 0x6f, 0xe2, 0xd0, 0x0, 0x7e, 0x38, 0x0, - 0xab, 0xe7, 0x0, 0xf, 0xfe, 0xb0, 0x0, 0x0, - 0xb, 0x0, 0x0, 0x0, 0x70, 0x0, 0x0, 0x3, - 0x80, 0x0, 0x2c, 0x2d, 0x0, 0x7, 0x80, 0xf8, - 0x6, 0xf0, 0x2, 0xff, 0xf8, 0x0, 0x1, 0xa4, - 0x0, - - /* U+E63E "" */ - 0x0, 0x1, 0x6a, 0x40, 0x0, 0x0, 0x7f, 0xff, - 0xfe, 0x0, 0x7, 0xff, 0xff, 0xff, 0xe0, 0x2f, - 0xf4, 0x0, 0x1b, 0xfc, 0x3f, 0x40, 0x0, 0x0, - 0xbe, 0x28, 0x0, 0x6a, 0x40, 0x18, 0x0, 0x1f, - 0xff, 0xf8, 0x0, 0x0, 0xbf, 0xff, 0xff, 0x0, - 0x0, 0xbd, 0x0, 0x6f, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x2d, 0x0, 0x0, 0x0, - 0x0, 0xbf, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x7f, 0x0, 0x0, 0x0, 0x0, - 0x4, 0x0, 0x0, - - /* U+E668 "" */ - 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x3d, 0x0, - 0x0, 0xf, 0x40, 0x0, 0x3, 0xd0, 0x10, 0x0, - 0xf4, 0x7, 0xc0, 0x3d, 0x0, 0x2f, 0xf, 0x40, - 0x0, 0xbf, 0xd0, 0x0, 0x2, 0xf4, 0x0, 0x0, - 0x5, 0x0, 0x0, - - /* U+E745 "" */ - 0x6a, 0xaa, 0x80, 0x0, 0x7f, 0xff, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x2a, 0xaa, 0x80, 0x0, - 0xbf, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xb4, 0x7f, 0xf0, 0x2, 0xfc, - 0x6a, 0xa0, 0xb, 0xfc, 0x0, 0x0, 0x2d, 0xf8, - 0x0, 0x0, 0x74, 0xe0, 0x0, 0x0, 0xd3, 0x80, - 0x0, 0x0, 0xde, 0x0, 0x0, 0x0, 0xf8, 0x0, - - /* U+E770 "" */ - 0x0, 0x1, 0x80, 0x0, 0x0, 0x7, 0xf4, 0x0, - 0x0, 0xf, 0x7e, 0x0, 0x0, 0x3d, 0xb, 0xfc, - 0xb4, 0xb8, 0x1, 0xae, 0xbf, 0xf0, 0x0, 0xe, - 0xbb, 0xc0, 0x0, 0xe, 0xb1, 0x42, 0xc0, 0xe, - 0xb0, 0x7, 0xf4, 0xe, 0xb4, 0xf, 0xfe, 0xe, - 0xbe, 0x3f, 0xff, 0xce, 0xbf, 0xff, 0xff, 0xfe, - 0xbf, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfd, - - /* U+E89C "" */ - 0x1a, 0xaa, 0x40, 0xb, 0xff, 0xfe, 0x0, 0xb0, - 0x1, 0xf8, 0xb, 0x0, 0xf, 0xe0, 0xb0, 0x0, - 0xff, 0x8b, 0x0, 0xf, 0xfd, 0xb0, 0x0, 0x15, - 0xeb, 0x0, 0xa0, 0xe, 0xb0, 0xf, 0x0, 0xeb, - 0x5, 0xf5, 0xe, 0xb0, 0xff, 0xf0, 0xeb, 0x1, - 0xf4, 0xe, 0xb0, 0xf, 0x0, 0xeb, 0x0, 0x50, - 0xe, 0xb0, 0x0, 0x0, 0xeb, 0xaa, 0xaa, 0xae, - 0x7f, 0xff, 0xff, 0xd0, 0x0, 0x0, 0x0, - - /* U+E8AF "" */ - 0xa, 0xaa, 0xaa, 0x40, 0x3, 0xff, 0xff, 0xfd, - 0x0, 0x38, 0x0, 0x0, 0xe0, 0x3, 0x80, 0x0, - 0xe, 0x0, 0x38, 0x0, 0x0, 0xe3, 0xc3, 0x80, - 0x0, 0xe, 0x3e, 0x38, 0x0, 0x0, 0xe3, 0xe3, - 0x80, 0x0, 0xe, 0x3e, 0x3a, 0xaa, 0xaa, 0xe3, - 0xe3, 0xff, 0xff, 0xfc, 0x3e, 0x3e, 0x0, 0x0, - 0x3, 0xe3, 0x86, 0xaa, 0xaa, 0xfe, 0x0, 0xbf, - 0xff, 0xff, 0xe0, 0x7, 0xff, 0xff, 0xfe, 0x0, - 0x0, 0x0, 0x3, 0xe0, 0x0, 0x0, 0x0, 0x1d, - 0x0, 0x0, 0x0, 0x0, 0x0, - - /* U+E8B8 "" */ - 0x0, 0x6, 0x90, 0x0, 0x0, 0x7, 0xfd, 0x0, - 0x0, 0x2, 0xc3, 0x80, 0x0, 0x79, 0xf0, 0xf6, - 0xd0, 0x3f, 0xf4, 0x1f, 0xfc, 0x2c, 0x10, 0x0, - 0x43, 0x8f, 0x40, 0xbe, 0x1, 0xf0, 0xf4, 0xbf, - 0xe1, 0xf0, 0x1d, 0x3f, 0xfc, 0x74, 0xb, 0x8b, - 0xff, 0x2d, 0xb, 0xc1, 0xff, 0x43, 0xe3, 0xc0, - 0xa, 0x40, 0x3c, 0x7a, 0xd0, 0x7, 0xad, 0xf, - 0xff, 0xf, 0xff, 0x0, 0x92, 0xc3, 0x86, 0x0, - 0x0, 0x7a, 0xd0, 0x0, 0x0, 0xf, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, - - /* U+E8FD "" */ - 0x0, 0x1, 0x54, 0x0, 0x0, 0x2, 0xff, 0xfc, - 0x0, 0x1, 0xf9, 0x6, 0xf4, 0x0, 0x7c, 0x0, - 0x3, 0xd0, 0xf, 0x2, 0xfc, 0xf, 0x2, 0xd0, - 0x7a, 0xf0, 0x38, 0x3c, 0x1, 0xb, 0x2, 0xc3, - 0x80, 0x0, 0xe0, 0x1d, 0x34, 0x0, 0x3c, 0x1, - 0xd3, 0x40, 0xb, 0x0, 0x1d, 0x38, 0x0, 0x60, - 0x1, 0xc3, 0xc0, 0x0, 0x0, 0x3c, 0x1e, 0x0, - 0xf0, 0x7, 0x80, 0xf4, 0xa, 0x0, 0xf0, 0x3, - 0xe0, 0x0, 0x7c, 0x0, 0xb, 0xea, 0xbf, 0x0, - 0x0, 0x1b, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, - 0x0, - - /* U+E90F "" */ - 0x0, 0x15, 0x40, 0x0, 0x1f, 0xff, 0x40, 0xb, - 0xd0, 0x7e, 0x1, 0xe0, 0x0, 0xb4, 0x3c, 0x0, - 0x3, 0xc3, 0x80, 0x0, 0x2c, 0x34, 0x0, 0x1, - 0xc3, 0x80, 0x0, 0x2c, 0x3c, 0x0, 0x3, 0xc2, - 0xd0, 0x0, 0x78, 0xf, 0xaa, 0xaf, 0x0, 0x2f, - 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, - 0x40, 0x0, 0xaa, 0xa0, 0x0, 0x1, 0xa4, 0x0, - 0x0, 0xf, 0x40, 0x0, 0x0, 0x0, 0x0, - - /* U+E92E "" */ - 0x0, 0x1a, 0x40, 0x6, 0xaf, 0xff, 0xa8, 0xbf, - 0xff, 0xff, 0xd3, 0xc0, 0x0, 0x3c, 0x3c, 0x0, - 0x3, 0xc3, 0xc7, 0xd, 0x3c, 0x3c, 0x70, 0xd3, - 0xc3, 0xc7, 0xd, 0x3c, 0x3c, 0x70, 0xd3, 0xc3, - 0xc7, 0xd, 0x3c, 0x3c, 0x70, 0xd3, 0xc3, 0xc7, - 0xd, 0x3c, 0x3c, 0x0, 0x3, 0xc3, 0xc0, 0x0, - 0x3c, 0x2f, 0xff, 0xff, 0x80, 0xaa, 0xaa, 0xa0, - - /* U+E9B9 "" */ - 0x4, 0x1, 0x55, 0x55, 0x43, 0xf0, 0xff, 0xff, - 0xfc, 0x7f, 0xf, 0xff, 0xff, 0xd2, 0xd0, 0xbf, - 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, - 0x15, 0x55, 0x54, 0x3f, 0xf, 0xff, 0xff, 0xc7, - 0xf0, 0xff, 0xff, 0xfd, 0x2d, 0xb, 0xff, 0xff, - 0x80, 0x0, 0x0, 0x0, 0x0, 0x4, 0x1, 0x55, - 0x55, 0x43, 0xf0, 0xff, 0xff, 0xfc, 0x7f, 0xf, - 0xff, 0xff, 0xd2, 0xd0, 0xbf, 0xff, 0xf8, - - /* U+E9F4 "" */ - 0x0, 0x0, 0x7d, 0x0, 0x0, 0x0, 0x0, 0xff, - 0x0, 0x0, 0x0, 0x1, 0xd7, 0x40, 0x0, 0x0, - 0x1, 0xff, 0x40, 0x0, 0x0, 0x0, 0x7d, 0x0, - 0x0, 0x15, 0x0, 0x28, 0x0, 0x54, 0x7f, 0x40, - 0x28, 0x1, 0xfd, 0xf7, 0xc1, 0xff, 0x3, 0xdf, - 0xf3, 0xe7, 0xeb, 0xdb, 0xcf, 0x7f, 0xaf, 0x0, - 0xfa, 0xfd, 0x15, 0xb, 0x0, 0xe0, 0x54, 0x0, - 0xb, 0x0, 0xe0, 0x0, 0x0, 0x3, 0xeb, 0xc0, - 0x0, 0x0, 0x3, 0xff, 0xc0, 0x0, 0x1, 0xae, - 0x0, 0xba, 0x40, 0x3, 0xfc, 0x0, 0x3f, 0xc0, - 0x7, 0x5d, 0x0, 0x75, 0xd0, 0x7, 0xfd, 0x0, - 0x7f, 0xd0, 0x2, 0xf8, 0x0, 0x2f, 0x80, 0x0, - 0x0, 0x0, 0x0, 0x0, - - /* U+E9F7 "" */ - 0x1a, 0xaa, 0xaa, 0xa4, 0x7f, 0xff, 0xff, 0xfd, - 0x70, 0x0, 0x0, 0xe, 0xb0, 0x0, 0x0, 0xe, - 0xba, 0xaa, 0xaa, 0xae, 0xbf, 0xff, 0xff, 0xfe, - 0xb4, 0x0, 0x0, 0xe, 0xb0, 0x0, 0x0, 0xe, - 0xb0, 0x0, 0x0, 0xe, 0xb0, 0x0, 0x0, 0xe, - 0xb0, 0x0, 0x0, 0xe, 0xb0, 0x0, 0x0, 0xe, - 0xb0, 0x0, 0x0, 0xe, 0x70, 0x0, 0x0, 0xe, - 0x7f, 0xff, 0xff, 0xfd, 0x1a, 0xaa, 0xaa, 0xa4, - - /* U+EA07 "" */ - 0x0, 0x1, 0x64, 0x0, 0x0, 0x2, 0xff, 0xfc, - 0x0, 0x1, 0xff, 0xef, 0xf4, 0x0, 0x7c, 0xb4, - 0xe3, 0xd0, 0xf, 0xf, 0xb, 0xf, 0x2, 0xfa, - 0xfa, 0xba, 0xb8, 0x3f, 0xff, 0xff, 0xff, 0xc3, - 0x82, 0xc0, 0x3c, 0x1d, 0x34, 0x2c, 0x3, 0xc1, - 0xd3, 0x42, 0xc0, 0x3c, 0x1d, 0x3e, 0xbe, 0xab, - 0xea, 0xc2, 0xff, 0xff, 0xff, 0xfc, 0x1e, 0xe, - 0xb, 0x4b, 0x80, 0xb4, 0xf0, 0xf1, 0xf0, 0x3, - 0xe7, 0x9e, 0xbc, 0x0, 0xb, 0xff, 0xff, 0x0, - 0x0, 0x1b, 0xfe, 0x40, 0x0, 0x0, 0x0, 0x0, - 0x0, - - /* U+EAD6 "" */ - 0x1a, 0xaa, 0xaa, 0xa4, 0x7f, 0xff, 0xff, 0xfd, - 0x70, 0x0, 0x0, 0xe, 0xb0, 0x0, 0x0, 0xe, - 0xb0, 0x0, 0x0, 0xe, 0xb2, 0x92, 0x84, 0x4e, - 0xb3, 0xbb, 0x8c, 0xce, 0xb3, 0x3a, 0xc, 0xce, - 0xb3, 0x3b, 0x4a, 0x8e, 0xb3, 0x3a, 0x7, 0x4e, - 0xb2, 0x92, 0x82, 0xe, 0xb0, 0x0, 0x0, 0xe, - 0xb0, 0x0, 0x0, 0xe, 0x70, 0x0, 0x0, 0xe, - 0x7f, 0xff, 0xff, 0xfd, 0x1a, 0xaa, 0xaa, 0xa4, - - /* U+EB8E "" */ - 0x5, 0x55, 0x55, 0x55, 0x43, 0xff, 0xff, 0xff, - 0xfd, 0x3f, 0xff, 0xff, 0xff, 0xe3, 0xff, 0xff, - 0xff, 0xfe, 0x38, 0x0, 0x0, 0x0, 0xe3, 0x87, - 0x40, 0x0, 0xe, 0x38, 0x3d, 0x0, 0x0, 0xe3, - 0x80, 0xf4, 0x0, 0xe, 0x38, 0xf, 0x0, 0x0, - 0xe3, 0x83, 0xc0, 0x69, 0xe, 0x38, 0x20, 0x2f, - 0xf0, 0xe3, 0x80, 0x0, 0x0, 0xe, 0x3f, 0xff, - 0xff, 0xff, 0xd1, 0xaa, 0xaa, 0xaa, 0xa8, - - /* U+EB97 "" */ - 0xa, 0xaa, 0xaa, 0xaa, 0x43, 0xff, 0xff, 0xff, - 0xfd, 0x38, 0x0, 0x0, 0x0, 0xe3, 0x80, 0x0, - 0x0, 0xe, 0x38, 0x0, 0x1, 0xc0, 0xe3, 0x8b, - 0xff, 0xdf, 0xe, 0x38, 0x0, 0x0, 0xc0, 0xe3, - 0x81, 0x40, 0x0, 0xe, 0x38, 0xb8, 0xff, 0xf0, - 0xe3, 0x87, 0x8a, 0xaa, 0xe, 0x38, 0x4, 0x0, - 0x0, 0xe3, 0x80, 0x0, 0x0, 0xe, 0x3e, 0xaa, - 0xaa, 0xaa, 0xe1, 0xff, 0xff, 0xff, 0xfc, 0x0, - 0xf, 0xff, 0x80, 0x0, 0x0, 0xaa, 0xa0, 0x0, - - /* U+EBCC "" */ - 0x0, 0x0, 0x0, 0x0, 0x3, 0x80, 0x2, 0xc0, - 0x2b, 0xea, 0xab, 0xe8, 0x7f, 0xff, 0xff, 0xfd, - 0xb0, 0x0, 0x0, 0xe, 0xba, 0xaa, 0xaa, 0xae, - 0xbf, 0xff, 0xff, 0xfe, 0xb0, 0x0, 0x0, 0xe, - 0xb0, 0x0, 0x0, 0xe, 0xb0, 0xd2, 0x87, 0xe, - 0xb0, 0x81, 0x42, 0xe, 0xb0, 0x0, 0x0, 0xe, - 0xb0, 0x81, 0x42, 0xe, 0xb0, 0xd2, 0x87, 0xe, - 0xb0, 0x0, 0x0, 0xe, 0xba, 0xaa, 0xaa, 0xae, - 0x3f, 0xff, 0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, - - /* U+EC1C "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x80, 0x0, - 0x1, 0xf0, 0x0, 0x0, 0x7e, 0x0, 0x0, 0x1f, - 0xc0, 0x0, 0xb, 0xf8, 0x0, 0x2, 0xff, 0x0, - 0x0, 0xb9, 0xff, 0xa4, 0x2e, 0x6, 0xbf, 0xd7, - 0xfe, 0x90, 0xb8, 0x1a, 0xff, 0x6e, 0x0, 0x0, - 0xff, 0x80, 0x0, 0x2f, 0xe0, 0x0, 0x3, 0xf4, - 0x0, 0x0, 0xbd, 0x0, 0x0, 0xf, 0x40, 0x0, - 0x2, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, - - /* U+EF40 "" */ - 0x14, 0x5, 0x1, 0x40, 0xbd, 0x2f, 0x4b, 0xd0, - 0xbe, 0x2f, 0x8b, 0xe0, 0x38, 0xe, 0x3, 0x80, - 0x0, 0x0, 0x0, 0x0, 0x14, 0x5, 0x0, 0x0, - 0xbd, 0x2f, 0x40, 0x60, 0xbe, 0x2f, 0x81, 0xfc, - 0x38, 0xe, 0x7, 0xfc, 0x0, 0x0, 0x1e, 0xf8, - 0x14, 0x0, 0x74, 0xe0, 0xbd, 0x0, 0xd3, 0x80, - 0xbe, 0x1, 0xde, 0x0, 0x38, 0x0, 0xf8, 0x0, - - /* U+EF4A "" */ - 0x0, 0x1, 0x54, 0x0, 0x0, 0x2, 0xff, 0xfc, - 0x0, 0x1, 0xf9, 0x6, 0xf4, 0x0, 0x7c, 0x0, - 0x3, 0xd0, 0xf, 0x0, 0x0, 0xf, 0x2, 0xd0, - 0x0, 0x0, 0x38, 0x3c, 0x0, 0x0, 0x2, 0xc3, - 0x80, 0x0, 0x0, 0x1d, 0x34, 0x0, 0x0, 0x1, - 0xd3, 0x40, 0x0, 0x0, 0x1d, 0x38, 0x0, 0x0, - 0x1, 0xc3, 0xc0, 0x0, 0x0, 0x3c, 0x1e, 0x0, - 0x0, 0x7, 0x80, 0xf4, 0x0, 0x0, 0xf0, 0x3, - 0xe0, 0x0, 0x7c, 0x0, 0xb, 0xea, 0xbf, 0x0, - 0x0, 0x1b, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, - 0x0, - - /* U+EF7A "" */ - 0x0, 0x55, 0x0, 0x0, 0x7, 0xff, 0xd0, 0x0, - 0x1f, 0x41, 0xf4, 0x0, 0x3c, 0x0, 0x3c, 0x0, - 0x74, 0x0, 0x2c, 0x0, 0x70, 0x0, 0x1d, 0x0, - 0x74, 0x0, 0x1d, 0x0, 0x38, 0x0, 0x2c, 0x0, - 0x3d, 0x0, 0x78, 0x0, 0xf, 0xeb, 0xfc, 0x0, - 0x2, 0xff, 0x5f, 0x0, 0x0, 0x0, 0x7, 0xc0, - 0x0, 0x0, 0x1, 0xf0, 0x0, 0x0, 0x0, 0x7c, - 0x0, 0x0, 0x0, 0x1c, - - /* U+EFE6 "" */ - 0x0, 0x54, 0x1, 0x90, 0x3, 0xfe, 0x3, 0xf0, - 0xb, 0x8b, 0x4b, 0xf8, 0xf, 0x3, 0x8f, 0xfc, - 0xf, 0x3, 0x8f, 0xfc, 0xf, 0x3, 0x8f, 0xfc, - 0xf, 0x3, 0x81, 0xe0, 0xf, 0x3, 0x81, 0xd0, - 0xf, 0x3, 0x81, 0xd0, 0x1f, 0x43, 0x81, 0xd0, - 0xbf, 0xc3, 0x81, 0xd0, 0xbf, 0xd3, 0x81, 0xd0, - 0xbf, 0xd3, 0x81, 0xd0, 0x7f, 0xc2, 0xd3, 0xc0, - 0x2f, 0x80, 0xff, 0x40, 0xa, 0x0, 0x14, 0x0, - - /* U+F028 "" */ - 0xa, 0xaa, 0xaa, 0xaa, 0xa0, 0x3f, 0xff, 0xff, - 0xff, 0xfc, 0x38, 0x0, 0x0, 0x0, 0x2c, 0x38, - 0x0, 0x0, 0x0, 0x2c, 0x38, 0xb1, 0xc3, 0x4a, - 0x2c, 0x38, 0x0, 0x0, 0x0, 0x2c, 0x38, 0x50, - 0x81, 0x5, 0x2c, 0x38, 0xb1, 0xc3, 0x4a, 0x2c, - 0x38, 0x0, 0x0, 0x0, 0x2c, 0x38, 0x2, 0xaa, - 0x80, 0x2c, 0x38, 0x3, 0xff, 0xc0, 0x2c, 0x38, - 0x0, 0x0, 0x0, 0x2c, 0x3f, 0xff, 0xff, 0xff, - 0xfc, 0xa, 0xaa, 0xaa, 0xaa, 0xa0, - - /* U+F090 "" */ - 0x0, 0x5, 0x0, 0x0, 0x0, 0xe0, 0x0, 0x0, - 0xe, 0x0, 0x0, 0x0, 0xe0, 0x0, 0x0, 0xe, - 0x0, 0x0, 0x14, 0xe2, 0x40, 0x3, 0xde, 0xb8, - 0x0, 0xf, 0xfe, 0x0, 0x0, 0x3f, 0x80, 0x1, - 0x0, 0xe0, 0x4, 0xb0, 0x0, 0x0, 0xeb, 0x0, - 0x0, 0xe, 0xbf, 0xff, 0xff, 0xe2, 0xaa, 0xaa, - 0xa8, - - /* U+F15C "" */ - 0x0, 0x0, 0x69, 0x0, 0x0, 0x0, 0xb, 0xff, - 0xd0, 0x0, 0x0, 0x2f, 0x41, 0xf4, 0x0, 0x0, - 0x3c, 0x0, 0x3c, 0x0, 0x0, 0xb0, 0x0, 0x1d, - 0x0, 0x7, 0xf0, 0x0, 0xe, 0x0, 0x1f, 0x40, - 0x0, 0xf, 0x80, 0x3c, 0x0, 0x0, 0xf, 0xf0, - 0x38, 0x0, 0x0, 0x0, 0x3c, 0x38, 0x0, 0x0, - 0x0, 0x2c, 0x3c, 0x0, 0x0, 0x0, 0x2c, 0x1e, - 0x0, 0x0, 0x0, 0x7c, 0xb, 0xff, 0xff, 0xff, - 0xf0, 0x0, 0xaa, 0xaa, 0xaa, 0x80, - - /* U+F720 "" */ - 0x0, 0x1, 0x40, 0x0, 0x0, 0x1f, 0xf4, 0x0, - 0x0, 0xfd, 0xbe, 0x0, 0xb, 0xe0, 0xb, 0xe0, - 0x3e, 0x0, 0x0, 0xfc, 0xbe, 0x0, 0x0, 0xfd, - 0xbb, 0xe0, 0xb, 0xed, 0xb0, 0xfd, 0x7e, 0x1d, - 0xb0, 0x1f, 0xf4, 0x1d, 0xb0, 0x3, 0xc0, 0x1d, - 0xb0, 0x3, 0x80, 0x1d, 0xb0, 0x3, 0x80, 0x1d, - 0x78, 0x3, 0x80, 0x3d, 0x2f, 0x43, 0x82, 0xf8, - 0x7, 0xf7, 0xdf, 0xc0, 0x0, 0x7f, 0xfd, 0x0, - 0x0, 0xb, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, - - /* U+F8C7 "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0x0, - 0x0, 0x0, 0x0, 0xb0, 0x0, 0x0, 0x10, 0xb, - 0x0, 0x50, 0xf, 0x0, 0xb0, 0xf, 0x1, 0xd0, - 0xb, 0x0, 0x78, 0x3c, 0x0, 0xb0, 0x2, 0xc3, - 0x80, 0xb, 0x0, 0x1d, 0x34, 0x0, 0xb0, 0x1, - 0xd3, 0x40, 0x6, 0x0, 0x1d, 0x38, 0x0, 0x0, - 0x1, 0xc3, 0xc0, 0x0, 0x0, 0x3c, 0x1d, 0x0, - 0x0, 0x7, 0x80, 0xf4, 0x0, 0x0, 0xf0, 0x3, - 0xe0, 0x0, 0x7c, 0x0, 0xb, 0xea, 0xbf, 0x0, - 0x0, 0x1b, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, - 0x0, - - /* U+FFF75 "󿽵" */ - 0x2a, 0xaa, 0xaa, 0xa9, 0x3, 0xff, 0xff, 0xff, - 0xfc, 0x38, 0x0, 0x0, 0x1, 0xd3, 0x89, 0x7, - 0x3, 0xe, 0x38, 0x0, 0x0, 0x0, 0xe3, 0xff, - 0xff, 0xff, 0xfe, 0x2a, 0xab, 0xff, 0xab, 0xe0, - 0x1, 0xff, 0x44, 0xe, 0x6, 0xfe, 0x0, 0x82, - 0xd2, 0xf9, 0x2, 0x6, 0xf8, 0x38, 0x30, 0x1b, - 0xf8, 0x3, 0xea, 0xaf, 0xfe, 0xa9, 0x3f, 0xff, - 0xff, 0xff, 0xe3, 0x80, 0x0, 0x1, 0xe, 0x38, - 0x90, 0x20, 0x20, 0xe3, 0xea, 0xaa, 0xaa, 0xae, - 0x1f, 0xff, 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, - 0x0 -}; - - -/*--------------------- - * GLYPH DESCRIPTION - *--------------------*/ - -static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { - {.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */, - {.bitmap_index = 0, .adv_w = 320, .box_w = 12, .box_h = 12, .ofs_x = 4, .ofs_y = 4}, - {.bitmap_index = 36, .adv_w = 320, .box_w = 18, .box_h = 14, .ofs_x = 1, .ofs_y = 3}, - {.bitmap_index = 99, .adv_w = 320, .box_w = 11, .box_h = 16, .ofs_x = 4, .ofs_y = 2}, - {.bitmap_index = 143, .adv_w = 320, .box_w = 12, .box_h = 18, .ofs_x = 4, .ofs_y = 1}, - {.bitmap_index = 197, .adv_w = 320, .box_w = 19, .box_h = 20, .ofs_x = 1, .ofs_y = 0}, - {.bitmap_index = 292, .adv_w = 320, .box_w = 18, .box_h = 14, .ofs_x = 1, .ofs_y = 3}, - {.bitmap_index = 355, .adv_w = 320, .box_w = 18, .box_h = 18, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 436, .adv_w = 320, .box_w = 10, .box_h = 6, .ofs_x = 5, .ofs_y = 7}, - {.bitmap_index = 451, .adv_w = 320, .box_w = 18, .box_h = 14, .ofs_x = 1, .ofs_y = 3}, - {.bitmap_index = 514, .adv_w = 320, .box_w = 18, .box_h = 18, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 595, .adv_w = 320, .box_w = 16, .box_h = 16, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 659, .adv_w = 320, .box_w = 10, .box_h = 16, .ofs_x = 5, .ofs_y = 2}, - {.bitmap_index = 699, .adv_w = 320, .box_w = 14, .box_h = 16, .ofs_x = 3, .ofs_y = 2}, - {.bitmap_index = 755, .adv_w = 320, .box_w = 14, .box_h = 14, .ofs_x = 3, .ofs_y = 3}, - {.bitmap_index = 804, .adv_w = 320, .box_w = 12, .box_h = 12, .ofs_x = 4, .ofs_y = 4}, - {.bitmap_index = 840, .adv_w = 320, .box_w = 16, .box_h = 10, .ofs_x = 2, .ofs_y = 5}, - {.bitmap_index = 880, .adv_w = 320, .box_w = 4, .box_h = 14, .ofs_x = 8, .ofs_y = 3}, - {.bitmap_index = 894, .adv_w = 320, .box_w = 14, .box_h = 14, .ofs_x = 3, .ofs_y = 3}, - {.bitmap_index = 943, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 2}, - {.bitmap_index = 1018, .adv_w = 320, .box_w = 14, .box_h = 10, .ofs_x = 3, .ofs_y = 5}, - {.bitmap_index = 1053, .adv_w = 320, .box_w = 16, .box_h = 14, .ofs_x = 3, .ofs_y = 3}, - {.bitmap_index = 1109, .adv_w = 320, .box_w = 16, .box_h = 14, .ofs_x = 2, .ofs_y = 3}, - {.bitmap_index = 1165, .adv_w = 320, .box_w = 14, .box_h = 18, .ofs_x = 3, .ofs_y = 1}, - {.bitmap_index = 1228, .adv_w = 320, .box_w = 18, .box_h = 17, .ofs_x = 1, .ofs_y = 2}, - {.bitmap_index = 1305, .adv_w = 320, .box_w = 17, .box_h = 18, .ofs_x = 2, .ofs_y = 1}, - {.bitmap_index = 1382, .adv_w = 320, .box_w = 18, .box_h = 18, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 1463, .adv_w = 320, .box_w = 14, .box_h = 18, .ofs_x = 3, .ofs_y = 1}, - {.bitmap_index = 1526, .adv_w = 320, .box_w = 14, .box_h = 16, .ofs_x = 3, .ofs_y = 2}, - {.bitmap_index = 1582, .adv_w = 320, .box_w = 18, .box_h = 14, .ofs_x = 1, .ofs_y = 3}, - {.bitmap_index = 1645, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 1745, .adv_w = 320, .box_w = 16, .box_h = 16, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 1809, .adv_w = 320, .box_w = 18, .box_h = 18, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 1890, .adv_w = 320, .box_w = 16, .box_h = 16, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 1954, .adv_w = 320, .box_w = 18, .box_h = 14, .ofs_x = 1, .ofs_y = 3}, - {.bitmap_index = 2017, .adv_w = 320, .box_w = 18, .box_h = 16, .ofs_x = 1, .ofs_y = 2}, - {.bitmap_index = 2089, .adv_w = 320, .box_w = 16, .box_h = 18, .ofs_x = 2, .ofs_y = 1}, - {.bitmap_index = 2161, .adv_w = 320, .box_w = 14, .box_h = 18, .ofs_x = 3, .ofs_y = 1}, - {.bitmap_index = 2224, .adv_w = 320, .box_w = 16, .box_h = 14, .ofs_x = 3, .ofs_y = 3}, - {.bitmap_index = 2280, .adv_w = 320, .box_w = 18, .box_h = 18, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 2361, .adv_w = 320, .box_w = 16, .box_h = 15, .ofs_x = 2, .ofs_y = 3}, - {.bitmap_index = 2421, .adv_w = 320, .box_w = 16, .box_h = 16, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 2485, .adv_w = 320, .box_w = 20, .box_h = 14, .ofs_x = 0, .ofs_y = 3}, - {.bitmap_index = 2555, .adv_w = 320, .box_w = 14, .box_h = 14, .ofs_x = 3, .ofs_y = 3}, - {.bitmap_index = 2604, .adv_w = 320, .box_w = 20, .box_h = 14, .ofs_x = 0, .ofs_y = 3}, - {.bitmap_index = 2674, .adv_w = 320, .box_w = 16, .box_h = 18, .ofs_x = 2, .ofs_y = 1}, - {.bitmap_index = 2746, .adv_w = 320, .box_w = 18, .box_h = 18, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 2827, .adv_w = 320, .box_w = 18, .box_h = 18, .ofs_x = 1, .ofs_y = 1} -}; - -/*--------------------- - * CHARACTER MAPPING - *--------------------*/ - -static const uint16_t unicode_list_0[] = { - 0x0, 0x14, 0x62, 0x9b, 0x148, 0x182, 0x1ca, 0x1d1, - 0x1e1, 0x26a, 0x2af, 0x2c0, 0x418, 0x47e, 0x488, 0x48d, - 0x48f, 0x490, 0x4f9, 0x523, 0x600, 0x62b, 0x757, 0x76a, - 0x773, 0x7b8, 0x7ca, 0x7e9, 0x874, 0x8af, 0x8b2, 0x8c2, - 0x991, 0xa49, 0xa52, 0xa87, 0xad7, 0xdfb, 0xe05, 0xe35, - 0xea1, 0xee3, 0xf4b, 0x1017, 0x15db, 0x1782 -}; - -/*Collect the unicode lists and glyph_id offsets*/ -static const lv_font_fmt_txt_cmap_t cmaps[] = -{ - { - .range_start = 57669, .range_length = 6019, .glyph_id_start = 1, - .unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 46, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY - }, - { - .range_start = 1048437, .range_length = 1, .glyph_id_start = 47, - .unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY - } -}; - - - -/*-------------------- - * ALL CUSTOM DATA - *--------------------*/ - -#if LVGL_VERSION_MAJOR == 8 -/*Store all the custom data of the font*/ -static lv_font_fmt_txt_glyph_cache_t cache; -#endif - -#if LVGL_VERSION_MAJOR >= 8 -static const lv_font_fmt_txt_dsc_t font_dsc = { -#else -static lv_font_fmt_txt_dsc_t font_dsc = { -#endif - .glyph_bitmap = glyph_bitmap, - .glyph_dsc = glyph_dsc, - .cmaps = cmaps, - .kern_dsc = NULL, - .kern_scale = 0, - .cmap_num = 2, - .bpp = 2, - .kern_classes = 0, - .bitmap_format = 0, -#if LVGL_VERSION_MAJOR == 8 - .cache = &cache -#endif -}; - - - -/*----------------- - * PUBLIC FONT - *----------------*/ - -/*Initialize a public general font descriptor*/ -#if LVGL_VERSION_MAJOR >= 8 -const lv_font_t material_symbols_shared_20 = { -#else -lv_font_t material_symbols_shared_20 = { -#endif - .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ - .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ - .line_height = 20, /*The maximum line height required by the font*/ - .base_line = 0, /*Baseline measured from the bottom of the line*/ -#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) - .subpx = LV_FONT_SUBPX_NONE, -#endif -#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 - .underline_position = 0, - .underline_thickness = 0, -#endif - .dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ -#if LV_VERSION_CHECK(8, 2, 0) || LVGL_VERSION_MAJOR >= 9 - .fallback = NULL, -#endif - .user_data = NULL, -}; - - - -#endif /*#if MATERIAL_SYMBOLS_SHARED_20*/ - diff --git a/Modules/lvgl-module/source-fonts/material_symbols_shared_24.c b/Modules/lvgl-module/source-fonts/material_symbols_shared_24.c deleted file mode 100644 index 005cb209f..000000000 --- a/Modules/lvgl-module/source-fonts/material_symbols_shared_24.c +++ /dev/null @@ -1,748 +0,0 @@ -/******************************************************************************* - * Size: 24 px - * Bpp: 2 - * Opts: --no-compress --no-prefilter --bpp 2 --size 24 --font MaterialSymbolsRounded.ttf -r 0xE145,0xE5C3,0xE770,0xEF40,0xEBCC,0xEFE6,0xEF4A,0xE5CD,0xF15C,0xE668,0xE92E,0xE326,0xEB97,0xE745,0xEC1C,0xE2C7,0xF720,0xF090,0xE8AF,0xE30F,0xE8FD,0xE9F4,0xE3F4,0xE316,0xE90F,0xEA07,0xE9B9,0xE159,0xE5D2,0xE28D,0xE5D4,0xE405,0xE89C,0xF8C7,0xE5D5,0xEF7A,0xE8B8,0xE9F7,0xE55D,0xF028,0xE1E0,0xE63E,0xE1A7,0xEB8E,0xEAD6,0xE3AF,0xFFF75 --format lvgl -o source-fonts/material_symbols_shared_24.c --force-fast-kern-format - ******************************************************************************/ - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -#ifndef MATERIAL_SYMBOLS_SHARED_24 -#define MATERIAL_SYMBOLS_SHARED_24 1 -#endif - -#if MATERIAL_SYMBOLS_SHARED_24 - -/*----------------- - * BITMAPS - *----------------*/ - -/*Store the image of the glyphs*/ -static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { - /* U+E145 "" */ - 0x0, 0xf, 0x0, 0x0, 0x0, 0xf0, 0x0, 0x0, - 0xf, 0x0, 0x0, 0x0, 0xf0, 0x0, 0x0, 0xf, - 0x0, 0x0, 0x0, 0xf0, 0x0, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x0, 0xf, 0x0, 0x0, - 0x0, 0xf0, 0x0, 0x0, 0xf, 0x0, 0x0, 0x0, - 0xf0, 0x0, 0x0, 0xf, 0x0, 0x0, 0x0, 0xf0, - 0x0, - - /* U+E159 "" */ - 0x7f, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x2f, 0xff, - 0x40, 0x0, 0x1, 0xff, 0xf7, 0xf0, 0x0, 0xf, - 0xdf, 0xf0, 0xbe, 0x0, 0xbe, 0xf, 0xf0, 0xf, - 0xd7, 0xf0, 0xf, 0xf0, 0x1, 0xff, 0x40, 0xf, - 0xf0, 0x0, 0x28, 0x0, 0xf, 0xf0, 0x0, 0x0, - 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, 0xf, 0xf0, - 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, - 0xf, 0xf0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xfd, - - /* U+E1A7 "" */ - 0x0, 0x0, 0x0, 0x0, 0x3, 0xd0, 0x0, 0x0, - 0xfd, 0x0, 0x40, 0x3f, 0xd0, 0xb8, 0xf, 0xbd, - 0xf, 0x83, 0xcb, 0xc0, 0xf8, 0xf2, 0xf0, 0xf, - 0xbe, 0xf0, 0x0, 0xff, 0xf0, 0x0, 0xf, 0xf0, - 0x0, 0x2, 0xf8, 0x0, 0x2, 0xff, 0x80, 0x2, - 0xff, 0xf8, 0x2, 0xf3, 0xcf, 0x82, 0xf0, 0xf1, - 0xf1, 0xf0, 0x3c, 0xf8, 0x60, 0xf, 0xf8, 0x0, - 0x3, 0xf8, 0x0, 0x0, 0xf8, 0x0, 0x0, 0x28, - 0x0, - - /* U+E1E0 "" */ - 0x0, 0x5, 0x0, 0x0, 0x0, 0xf0, 0x0, 0x0, - 0x3f, 0xc0, 0x0, 0x7, 0xfd, 0x0, 0x0, 0xf, - 0x0, 0x0, 0x0, 0xf0, 0x0, 0x7d, 0xf, 0xf, - 0xff, 0xf0, 0xf0, 0xff, 0xff, 0xf, 0xf, 0xf7, - 0xd0, 0xf0, 0xff, 0x3c, 0xf, 0x3, 0xc3, 0xc0, - 0xf0, 0x3c, 0x3f, 0xff, 0xff, 0xc1, 0xff, 0xff, - 0xf4, 0x0, 0xf, 0x0, 0x0, 0x0, 0xf0, 0x0, - 0x0, 0xf, 0x40, 0x0, 0x3, 0xfc, 0x0, 0x0, - 0x3f, 0xc0, 0x0, 0x1, 0xf4, 0x0, - - /* U+E28D "" */ - 0x0, 0x0, 0x2f, 0x80, 0x0, 0x0, 0x0, 0xb, - 0xfe, 0x0, 0x0, 0x0, 0x0, 0xf0, 0xf0, 0x0, - 0x0, 0x0, 0xf, 0xf, 0x0, 0x0, 0x0, 0x0, - 0xf0, 0xf0, 0x0, 0x0, 0x0, 0xf, 0xf, 0x0, - 0x0, 0x0, 0x0, 0xf0, 0xf0, 0x0, 0x0, 0x0, - 0xf, 0xf, 0x0, 0x0, 0x0, 0x0, 0xf0, 0xf0, - 0x0, 0x0, 0x0, 0xf, 0xf, 0x0, 0x0, 0x7, - 0xff, 0xff, 0xff, 0xfd, 0x0, 0xff, 0xff, 0xff, - 0xff, 0xf0, 0xf, 0x0, 0x0, 0x0, 0xf, 0x0, - 0xf0, 0x0, 0x0, 0x0, 0xf0, 0xf, 0xff, 0xff, - 0xff, 0xff, 0x1, 0xff, 0xff, 0xff, 0xff, 0xf4, - 0x2d, 0x0, 0x0, 0x0, 0x7, 0x83, 0xc3, 0xc0, - 0xf0, 0x3c, 0x3c, 0x3c, 0x3c, 0xf, 0x3, 0xc3, - 0xc7, 0x83, 0xc0, 0xf0, 0x3c, 0x2d, 0x7f, 0xff, - 0xff, 0xff, 0xff, 0xd2, 0xff, 0xff, 0xff, 0xff, - 0xf8, - - /* U+E2C7 "" */ - 0x7f, 0xff, 0x40, 0x0, 0x0, 0xff, 0xff, 0xe0, - 0x0, 0x0, 0xf0, 0x1, 0xff, 0xff, 0xfd, 0xf0, - 0x0, 0x7f, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, - 0xf, 0xf0, 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, - 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, 0xf, - 0xf0, 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, - 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, 0xf, 0xf0, - 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, - 0xf, 0xf0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xfd, - - /* U+E30F "" */ - 0x0, 0x3, 0xff, 0xc0, 0x0, 0x0, 0x3, 0xff, - 0xc0, 0x0, 0x0, 0x3, 0xc3, 0xc0, 0x0, 0x0, - 0x3, 0xc3, 0xc0, 0x0, 0x0, 0x3, 0xc3, 0xc0, - 0x0, 0x0, 0x3, 0xff, 0xc0, 0x0, 0x0, 0x0, - 0xff, 0x0, 0x0, 0xff, 0xf0, 0x3c, 0xf, 0xff, - 0xff, 0xfc, 0x0, 0x3f, 0xff, 0xf0, 0x3f, 0x0, - 0xfc, 0xf, 0xf0, 0x3f, 0x0, 0xfc, 0xf, 0xff, - 0xfc, 0x0, 0x3f, 0xff, 0xff, 0xf0, 0x3c, 0xf, - 0xff, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0x3, - 0xff, 0xc0, 0x0, 0x0, 0x3, 0xc3, 0xc0, 0x0, - 0x0, 0x3, 0xc3, 0xc0, 0x0, 0x0, 0x3, 0xc3, - 0xc0, 0x0, 0x0, 0x3, 0xff, 0xc0, 0x0, 0x0, - 0x3, 0xff, 0xc0, 0x0, - - /* U+E316 "" */ - 0x0, 0x14, 0x0, 0x0, 0xbd, 0x0, 0x2, 0xff, - 0x40, 0xb, 0xc7, 0xd0, 0x2f, 0x1, 0xf4, 0xbc, - 0x0, 0x7c, 0xb0, 0x0, 0x1c, - - /* U+E326 "" */ - 0x1f, 0xff, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, - 0xff, 0xfc, 0x3c, 0x0, 0x0, 0x0, 0x0, 0x3c, - 0x0, 0x0, 0x0, 0x0, 0x3c, 0x0, 0x0, 0xbf, - 0xfe, 0x3c, 0x0, 0x0, 0xff, 0xff, 0x3c, 0x0, - 0x0, 0xf0, 0xf, 0x3c, 0x0, 0x0, 0xf2, 0x8f, - 0x3c, 0x0, 0x0, 0xf0, 0xf, 0x3c, 0x0, 0x0, - 0xf0, 0xf, 0x3c, 0x0, 0x0, 0xf0, 0xf, 0x3f, - 0xff, 0xf0, 0xf0, 0xf, 0x1f, 0xff, 0xf0, 0xf0, - 0xf, 0x0, 0x0, 0x0, 0xf0, 0xf, 0xff, 0xff, - 0xf0, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xbf, 0xfe, - - /* U+E3AF "" */ - 0x0, 0x6, 0xff, 0x90, 0x0, 0x0, 0x7f, 0xff, - 0xfd, 0x0, 0x2, 0xfd, 0x3, 0x7f, 0x80, 0xb, - 0xd0, 0x9, 0x7, 0xe0, 0x1f, 0x80, 0x1c, 0x1, - 0xf4, 0x3e, 0xc0, 0x34, 0x0, 0x7c, 0x7c, 0x60, - 0x70, 0x0, 0x3d, 0xb4, 0x30, 0xff, 0xff, 0xfe, - 0xf0, 0x1f, 0xff, 0xc0, 0xf, 0xf0, 0xb, 0xff, - 0xc0, 0xf, 0xf0, 0x3, 0xff, 0xe0, 0xf, 0xf0, - 0x3, 0xff, 0xf4, 0xf, 0xbf, 0xff, 0xff, 0xc, - 0x1e, 0x7c, 0x0, 0xd, 0x9, 0x3d, 0x3d, 0x0, - 0x1c, 0x3, 0xbc, 0x1f, 0x40, 0x34, 0x2, 0xf4, - 0xb, 0xd0, 0x60, 0x7, 0xe0, 0x2, 0xfd, 0xc0, - 0x7f, 0x80, 0x0, 0x7f, 0xff, 0xfd, 0x0, 0x0, - 0x6, 0xff, 0x90, 0x0, - - /* U+E3F4 "" */ - 0x7f, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, - 0xff, 0xf0, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, - 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, 0xff, 0x0, - 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, 0xff, - 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, - 0xff, 0x0, 0x0, 0x10, 0xf, 0xf0, 0x14, 0xf, - 0x40, 0xff, 0x3, 0xc2, 0xfc, 0xf, 0xf0, 0xff, - 0x7f, 0xf0, 0xff, 0x1f, 0xff, 0xff, 0x4f, 0xf0, - 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0xf, - 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, - 0xfd, - - /* U+E405 "" */ - 0x0, 0xf, 0xff, 0x0, 0xf, 0xff, 0x0, 0xf, - 0xff, 0x0, 0xf, 0xff, 0x0, 0xf, 0x0, 0x0, - 0xf, 0x0, 0x0, 0xf, 0x0, 0x0, 0xf, 0x0, - 0x0, 0xf, 0x0, 0x0, 0xf, 0x0, 0xb, 0xef, - 0x0, 0x3f, 0xff, 0x0, 0xbf, 0xff, 0x0, 0xff, - 0xff, 0x0, 0xff, 0xff, 0x0, 0xbf, 0xfe, 0x0, - 0x3f, 0xfc, 0x0, 0xb, 0xe0, 0x0, - - /* U+E55D "" */ - 0x0, 0x1, 0x40, 0x0, 0x0, 0x3, 0xc0, 0x0, - 0x0, 0xb, 0xe0, 0x0, 0x0, 0xf, 0xf0, 0x0, - 0x0, 0x1e, 0xb4, 0x0, 0x0, 0x3d, 0x7c, 0x0, - 0x0, 0x7c, 0x3d, 0x0, 0x0, 0xf4, 0x1f, 0x0, - 0x0, 0xf0, 0xf, 0x0, 0x2, 0xe0, 0xb, 0x80, - 0x3, 0xc0, 0x3, 0xc0, 0xb, 0x80, 0x2, 0xe0, - 0xf, 0x0, 0x0, 0xf0, 0x1e, 0xb, 0xe0, 0xb4, - 0x3e, 0xbf, 0xfe, 0xbc, 0x7f, 0xf8, 0x2f, 0xfd, - 0xbf, 0x40, 0x1, 0xfe, 0x64, 0x0, 0x0, 0x19, - - /* U+E5C3 "" */ - 0x7d, 0x7, 0xd0, 0x7d, 0xff, 0xf, 0xf0, 0xff, - 0xff, 0xf, 0xf0, 0xff, 0x7d, 0x7, 0xd0, 0x7d, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x7d, 0x7, 0xd0, 0x7d, 0xff, 0xf, 0xf0, 0xff, - 0xff, 0xf, 0xf0, 0xff, 0x7d, 0x7, 0xd0, 0x7d, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x7d, 0x7, 0xd0, 0x7d, 0xff, 0xf, 0xf0, 0xff, - 0xff, 0xf, 0xf0, 0xff, 0x7d, 0x7, 0xd0, 0x7d, - - /* U+E5CD "" */ - 0x10, 0x0, 0x0, 0x4b, 0x40, 0x0, 0x3d, 0x7d, - 0x0, 0xf, 0xc1, 0xf4, 0x3, 0xf0, 0x7, 0xd0, - 0xfc, 0x0, 0x1f, 0xbf, 0x0, 0x0, 0x7f, 0xc0, - 0x0, 0x3, 0xf8, 0x0, 0x0, 0xff, 0xd0, 0x0, - 0x3f, 0x1f, 0x40, 0xf, 0xc0, 0x7d, 0x3, 0xf0, - 0x1, 0xf4, 0xbc, 0x0, 0x7, 0xd6, 0x0, 0x0, - 0x18, - - /* U+E5D2 "" */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - - /* U+E5D4 "" */ - 0x7d, 0xff, 0xff, 0x7d, 0x0, 0x0, 0x7d, 0xff, - 0xff, 0x7d, 0x0, 0x0, 0x7d, 0xff, 0xff, 0x7d, - - /* U+E5D5 "" */ - 0x0, 0x2f, 0xf8, 0xf, 0x2, 0xff, 0xff, 0x8f, - 0xf, 0xe0, 0xb, 0xef, 0x2f, 0x0, 0x0, 0xff, - 0x3c, 0x0, 0x0, 0x3f, 0xb8, 0x0, 0x3f, 0xff, - 0xf0, 0x0, 0x3f, 0xff, 0xf0, 0x0, 0x0, 0x0, - 0xf0, 0x0, 0x0, 0x0, 0xf0, 0x0, 0x0, 0x0, - 0xb8, 0x0, 0x0, 0x18, 0x3c, 0x0, 0x0, 0x3c, - 0x2f, 0x0, 0x0, 0xf8, 0xf, 0xe0, 0xb, 0xe0, - 0x2, 0xff, 0xff, 0x80, 0x0, 0x2f, 0xf8, 0x0, - - /* U+E63E "" */ - 0x0, 0x1, 0xbf, 0xfe, 0x40, 0x0, 0x0, 0x2f, - 0xff, 0xff, 0xf9, 0x0, 0x2, 0xff, 0xff, 0xff, - 0xff, 0xc0, 0xf, 0xff, 0x90, 0x1, 0xbf, 0xf4, - 0x3f, 0xe0, 0x0, 0x0, 0xb, 0xfd, 0x3f, 0x40, - 0x0, 0x0, 0x0, 0xfd, 0x4, 0x0, 0x6f, 0xf9, - 0x0, 0x14, 0x0, 0x7, 0xff, 0xff, 0xe0, 0x0, - 0x0, 0x2f, 0xff, 0xff, 0xfc, 0x0, 0x0, 0x3f, - 0xd0, 0x7, 0xfc, 0x0, 0x0, 0x19, 0x0, 0x0, - 0x64, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xf8, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xf4, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xe0, 0x0, 0x0, - - /* U+E668 "" */ - 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x3e, - 0x0, 0x0, 0x0, 0xfc, 0x0, 0x0, 0x3, 0xf0, - 0x0, 0x0, 0xf, 0xc0, 0x60, 0x0, 0x3f, 0x0, - 0xbc, 0x0, 0xfc, 0x0, 0x3f, 0x3, 0xf0, 0x0, - 0xf, 0xcf, 0xc0, 0x0, 0x3, 0xff, 0x0, 0x0, - 0x0, 0xfc, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, - - /* U+E745 "" */ - 0xff, 0xff, 0xfc, 0x0, 0xf, 0xff, 0xff, 0xc0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xff, 0xfc, 0x0, 0xf, 0xff, - 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xb8, 0xff, 0xfc, 0x0, 0x2f, - 0xef, 0xff, 0xc0, 0xb, 0xff, 0x0, 0x0, 0x2, - 0xff, 0xe0, 0x0, 0x0, 0xb8, 0xf8, 0x0, 0x0, - 0x2e, 0x2e, 0x0, 0x0, 0x3, 0x8b, 0x80, 0x0, - 0x0, 0x3e, 0xe0, 0x0, 0x0, 0x3, 0xf8, 0x0, - - /* U+E770 "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0x80, - 0x0, 0x0, 0x3, 0xff, 0x0, 0x0, 0x0, 0x7c, - 0xbd, 0x0, 0x0, 0xf, 0x42, 0xff, 0xdf, 0x3, - 0xe0, 0x7, 0xff, 0xfd, 0xbc, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0xf, 0xf7, 0xd0, 0x0, 0x0, - 0xff, 0x8, 0xb, 0x40, 0xf, 0xf0, 0x1, 0xfe, - 0x0, 0xff, 0x0, 0x3f, 0xfc, 0xf, 0xfc, 0xf, - 0xff, 0xf0, 0xff, 0xf6, 0xff, 0xff, 0xdf, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xf0, - - /* U+E89C "" */ - 0x7f, 0xff, 0xf4, 0x0, 0xff, 0xff, 0xfe, 0x0, - 0xf0, 0x0, 0x3f, 0x80, 0xf0, 0x0, 0x3f, 0xe0, - 0xf0, 0x0, 0x3f, 0xf8, 0xf0, 0x0, 0x3f, 0xfd, - 0xf0, 0x0, 0x3f, 0xff, 0xf0, 0x0, 0x0, 0xf, - 0xf0, 0x3, 0xc0, 0xf, 0xf0, 0x3, 0xc0, 0xf, - 0xf0, 0x3, 0xc0, 0xf, 0xf0, 0xff, 0xff, 0xf, - 0xf0, 0xff, 0xff, 0xf, 0xf0, 0x3, 0xc0, 0xf, - 0xf0, 0x3, 0xc0, 0xf, 0xf0, 0x3, 0xc0, 0xf, - 0xf0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0xf, - 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xfd, - - /* U+E8AF "" */ - 0x7f, 0xff, 0xff, 0xf4, 0x0, 0xff, 0xff, 0xff, - 0xfc, 0x0, 0xf0, 0x0, 0x0, 0x3c, 0x0, 0xf0, - 0x0, 0x0, 0x3c, 0x0, 0xf0, 0x0, 0x0, 0x3c, - 0x3d, 0xf0, 0x0, 0x0, 0x3c, 0x3f, 0xf0, 0x0, - 0x0, 0x3c, 0x3f, 0xf0, 0x0, 0x0, 0x3c, 0x3f, - 0xf0, 0x0, 0x0, 0x3c, 0x3f, 0xf7, 0xff, 0xff, - 0xfc, 0x3f, 0xff, 0xff, 0xff, 0xf4, 0x3f, 0xfd, - 0x0, 0x0, 0x0, 0x3f, 0xf4, 0x0, 0x0, 0x0, - 0xbf, 0x50, 0xff, 0xff, 0xff, 0xff, 0x0, 0xff, - 0xff, 0xff, 0xff, 0x0, 0x7f, 0xff, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x0, 0xbf, 0x0, 0x0, 0x0, - 0x0, 0x2f, 0x0, 0x0, 0x0, 0x0, 0x5, - - /* U+E8B8 "" */ - 0x0, 0x2, 0xff, 0x0, 0x0, 0x0, 0x3, 0xff, - 0x80, 0x0, 0x0, 0x7, 0x83, 0xc0, 0x0, 0xb, - 0x9f, 0x83, 0xd6, 0xd0, 0x2f, 0xff, 0x43, 0xff, - 0xf0, 0x3d, 0xb8, 0x0, 0x7d, 0xb8, 0xb8, 0x0, - 0x14, 0x0, 0x3c, 0xbd, 0x2, 0xff, 0x40, 0xbc, - 0x2f, 0x47, 0xff, 0xc3, 0xf4, 0xf, 0x4b, 0xff, - 0xd3, 0xd0, 0xf, 0x4b, 0xff, 0xd3, 0xd0, 0x2f, - 0x47, 0xff, 0xc3, 0xf4, 0xbd, 0x2, 0xff, 0x40, - 0xbc, 0xb8, 0x0, 0x14, 0x0, 0x3c, 0x3d, 0xb8, - 0x0, 0x7d, 0xb8, 0x2f, 0xff, 0x43, 0xff, 0xf0, - 0xb, 0x9f, 0x83, 0xd6, 0xd0, 0x0, 0x7, 0x83, - 0xc0, 0x0, 0x0, 0x3, 0xff, 0x80, 0x0, 0x0, - 0x2, 0xff, 0x0, 0x0, - - /* U+E8FD "" */ - 0x0, 0x6, 0xff, 0x90, 0x0, 0x0, 0x7f, 0xff, - 0xfd, 0x0, 0x2, 0xfd, 0x0, 0x7f, 0x80, 0xb, - 0xd0, 0x0, 0x7, 0xe0, 0x1f, 0x0, 0xbe, 0x0, - 0xf4, 0x3d, 0x3, 0xff, 0xc0, 0x7c, 0x7c, 0x3, - 0x42, 0xd0, 0x3d, 0xb4, 0x0, 0x1, 0xd0, 0x1e, - 0xf0, 0x0, 0x3, 0xc0, 0xf, 0xf0, 0x0, 0xf, - 0x0, 0xf, 0xf0, 0x0, 0x2d, 0x0, 0xf, 0xf0, - 0x0, 0x3c, 0x0, 0xf, 0xb4, 0x0, 0x0, 0x0, - 0x1e, 0x7c, 0x0, 0x14, 0x0, 0x3d, 0x3d, 0x0, - 0x3c, 0x0, 0x7c, 0x1f, 0x0, 0x3c, 0x0, 0xf4, - 0xb, 0xd0, 0x0, 0x7, 0xe0, 0x2, 0xfd, 0x0, - 0x7f, 0x80, 0x0, 0x7f, 0xff, 0xfd, 0x0, 0x0, - 0x6, 0xff, 0x90, 0x0, - - /* U+E90F "" */ - 0x0, 0x6f, 0xf4, 0x0, 0x2, 0xff, 0xff, 0x40, - 0xf, 0xd0, 0x1b, 0xd0, 0x2f, 0x0, 0x2, 0xf0, - 0x3c, 0x0, 0x0, 0xb8, 0x78, 0x0, 0x0, 0x3c, - 0xb4, 0x0, 0x0, 0x3c, 0xb4, 0x0, 0x0, 0x3c, - 0xb4, 0x0, 0x0, 0x3c, 0x78, 0x0, 0x0, 0x3c, - 0x3c, 0x0, 0x0, 0xb8, 0x2f, 0x0, 0x2, 0xf0, - 0xb, 0xff, 0xff, 0xd0, 0x2, 0xff, 0xff, 0x40, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xfe, 0x0, - 0x0, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xe0, 0x0, 0x0, 0x7, 0xc0, 0x0, - - /* U+E92E "" */ - 0x0, 0x3f, 0xfc, 0x0, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x3c, 0x0, 0x0, 0x3c, - 0x3c, 0x0, 0x0, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3c, 0x0, 0x0, 0x3c, 0x3c, 0x0, 0x0, 0x3c, - 0x3f, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xf4, - - /* U+E9B9 "" */ - 0x7d, 0x7, 0xff, 0xff, 0xfd, 0xff, 0xf, 0xff, - 0xff, 0xff, 0xff, 0xf, 0xff, 0xff, 0xff, 0x7d, - 0x7, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7d, 0x7, - 0xff, 0xff, 0xfd, 0xff, 0xf, 0xff, 0xff, 0xff, - 0xff, 0xf, 0xff, 0xff, 0xff, 0x7d, 0x7, 0xff, - 0xff, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7d, 0x7, 0xff, 0xff, - 0xfd, 0xff, 0xf, 0xff, 0xff, 0xff, 0xff, 0xf, - 0xff, 0xff, 0xff, 0x7d, 0x7, 0xff, 0xff, 0xfd, - - /* U+E9F4 "" */ - 0x0, 0x0, 0xb, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0x2f, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x7c, - 0x0, 0x0, 0x0, 0x0, 0x3c, 0x7c, 0x0, 0x0, - 0x0, 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x0, 0x0, - 0xb, 0xe0, 0x0, 0x0, 0x5, 0x0, 0x3, 0x80, - 0x0, 0x50, 0x3f, 0xc0, 0x3, 0x80, 0x3, 0xfc, - 0xbf, 0xe0, 0xb, 0xd0, 0xb, 0xfe, 0xf0, 0xf0, - 0x3f, 0xfc, 0xf, 0xf, 0xfa, 0xfe, 0xf9, 0x7f, - 0xbf, 0xaf, 0x7f, 0xeb, 0xf0, 0xf, 0xeb, 0xfd, - 0x1a, 0x41, 0xe0, 0xb, 0x41, 0xa4, 0x0, 0x1, - 0xe0, 0xb, 0x40, 0x0, 0x0, 0x0, 0xf4, 0x1f, - 0x0, 0x0, 0x0, 0x0, 0xbf, 0xfe, 0x0, 0x0, - 0x0, 0x0, 0xfb, 0xef, 0x0, 0x0, 0x0, 0xbf, - 0xc0, 0x3, 0xfe, 0x0, 0x2, 0xff, 0x80, 0x2, - 0xff, 0x80, 0x3, 0xc3, 0xc0, 0x3, 0xc3, 0xc0, - 0x3, 0xc3, 0xc0, 0x3, 0xc3, 0xc0, 0x2, 0xff, - 0x80, 0x2, 0xff, 0x80, 0x0, 0xbe, 0x0, 0x0, - 0xbe, 0x0, - - /* U+E9F7 "" */ - 0x7f, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, - 0xff, 0xf0, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, - 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, - 0xff, 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, - 0x0, 0xff, 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, - 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0xf, 0xf0, - 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0xf, - 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, - 0xfd, - - /* U+EA07 "" */ - 0x0, 0x6, 0xff, 0x90, 0x0, 0x0, 0x7f, 0xff, - 0xfd, 0x0, 0x2, 0xff, 0xef, 0xff, 0x80, 0xb, - 0xd7, 0xc7, 0xcb, 0xe0, 0x1f, 0xb, 0x43, 0xd1, - 0xf4, 0x3d, 0xf, 0x2, 0xe0, 0xbc, 0x7f, 0xff, - 0xff, 0xff, 0xfd, 0xbf, 0xff, 0xff, 0xff, 0xfe, - 0xf0, 0x2d, 0x0, 0xf0, 0xf, 0xf0, 0x2d, 0x0, - 0xb4, 0xf, 0xf0, 0x2d, 0x0, 0xb4, 0xf, 0xf0, - 0x2d, 0x0, 0xf0, 0xf, 0xbf, 0xff, 0xff, 0xff, - 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xfd, 0x3d, 0xf, - 0x2, 0xe0, 0xbc, 0x1f, 0xb, 0x43, 0xd1, 0xf4, - 0xb, 0xd7, 0xc7, 0xcb, 0xe0, 0x2, 0xff, 0xef, - 0xff, 0x80, 0x0, 0x7f, 0xff, 0xfd, 0x0, 0x0, - 0x6, 0xff, 0x90, 0x0, - - /* U+EAD6 "" */ - 0x7f, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, - 0xff, 0xf0, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, - 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, 0xff, 0x0, - 0x0, 0x0, 0xf, 0xf3, 0xf3, 0xf3, 0xc, 0xff, - 0x32, 0x74, 0x35, 0xcf, 0xf3, 0x27, 0x82, 0xa8, - 0xff, 0x32, 0x78, 0x1f, 0x4f, 0xf3, 0x27, 0x40, - 0xf0, 0xff, 0x3f, 0x3f, 0xa, 0xf, 0xf0, 0x0, - 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0xf, 0xf0, - 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0xf, - 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, - 0xfd, - - /* U+EB8E "" */ - 0x7f, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, - 0xf, 0xf0, 0x20, 0x0, 0x0, 0xf, 0xf0, 0x7c, - 0x0, 0x0, 0xf, 0xf0, 0x3f, 0x0, 0x0, 0xf, - 0xf0, 0xf, 0xc0, 0x0, 0xf, 0xf0, 0xf, 0xc0, - 0x0, 0xf, 0xf0, 0x3f, 0x0, 0x0, 0xf, 0xf0, - 0x7c, 0xf, 0xff, 0xf, 0xf0, 0x20, 0xf, 0xff, - 0xf, 0xf0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xfd, - - /* U+EB97 "" */ - 0x7f, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, 0xf, 0xf0, - 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x34, - 0xf, 0xf0, 0xaa, 0xaa, 0x3e, 0xf, 0xf0, 0xaa, - 0xaa, 0x3e, 0xf, 0xf0, 0x0, 0x0, 0x34, 0xf, - 0xf0, 0x1c, 0x0, 0x0, 0xf, 0xf0, 0xbc, 0xaa, - 0xaa, 0xf, 0xf0, 0xbc, 0xaa, 0xaa, 0xf, 0xf0, - 0x1c, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, - 0xf, 0xf0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xfd, - 0x0, 0xf, 0xff, 0xf0, 0x0, 0x0, 0xf, 0xff, - 0xf0, 0x0, - - /* U+EBCC "" */ - 0x3, 0xc0, 0x0, 0x3c, 0x0, 0x3c, 0x0, 0x3, - 0xc0, 0x7f, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, - 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, 0xff, 0x0, - 0x0, 0x0, 0xf, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, - 0xff, 0x0, 0x0, 0x0, 0xf, 0xf0, 0xf0, 0xf0, - 0xf0, 0xff, 0xf, 0xf, 0xf, 0xf, 0xf0, 0x0, - 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0xf, 0xf0, - 0xf0, 0xf0, 0xf0, 0xff, 0xf, 0xf, 0xf, 0xf, - 0xf0, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, - 0xf, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, - 0xff, 0xfd, - - /* U+EC1C "" */ - 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x2f, 0x0, - 0x0, 0x0, 0xbe, 0x0, 0x0, 0x2, 0xfc, 0x0, - 0x0, 0xb, 0xf8, 0x0, 0x0, 0x2f, 0xf0, 0x0, - 0x0, 0xbf, 0xe0, 0x0, 0x3, 0xf7, 0xe4, 0x0, - 0xf, 0xcf, 0xff, 0xfd, 0x3f, 0x1, 0x6b, 0xfe, - 0xbf, 0xe9, 0x40, 0xfc, 0x7f, 0xff, 0xf3, 0xf0, - 0x0, 0x1b, 0xdf, 0xc0, 0x0, 0xb, 0xfe, 0x0, - 0x0, 0xf, 0xf8, 0x0, 0x0, 0x2f, 0xe0, 0x0, - 0x0, 0x3f, 0x80, 0x0, 0x0, 0xbe, 0x0, 0x0, - 0x0, 0xf8, 0x0, 0x0, 0x1, 0xe0, 0x0, 0x0, - - /* U+EF40 "" */ - 0x7d, 0x7, 0xd0, 0x7d, 0xf, 0xf0, 0xff, 0xf, - 0xf0, 0xff, 0xf, 0xf0, 0xff, 0x7, 0xd0, 0x7d, - 0x7, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7d, 0x7, 0xd0, 0x0, 0xf, - 0xf0, 0xff, 0x0, 0xb8, 0xff, 0xf, 0xf0, 0x2f, - 0xe7, 0xd0, 0x7d, 0xb, 0xff, 0x0, 0x0, 0x2, - 0xff, 0xe0, 0x0, 0x0, 0xb8, 0xf8, 0x7d, 0x0, - 0x2e, 0x2e, 0xf, 0xf0, 0x3, 0x8b, 0x80, 0xff, - 0x0, 0x3e, 0xe0, 0x7, 0xd0, 0x3, 0xf8, 0x0, - - /* U+EF4A "" */ - 0x0, 0x6, 0xff, 0x90, 0x0, 0x0, 0x7f, 0xff, - 0xfd, 0x0, 0x2, 0xfd, 0x0, 0x7f, 0x80, 0xb, - 0xd0, 0x0, 0x7, 0xe0, 0x1f, 0x0, 0x0, 0x0, - 0xf4, 0x3d, 0x0, 0x0, 0x0, 0x7c, 0x7c, 0x0, - 0x0, 0x0, 0x3d, 0xb4, 0x0, 0x0, 0x0, 0x1e, - 0xf0, 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, - 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, 0xf, 0xf0, - 0x0, 0x0, 0x0, 0xf, 0xb4, 0x0, 0x0, 0x0, - 0x1e, 0x7c, 0x0, 0x0, 0x0, 0x3d, 0x3d, 0x0, - 0x0, 0x0, 0x7c, 0x1f, 0x0, 0x0, 0x0, 0xf4, - 0xb, 0xd0, 0x0, 0x7, 0xe0, 0x2, 0xfd, 0x0, - 0x7f, 0x80, 0x0, 0x7f, 0xff, 0xfd, 0x0, 0x0, - 0x6, 0xff, 0x90, 0x0, - - /* U+EF7A "" */ - 0x1, 0xbf, 0x90, 0x0, 0x0, 0xbf, 0xff, 0x80, - 0x0, 0x2f, 0x40, 0x7e, 0x0, 0x7, 0xc0, 0x0, - 0xf4, 0x0, 0xb4, 0x0, 0x7, 0x80, 0xf, 0x0, - 0x0, 0x3c, 0x0, 0xf0, 0x0, 0x3, 0xc0, 0xf, - 0x0, 0x0, 0x3c, 0x0, 0xb4, 0x0, 0x7, 0x80, - 0x7, 0xc0, 0x0, 0xf0, 0x0, 0x2f, 0x40, 0x7f, - 0x0, 0x0, 0xbf, 0xff, 0xfc, 0x0, 0x1, 0xbf, - 0x83, 0xf0, 0x0, 0x0, 0x0, 0xf, 0xc0, 0x0, - 0x0, 0x0, 0x3f, 0x0, 0x0, 0x0, 0x0, 0xfc, - 0x0, 0x0, 0x0, 0x3, 0xe0, 0x0, 0x0, 0x0, - 0x8, - - /* U+EFE6 "" */ - 0x0, 0xbe, 0x0, 0x3f, 0xc0, 0x3f, 0xfc, 0x3, - 0xfc, 0xb, 0x82, 0xe0, 0xbf, 0xe0, 0xf0, 0xf, - 0xf, 0xff, 0xf, 0x0, 0xf0, 0xff, 0xf0, 0xf0, - 0xf, 0xf, 0xff, 0xf, 0x0, 0xf0, 0xff, 0xf0, - 0xf0, 0xf, 0x0, 0xf0, 0xf, 0x0, 0xf0, 0xf, - 0x0, 0xf0, 0xf, 0x0, 0xf0, 0xf, 0x0, 0xf0, - 0xf, 0xf, 0xff, 0xf, 0x0, 0xf0, 0xff, 0xf0, - 0xf0, 0xf, 0xf, 0xff, 0xf, 0x0, 0xf0, 0xff, - 0xf0, 0xf0, 0xf, 0xb, 0xfe, 0xb, 0x82, 0xe0, - 0x3f, 0xc0, 0x3f, 0xfc, 0x3, 0xfc, 0x0, 0xbe, - 0x0, - - /* U+F028 "" */ - 0x7f, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf0, 0xf0, - 0xf0, 0xf0, 0xf0, 0xff, 0xf, 0xf, 0xf, 0xf, - 0xf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x5, - 0x5, 0x5, 0x5, 0xf, 0xf0, 0xf0, 0xf0, 0xf0, - 0xf0, 0xff, 0x5, 0x5, 0x5, 0x5, 0xf, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0x3f, 0xff, - 0xc0, 0xf, 0xf0, 0x3, 0xff, 0xfc, 0x0, 0xff, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xfd, - - /* U+F090 "" */ - 0x0, 0x3, 0xc0, 0x0, 0x0, 0x3, 0xc0, 0x0, - 0x0, 0x3, 0xc0, 0x0, 0x0, 0x3, 0xc0, 0x0, - 0x0, 0x3, 0xc0, 0x0, 0x0, 0x3, 0xc0, 0x0, - 0x1, 0xd3, 0xc7, 0x40, 0x1, 0xf7, 0xdf, 0x40, - 0x0, 0xbf, 0xfd, 0x0, 0x0, 0x2f, 0xf4, 0x0, - 0x0, 0xb, 0xd0, 0x0, 0xf0, 0x1, 0x40, 0xf, - 0xf0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0xf, - 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xfd, - - /* U+F15C "" */ - 0x0, 0x0, 0xbf, 0xe0, 0x0, 0x0, 0x0, 0x7f, - 0xff, 0xd0, 0x0, 0x0, 0x1f, 0x80, 0x2f, 0x40, - 0x0, 0x3, 0xd0, 0x0, 0x7c, 0x0, 0x0, 0xb8, - 0x0, 0x2, 0xe0, 0x0, 0x2f, 0x0, 0x0, 0xf, - 0x0, 0x1f, 0xf0, 0x0, 0x0, 0xf0, 0x3, 0xe0, - 0x0, 0x0, 0xf, 0xe0, 0xb8, 0x0, 0x0, 0x0, - 0xff, 0xcf, 0x0, 0x0, 0x0, 0x0, 0x7e, 0xf0, - 0x0, 0x0, 0x0, 0x1, 0xff, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xb8, 0x0, 0x0, 0x0, 0x1, 0xf3, - 0xe0, 0x0, 0x0, 0x0, 0x7e, 0x1f, 0xff, 0xff, - 0xff, 0xff, 0xc0, 0x2f, 0xff, 0xff, 0xff, 0xe0, - - /* U+F720 "" */ - 0x0, 0x1, 0xf4, 0x0, 0x0, 0x1, 0xff, 0xf4, - 0x0, 0x0, 0xbf, 0x5f, 0xe0, 0x0, 0xbf, 0x40, - 0x1f, 0xe0, 0x3f, 0x80, 0x0, 0x2f, 0xcf, 0xe0, - 0x0, 0x0, 0xbf, 0xff, 0xc0, 0x0, 0x3f, 0xff, - 0x7f, 0x80, 0x2f, 0xdf, 0xf0, 0xbf, 0x5f, 0xe0, - 0xff, 0x0, 0xbf, 0xe0, 0xf, 0xf0, 0x1, 0xf4, - 0x0, 0xff, 0x0, 0xf, 0x0, 0xf, 0xf0, 0x0, - 0xf0, 0x0, 0xff, 0x0, 0xf, 0x0, 0xf, 0xfc, - 0x0, 0xf0, 0x3, 0xf7, 0xf8, 0xf, 0x2, 0xfd, - 0xb, 0xf4, 0xf1, 0xfe, 0x0, 0xb, 0xff, 0xfe, - 0x0, 0x0, 0x1f, 0xff, 0x40, 0x0, 0x0, 0x1f, - 0x40, 0x0, - - /* U+F8C7 "" */ - 0x0, 0x0, 0x3c, 0x0, 0x0, 0x0, 0x0, 0x3c, - 0x0, 0x0, 0x0, 0x0, 0x3c, 0x0, 0x0, 0x5, - 0x0, 0x3c, 0x0, 0x50, 0x1f, 0x0, 0x3c, 0x0, - 0xf4, 0x3d, 0x0, 0x3c, 0x0, 0x7c, 0x7c, 0x0, - 0x3c, 0x0, 0x3d, 0xb4, 0x0, 0x3c, 0x0, 0x1e, - 0xf0, 0x0, 0x3c, 0x0, 0xf, 0xf0, 0x0, 0x3c, - 0x0, 0xf, 0xf0, 0x0, 0x3c, 0x0, 0xf, 0xf0, - 0x0, 0x0, 0x0, 0xf, 0xb4, 0x0, 0x0, 0x0, - 0x1e, 0x7c, 0x0, 0x0, 0x0, 0x3d, 0x3d, 0x0, - 0x0, 0x0, 0x7c, 0x1f, 0x0, 0x0, 0x0, 0xf4, - 0xb, 0xd0, 0x0, 0x7, 0xe0, 0x2, 0xfd, 0x0, - 0x7f, 0x80, 0x0, 0x7f, 0xff, 0xfd, 0x0, 0x0, - 0x6, 0xff, 0x90, 0x0, - - /* U+FFF75 "󿽵" */ - 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0xf0, 0x0, 0x0, 0x0, 0xf, 0xf0, - 0xd0, 0x28, 0x7, 0xf, 0xf0, 0x0, 0x0, 0x0, - 0xf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x0, 0x2, 0xff, 0x80, 0xf, - 0x0, 0x7f, 0xf4, 0x28, 0xf, 0xb, 0xfe, 0x0, - 0x0, 0x2f, 0x7f, 0x90, 0x28, 0x7, 0xfd, 0xf8, - 0x34, 0x1, 0xbf, 0xe0, 0xf0, 0x10, 0x6f, 0xf9, - 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, 0xf, - 0xf0, 0xd0, 0x28, 0x7, 0xf, 0xf0, 0x0, 0x0, - 0x0, 0xf, 0xbf, 0xff, 0xff, 0xff, 0xff, 0x2f, - 0xff, 0xff, 0xff, 0xff -}; - - -/*--------------------- - * GLYPH DESCRIPTION - *--------------------*/ - -static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { - {.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */, - {.bitmap_index = 0, .adv_w = 384, .box_w = 14, .box_h = 14, .ofs_x = 5, .ofs_y = 5}, - {.bitmap_index = 49, .adv_w = 384, .box_w = 20, .box_h = 16, .ofs_x = 2, .ofs_y = 4}, - {.bitmap_index = 129, .adv_w = 384, .box_w = 13, .box_h = 20, .ofs_x = 5, .ofs_y = 2}, - {.bitmap_index = 194, .adv_w = 384, .box_w = 14, .box_h = 20, .ofs_x = 5, .ofs_y = 2}, - {.bitmap_index = 264, .adv_w = 384, .box_w = 22, .box_h = 22, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 385, .adv_w = 384, .box_w = 20, .box_h = 16, .ofs_x = 2, .ofs_y = 4}, - {.bitmap_index = 465, .adv_w = 384, .box_w = 20, .box_h = 20, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 565, .adv_w = 384, .box_w = 12, .box_h = 7, .ofs_x = 6, .ofs_y = 9}, - {.bitmap_index = 586, .adv_w = 384, .box_w = 20, .box_h = 16, .ofs_x = 2, .ofs_y = 4}, - {.bitmap_index = 666, .adv_w = 384, .box_w = 20, .box_h = 20, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 766, .adv_w = 384, .box_w = 18, .box_h = 18, .ofs_x = 3, .ofs_y = 3}, - {.bitmap_index = 847, .adv_w = 384, .box_w = 12, .box_h = 18, .ofs_x = 6, .ofs_y = 3}, - {.bitmap_index = 901, .adv_w = 384, .box_w = 16, .box_h = 18, .ofs_x = 4, .ofs_y = 3}, - {.bitmap_index = 973, .adv_w = 384, .box_w = 16, .box_h = 16, .ofs_x = 4, .ofs_y = 4}, - {.bitmap_index = 1037, .adv_w = 384, .box_w = 14, .box_h = 14, .ofs_x = 5, .ofs_y = 5}, - {.bitmap_index = 1086, .adv_w = 384, .box_w = 18, .box_h = 12, .ofs_x = 3, .ofs_y = 6}, - {.bitmap_index = 1140, .adv_w = 384, .box_w = 4, .box_h = 16, .ofs_x = 10, .ofs_y = 4}, - {.bitmap_index = 1156, .adv_w = 384, .box_w = 16, .box_h = 16, .ofs_x = 4, .ofs_y = 4}, - {.bitmap_index = 1220, .adv_w = 384, .box_w = 24, .box_h = 17, .ofs_x = 0, .ofs_y = 3}, - {.bitmap_index = 1322, .adv_w = 384, .box_w = 16, .box_h = 12, .ofs_x = 4, .ofs_y = 6}, - {.bitmap_index = 1370, .adv_w = 384, .box_w = 18, .box_h = 16, .ofs_x = 4, .ofs_y = 4}, - {.bitmap_index = 1442, .adv_w = 384, .box_w = 18, .box_h = 17, .ofs_x = 3, .ofs_y = 4}, - {.bitmap_index = 1519, .adv_w = 384, .box_w = 16, .box_h = 20, .ofs_x = 4, .ofs_y = 2}, - {.bitmap_index = 1599, .adv_w = 384, .box_w = 20, .box_h = 19, .ofs_x = 2, .ofs_y = 3}, - {.bitmap_index = 1694, .adv_w = 384, .box_w = 20, .box_h = 20, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 1794, .adv_w = 384, .box_w = 20, .box_h = 20, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 1894, .adv_w = 384, .box_w = 16, .box_h = 20, .ofs_x = 4, .ofs_y = 2}, - {.bitmap_index = 1974, .adv_w = 384, .box_w = 16, .box_h = 18, .ofs_x = 4, .ofs_y = 3}, - {.bitmap_index = 2046, .adv_w = 384, .box_w = 20, .box_h = 16, .ofs_x = 2, .ofs_y = 4}, - {.bitmap_index = 2126, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 2264, .adv_w = 384, .box_w = 18, .box_h = 18, .ofs_x = 3, .ofs_y = 3}, - {.bitmap_index = 2345, .adv_w = 384, .box_w = 20, .box_h = 20, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 2445, .adv_w = 384, .box_w = 18, .box_h = 18, .ofs_x = 3, .ofs_y = 3}, - {.bitmap_index = 2526, .adv_w = 384, .box_w = 20, .box_h = 16, .ofs_x = 2, .ofs_y = 4}, - {.bitmap_index = 2606, .adv_w = 384, .box_w = 20, .box_h = 18, .ofs_x = 2, .ofs_y = 3}, - {.bitmap_index = 2696, .adv_w = 384, .box_w = 18, .box_h = 20, .ofs_x = 3, .ofs_y = 2}, - {.bitmap_index = 2786, .adv_w = 384, .box_w = 16, .box_h = 20, .ofs_x = 4, .ofs_y = 2}, - {.bitmap_index = 2866, .adv_w = 384, .box_w = 18, .box_h = 16, .ofs_x = 4, .ofs_y = 4}, - {.bitmap_index = 2938, .adv_w = 384, .box_w = 20, .box_h = 20, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 3038, .adv_w = 384, .box_w = 18, .box_h = 18, .ofs_x = 3, .ofs_y = 3}, - {.bitmap_index = 3119, .adv_w = 384, .box_w = 18, .box_h = 18, .ofs_x = 3, .ofs_y = 3}, - {.bitmap_index = 3200, .adv_w = 384, .box_w = 22, .box_h = 16, .ofs_x = 1, .ofs_y = 4}, - {.bitmap_index = 3288, .adv_w = 384, .box_w = 16, .box_h = 16, .ofs_x = 4, .ofs_y = 4}, - {.bitmap_index = 3352, .adv_w = 384, .box_w = 22, .box_h = 16, .ofs_x = 1, .ofs_y = 4}, - {.bitmap_index = 3440, .adv_w = 384, .box_w = 18, .box_h = 20, .ofs_x = 3, .ofs_y = 2}, - {.bitmap_index = 3530, .adv_w = 384, .box_w = 20, .box_h = 20, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 3630, .adv_w = 384, .box_w = 20, .box_h = 20, .ofs_x = 2, .ofs_y = 2} -}; - -/*--------------------- - * CHARACTER MAPPING - *--------------------*/ - -static const uint16_t unicode_list_0[] = { - 0x0, 0x14, 0x62, 0x9b, 0x148, 0x182, 0x1ca, 0x1d1, - 0x1e1, 0x26a, 0x2af, 0x2c0, 0x418, 0x47e, 0x488, 0x48d, - 0x48f, 0x490, 0x4f9, 0x523, 0x600, 0x62b, 0x757, 0x76a, - 0x773, 0x7b8, 0x7ca, 0x7e9, 0x874, 0x8af, 0x8b2, 0x8c2, - 0x991, 0xa49, 0xa52, 0xa87, 0xad7, 0xdfb, 0xe05, 0xe35, - 0xea1, 0xee3, 0xf4b, 0x1017, 0x15db, 0x1782 -}; - -/*Collect the unicode lists and glyph_id offsets*/ -static const lv_font_fmt_txt_cmap_t cmaps[] = -{ - { - .range_start = 57669, .range_length = 6019, .glyph_id_start = 1, - .unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 46, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY - }, - { - .range_start = 1048437, .range_length = 1, .glyph_id_start = 47, - .unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY - } -}; - - - -/*-------------------- - * ALL CUSTOM DATA - *--------------------*/ - -#if LVGL_VERSION_MAJOR == 8 -/*Store all the custom data of the font*/ -static lv_font_fmt_txt_glyph_cache_t cache; -#endif - -#if LVGL_VERSION_MAJOR >= 8 -static const lv_font_fmt_txt_dsc_t font_dsc = { -#else -static lv_font_fmt_txt_dsc_t font_dsc = { -#endif - .glyph_bitmap = glyph_bitmap, - .glyph_dsc = glyph_dsc, - .cmaps = cmaps, - .kern_dsc = NULL, - .kern_scale = 0, - .cmap_num = 2, - .bpp = 2, - .kern_classes = 0, - .bitmap_format = 0, -#if LVGL_VERSION_MAJOR == 8 - .cache = &cache -#endif -}; - - - -/*----------------- - * PUBLIC FONT - *----------------*/ - -/*Initialize a public general font descriptor*/ -#if LVGL_VERSION_MAJOR >= 8 -const lv_font_t material_symbols_shared_24 = { -#else -lv_font_t material_symbols_shared_24 = { -#endif - .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ - .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ - .line_height = 23, /*The maximum line height required by the font*/ - .base_line = -1, /*Baseline measured from the bottom of the line*/ -#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) - .subpx = LV_FONT_SUBPX_NONE, -#endif -#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 - .underline_position = 0, - .underline_thickness = 0, -#endif - .dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ -#if LV_VERSION_CHECK(8, 2, 0) || LVGL_VERSION_MAJOR >= 9 - .fallback = NULL, -#endif - .user_data = NULL, -}; - - - -#endif /*#if MATERIAL_SYMBOLS_SHARED_24*/ - diff --git a/Modules/lvgl-module/source-fonts/material_symbols_shared_32.c b/Modules/lvgl-module/source-fonts/material_symbols_shared_32.c deleted file mode 100644 index 5ec207f01..000000000 --- a/Modules/lvgl-module/source-fonts/material_symbols_shared_32.c +++ /dev/null @@ -1,1158 +0,0 @@ -/******************************************************************************* - * Size: 32 px - * Bpp: 2 - * Opts: --no-compress --no-prefilter --bpp 2 --size 32 --font MaterialSymbolsRounded.ttf -r 0xE145,0xE5C3,0xE770,0xEF40,0xEBCC,0xEFE6,0xEF4A,0xE5CD,0xF15C,0xE668,0xE92E,0xE326,0xEB97,0xE745,0xEC1C,0xE2C7,0xF720,0xF090,0xE8AF,0xE30F,0xE8FD,0xE9F4,0xE3F4,0xE316,0xE90F,0xEA07,0xE9B9,0xE159,0xE5D2,0xE28D,0xE5D4,0xE405,0xE89C,0xF8C7,0xE5D5,0xEF7A,0xE8B8,0xE9F7,0xE55D,0xF028,0xE1E0,0xE63E,0xE1A7,0xEB8E,0xEAD6,0xE3AF,0xFFF75 --format lvgl -o source-fonts/material_symbols_shared_32.c --force-fast-kern-format - ******************************************************************************/ - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -#ifndef MATERIAL_SYMBOLS_SHARED_32 -#define MATERIAL_SYMBOLS_SHARED_32 1 -#endif - -#if MATERIAL_SYMBOLS_SHARED_32 - -/*----------------- - * BITMAPS - *----------------*/ - -/*Store the image of the glyphs*/ -static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { - /* U+E145 "" */ - 0x0, 0x0, 0x14, 0x0, 0x0, 0x0, 0x0, 0x3d, - 0x0, 0x0, 0x0, 0x0, 0x3d, 0x0, 0x0, 0x0, - 0x0, 0x3d, 0x0, 0x0, 0x0, 0x0, 0x3d, 0x0, - 0x0, 0x0, 0x0, 0x3d, 0x0, 0x0, 0x0, 0x0, - 0x3d, 0x0, 0x0, 0x0, 0x0, 0x3d, 0x0, 0x0, - 0x1a, 0xaa, 0xbe, 0xaa, 0xa4, 0x3f, 0xff, 0xff, - 0xff, 0xfd, 0x3f, 0xff, 0xff, 0xff, 0xfc, 0x0, - 0x0, 0x7e, 0x0, 0x0, 0x0, 0x0, 0x3d, 0x0, - 0x0, 0x0, 0x0, 0x3d, 0x0, 0x0, 0x0, 0x0, - 0x3d, 0x0, 0x0, 0x0, 0x0, 0x3d, 0x0, 0x0, - 0x0, 0x0, 0x3d, 0x0, 0x0, 0x0, 0x0, 0x3d, - 0x0, 0x0, 0x0, 0x0, 0x3c, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, - - /* U+E159 "" */ - 0x6, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa0, 0x2f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x3f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfd, 0x3f, 0x40, 0x0, - 0x0, 0x0, 0x0, 0xbe, 0x3f, 0xf0, 0x0, 0x0, - 0x0, 0x7, 0xfe, 0x3f, 0xfe, 0x0, 0x0, 0x0, - 0x3f, 0xfe, 0x3e, 0x7f, 0xd0, 0x0, 0x2, 0xfe, - 0x3e, 0x3e, 0xb, 0xf8, 0x0, 0x1f, 0xf0, 0x3e, - 0x3e, 0x0, 0xff, 0x40, 0xbf, 0x40, 0x3e, 0x3e, - 0x0, 0x1f, 0xfb, 0xf8, 0x0, 0x3e, 0x3e, 0x0, - 0x2, 0xff, 0xd0, 0x0, 0x3e, 0x3e, 0x0, 0x0, - 0x7e, 0x0, 0x0, 0x3e, 0x3e, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3e, 0x3e, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3e, 0x3e, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3e, 0x3e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, - 0x3e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0x3e, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0x3e, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3e, 0x3f, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfd, 0x2f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfc, 0x6, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xa0, - - /* U+E1A7 "" */ - 0x0, 0x0, 0x60, 0x0, 0x0, 0x0, 0x3f, 0x0, - 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x3, 0xff, - 0x0, 0x24, 0x0, 0xff, 0xf0, 0x2f, 0x80, 0x3e, - 0xff, 0x3, 0xf8, 0xf, 0x8b, 0xf0, 0x7f, 0x83, - 0xe0, 0xfc, 0x7, 0xf8, 0xf8, 0xfe, 0x0, 0x7f, - 0xbe, 0xfe, 0x0, 0x7, 0xff, 0xfe, 0x0, 0x0, - 0x7f, 0xfe, 0x0, 0x0, 0x3, 0xfe, 0x0, 0x0, - 0x0, 0xff, 0x80, 0x0, 0x0, 0xff, 0xf8, 0x0, - 0x0, 0xff, 0xff, 0x80, 0x0, 0xfe, 0xff, 0xf8, - 0x0, 0xfe, 0x3e, 0x7f, 0x80, 0xfe, 0xf, 0x87, - 0xf0, 0xfe, 0x3, 0xe2, 0xfc, 0xbe, 0x0, 0xfa, - 0xfc, 0xe, 0x0, 0x3f, 0xfc, 0x0, 0x0, 0xf, - 0xfc, 0x0, 0x0, 0x3, 0xfc, 0x0, 0x0, 0x0, - 0xfc, 0x0, 0x0, 0x0, 0x2c, 0x0, 0x0, - - /* U+E1E0 "" */ - 0x0, 0x0, 0x18, 0x0, 0x0, 0x0, 0x0, 0x3e, - 0x0, 0x0, 0x0, 0x0, 0xff, 0x40, 0x0, 0x0, - 0x2, 0xff, 0xc0, 0x0, 0x0, 0x3, 0xff, 0xd0, - 0x0, 0x0, 0x0, 0x3e, 0x0, 0x0, 0x0, 0x0, - 0x3e, 0x0, 0x0, 0x1, 0x0, 0x3e, 0x1, 0x54, - 0x2f, 0xc0, 0x3e, 0xf, 0xfd, 0x3f, 0xf0, 0x3e, - 0xf, 0xfd, 0x7f, 0xf0, 0x3e, 0xf, 0xfd, 0x3f, - 0xe0, 0x3e, 0xf, 0xfd, 0xf, 0xc0, 0x3e, 0xf, - 0xfc, 0xf, 0x80, 0x3e, 0x2, 0xf0, 0xf, 0x80, - 0x3e, 0x2, 0xf0, 0xf, 0xd5, 0x7e, 0x57, 0xf0, - 0xf, 0xff, 0xff, 0xff, 0xf0, 0x3, 0xff, 0xff, - 0xff, 0xc0, 0x0, 0x55, 0x7e, 0x55, 0x0, 0x0, - 0x0, 0x3e, 0x0, 0x0, 0x0, 0x0, 0x3e, 0x0, - 0x0, 0x0, 0x0, 0x7f, 0x0, 0x0, 0x0, 0x0, - 0xff, 0x80, 0x0, 0x0, 0x1, 0xff, 0xc0, 0x0, - 0x0, 0x1, 0xff, 0x80, 0x0, 0x0, 0x0, 0xbf, - 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, - - /* U+E28D "" */ - 0x0, 0x0, 0x0, 0x1a, 0x40, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xfe, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x2, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0xf, 0xc0, 0x0, 0x0, 0x0, 0x0, - 0x3, 0xe0, 0xbc, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3e, 0xb, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x3, - 0xe0, 0xbc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, - 0xb, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xe0, - 0xbc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0xb, - 0xc0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xe0, 0xbc, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0xb, 0xc0, - 0x0, 0x0, 0x0, 0x0, 0x3, 0xe0, 0xbc, 0x0, - 0x0, 0x0, 0x1, 0x55, 0x7f, 0x5f, 0xd5, 0x54, - 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, - 0x0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0x3, 0xf5, 0x55, 0x55, 0x55, 0x55, 0xfc, 0x0, - 0x3e, 0x0, 0x0, 0x0, 0x0, 0xb, 0xc0, 0x3, - 0xe0, 0x0, 0x0, 0x0, 0x0, 0xbc, 0x0, 0x3f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x7, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfd, 0x0, 0xbe, 0xaa, - 0xaa, 0xaa, 0xaa, 0xab, 0xe0, 0xf, 0xc0, 0x0, - 0x0, 0x0, 0x0, 0x3f, 0x0, 0xf8, 0x2d, 0x0, - 0xf0, 0x7, 0x82, 0xf0, 0x1f, 0x43, 0xe0, 0x1f, - 0x40, 0xbc, 0x1f, 0x42, 0xf0, 0x3e, 0x1, 0xf4, - 0xb, 0xc0, 0xf8, 0x3f, 0x3, 0xe0, 0x1f, 0x40, - 0xbc, 0xf, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x80, 0x6a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0x90, - - /* U+E2C7 "" */ - 0x6, 0xaa, 0xa9, 0x0, 0x0, 0x0, 0x0, 0x2f, - 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, 0x3f, 0xff, - 0xff, 0xe0, 0x0, 0x0, 0x0, 0x3e, 0x0, 0x3, - 0xff, 0xff, 0xff, 0xf4, 0x3e, 0x0, 0x0, 0xff, - 0xff, 0xff, 0xfd, 0x3e, 0x0, 0x0, 0x2a, 0xaa, - 0xaa, 0xbe, 0x3e, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3e, 0x3e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, - 0x3e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0x3e, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0x3e, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3e, 0x3e, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3e, 0x3e, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3e, 0x3e, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3e, 0x3e, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3e, 0x3e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, - 0x3e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0x3e, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0x3e, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3e, 0x3f, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfd, 0x2f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfc, 0x6, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xa0, - - /* U+E30F "" */ - 0x0, 0x0, 0x2, 0xaa, 0x90, 0x0, 0x0, 0x0, - 0x0, 0xb, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xc2, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xc2, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xc2, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xc2, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0xb, 0xe7, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x3, 0xff, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0x40, 0x0, 0x0, 0x2f, 0xff, - 0x80, 0x3d, 0x1, 0xff, 0xfc, 0x3f, 0xff, 0xe0, - 0x0, 0x7, 0xff, 0xfe, 0x3f, 0xab, 0xf8, 0x0, - 0x1f, 0xea, 0xbe, 0x3e, 0x0, 0xfe, 0x0, 0x3f, - 0x40, 0x3e, 0x3e, 0x0, 0xfe, 0x0, 0x3f, 0x40, - 0x3e, 0x3f, 0xab, 0xf8, 0x0, 0x1f, 0xea, 0xbe, - 0x3f, 0xff, 0xe0, 0x18, 0x7, 0xff, 0xfe, 0x2f, - 0xff, 0x80, 0x7f, 0x1, 0xff, 0xfd, 0x0, 0x0, - 0x1, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x7, - 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xd3, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xc2, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xc2, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xc2, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xeb, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0xb, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0x7, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, - - /* U+E316 "" */ - 0x0, 0x2, 0x80, 0x0, 0x0, 0xb, 0xf0, 0x0, - 0x0, 0x2f, 0xfc, 0x0, 0x0, 0xbf, 0xbf, 0x0, - 0x2, 0xfc, 0x2f, 0xc0, 0xb, 0xf0, 0xb, 0xf0, - 0x2f, 0xc0, 0x2, 0xfc, 0x3f, 0x0, 0x0, 0xbe, - 0x3c, 0x0, 0x0, 0x2d, - - /* U+E326 "" */ - 0x1, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x90, 0x7, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xe0, 0xf, 0x80, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0x80, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0x80, 0x0, 0x0, 0x6, - 0xaa, 0xa4, 0xf, 0x80, 0x0, 0x0, 0x3f, 0xff, - 0xfd, 0xf, 0x80, 0x0, 0x0, 0x3f, 0xff, 0xfe, - 0xf, 0x80, 0x0, 0x0, 0x3e, 0x0, 0x3e, 0xf, - 0x80, 0x0, 0x0, 0x3e, 0x4, 0x3e, 0xf, 0x80, - 0x0, 0x0, 0x3e, 0x2c, 0x3e, 0xf, 0x80, 0x0, - 0x0, 0x3e, 0x18, 0x3e, 0xf, 0x80, 0x0, 0x0, - 0x3e, 0x0, 0x3e, 0xf, 0x80, 0x0, 0x0, 0x3e, - 0x0, 0x3e, 0xf, 0x80, 0x0, 0x0, 0x3e, 0x0, - 0x3e, 0xf, 0xff, 0xff, 0xe0, 0x3e, 0x0, 0x3e, - 0x7, 0xff, 0xff, 0xf0, 0x3e, 0x0, 0x3e, 0x1, - 0xaa, 0xaa, 0x90, 0x3e, 0x0, 0x3e, 0x0, 0x0, - 0x0, 0x0, 0x3e, 0x0, 0x3e, 0x3f, 0xff, 0xff, - 0xe0, 0x3f, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xf0, - 0x3f, 0xff, 0xfd, 0x2a, 0xaa, 0xaa, 0x90, 0xa, - 0xaa, 0xa4, - - /* U+E3AF "" */ - 0x0, 0x0, 0x1, 0x55, 0x40, 0x0, 0x0, 0x0, - 0x0, 0x2f, 0xff, 0xfd, 0x0, 0x0, 0x0, 0x2, - 0xff, 0xff, 0xff, 0xc0, 0x0, 0x0, 0x1f, 0xfe, - 0x42, 0xef, 0xf4, 0x0, 0x0, 0x7f, 0xd0, 0x3, - 0x42, 0xfe, 0x0, 0x1, 0xfe, 0x0, 0xb, 0x0, - 0x7f, 0x40, 0x3, 0xfc, 0x0, 0x1d, 0x0, 0x1f, - 0xc0, 0xb, 0xfd, 0x0, 0x38, 0x0, 0x7, 0xe0, - 0xf, 0xcb, 0x0, 0x70, 0x0, 0x3, 0xf4, 0x2f, - 0x43, 0x40, 0xf0, 0x0, 0x1, 0xf8, 0x3f, 0x2, - 0xc2, 0xff, 0xff, 0xff, 0xfc, 0x3e, 0x0, 0xe3, - 0xff, 0xf5, 0x55, 0xbc, 0x3e, 0x0, 0x7f, 0xff, - 0xf0, 0x0, 0x7d, 0x3d, 0x0, 0x3f, 0xff, 0xf4, - 0x0, 0x7d, 0x3d, 0x0, 0xf, 0xff, 0xfc, 0x0, - 0x7d, 0x3e, 0x0, 0xb, 0xff, 0xfe, 0x0, 0x7d, - 0x3f, 0x55, 0x5b, 0xff, 0xd7, 0x0, 0xbc, 0x2f, - 0xff, 0xff, 0xff, 0x83, 0xc0, 0xfc, 0x1f, 0x40, - 0x0, 0xf, 0x0, 0xd1, 0xf8, 0xf, 0xc0, 0x0, - 0xe, 0x0, 0xb3, 0xf0, 0x7, 0xe0, 0x0, 0x2c, - 0x0, 0x3f, 0xe0, 0x2, 0xf8, 0x0, 0x34, 0x0, - 0x2f, 0xc0, 0x0, 0xfe, 0x0, 0xe0, 0x0, 0xbf, - 0x0, 0x0, 0x3f, 0xd1, 0xc0, 0x7, 0xfc, 0x0, - 0x0, 0xb, 0xff, 0xea, 0xff, 0xf0, 0x0, 0x0, - 0x1, 0xff, 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, - 0x1b, 0xff, 0xe4, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, - - /* U+E3F4 "" */ - 0x2f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xbf, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xaa, 0xaa, 0xaa, - 0xaa, 0xbf, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f, - 0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xf8, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x0, - 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f, - 0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xf8, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x0, - 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f, - 0xf8, 0x0, 0x0, 0x5, 0x0, 0x2f, 0xf8, 0x0, - 0x0, 0xf, 0x0, 0x2f, 0xf8, 0x3, 0xc0, 0x3f, - 0xc0, 0x2f, 0xf8, 0xb, 0xe0, 0xbf, 0xe0, 0x2f, - 0xf8, 0x1f, 0xf5, 0xff, 0xf4, 0x2f, 0xf8, 0x3f, - 0xff, 0xff, 0xfc, 0x2f, 0xf8, 0x2a, 0xaa, 0xaa, - 0xa8, 0x2f, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f, - 0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xfe, 0xaa, - 0xaa, 0xaa, 0xaa, 0xbf, 0xbf, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xf8, - - /* U+E405 "" */ - 0x0, 0x0, 0xbf, 0xfe, 0x0, 0x0, 0xff, 0xff, - 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, - 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xfd, 0x54, - 0x0, 0x0, 0xf8, 0x0, 0x0, 0x0, 0xf8, 0x0, - 0x0, 0x0, 0xf8, 0x0, 0x0, 0x0, 0xf8, 0x0, - 0x0, 0x0, 0xf8, 0x0, 0x0, 0x0, 0xf8, 0x0, - 0x0, 0x0, 0xf8, 0x0, 0x1, 0xa8, 0xf8, 0x0, - 0xf, 0xff, 0xf8, 0x0, 0x3f, 0xff, 0xf8, 0x0, - 0xbf, 0xff, 0xf8, 0x0, 0xff, 0xff, 0xf8, 0x0, - 0xff, 0xff, 0xf8, 0x0, 0xff, 0xff, 0xf8, 0x0, - 0xbf, 0xff, 0xf4, 0x0, 0x3f, 0xff, 0xf0, 0x0, - 0x1f, 0xff, 0xc0, 0x0, 0x2, 0xfe, 0x0, 0x0, - - /* U+E55D "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0x80, 0x0, - 0x0, 0x0, 0x3, 0xfc, 0x0, 0x0, 0x0, 0x0, - 0xbf, 0xe0, 0x0, 0x0, 0x0, 0xf, 0xff, 0x0, - 0x0, 0x0, 0x1, 0xf5, 0xf4, 0x0, 0x0, 0x0, - 0x3f, 0xf, 0xc0, 0x0, 0x0, 0x7, 0xe0, 0xbd, - 0x0, 0x0, 0x0, 0xfc, 0x3, 0xf0, 0x0, 0x0, - 0x1f, 0x80, 0x2f, 0x40, 0x0, 0x2, 0xf0, 0x0, - 0xf8, 0x0, 0x0, 0x3e, 0x0, 0xf, 0xc0, 0x0, - 0xb, 0xd0, 0x0, 0x7e, 0x0, 0x0, 0xfc, 0x0, - 0x3, 0xf0, 0x0, 0x1f, 0x40, 0x0, 0x1f, 0x40, - 0x3, 0xf0, 0x0, 0x0, 0xfc, 0x0, 0x7e, 0x1, - 0xa4, 0xb, 0xd0, 0xf, 0xc1, 0xff, 0xf4, 0x3f, - 0x1, 0xfe, 0xff, 0xff, 0xfb, 0xf4, 0x2f, 0xff, - 0xe0, 0xbf, 0xff, 0x83, 0xff, 0xd0, 0x0, 0x7f, - 0xfc, 0x7f, 0xd0, 0x0, 0x0, 0x7f, 0xd2, 0x80, - 0x0, 0x0, 0x0, 0x28, - - /* U+E5C3 "" */ - 0x5, 0x0, 0x5, 0x0, 0x5, 0x3, 0xfc, 0x3, - 0xfc, 0x3, 0xfc, 0xbf, 0xd0, 0xbf, 0xd0, 0xbf, - 0xdb, 0xfe, 0xb, 0xfe, 0xb, 0xfe, 0x7f, 0xc0, - 0x7f, 0xc0, 0x7f, 0xc1, 0xe4, 0x1, 0xe4, 0x1, - 0xe4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x5, 0x0, 0x5, 0x0, - 0x5, 0x3, 0xfc, 0x3, 0xfc, 0x3, 0xfc, 0xbf, - 0xd0, 0xbf, 0xd0, 0xbf, 0xdb, 0xfe, 0xb, 0xfe, - 0xb, 0xfe, 0x7f, 0xc0, 0x7f, 0xc0, 0x7f, 0xc1, - 0xe4, 0x1, 0xe4, 0x1, 0xe4, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x5, 0x0, 0x5, 0x0, 0x5, 0x3, 0xfc, 0x3, - 0xfc, 0x3, 0xfc, 0xbf, 0xd0, 0xbf, 0xd0, 0xbf, - 0xdb, 0xfe, 0xb, 0xfe, 0xb, 0xfe, 0x7f, 0xc0, - 0x7f, 0xc0, 0x7f, 0xc1, 0xe4, 0x1, 0xe4, 0x1, - 0xe4, - - /* U+E5CD "" */ - 0x24, 0x0, 0x0, 0x1, 0x8b, 0xd0, 0x0, 0x0, - 0x7e, 0x7f, 0x40, 0x0, 0x1f, 0xd1, 0xfd, 0x0, - 0x7, 0xf4, 0x7, 0xf4, 0x1, 0xfd, 0x0, 0x1f, - 0xd0, 0x7f, 0x40, 0x0, 0x7f, 0x5f, 0xd0, 0x0, - 0x1, 0xff, 0xf4, 0x0, 0x0, 0x7, 0xfd, 0x0, - 0x0, 0x0, 0x7f, 0xd0, 0x0, 0x0, 0x1f, 0xff, - 0x40, 0x0, 0x7, 0xf5, 0xfd, 0x0, 0x1, 0xfd, - 0x7, 0xf4, 0x0, 0x7f, 0x40, 0x1f, 0xd0, 0x1f, - 0xd0, 0x0, 0x7f, 0x47, 0xf4, 0x0, 0x1, 0xfd, - 0xbd, 0x0, 0x0, 0x7, 0xe7, 0x40, 0x0, 0x0, - 0x1d, - - /* U+E5D2 "" */ - 0xbf, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x6a, 0xaa, 0xaa, 0xaa, - 0xaa, 0xa9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x2a, 0xaa, 0xaa, 0xaa, - 0xaa, 0xa8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xbf, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6a, 0xaa, - 0xaa, 0xaa, 0xaa, 0xa9, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xfe, - - /* U+E5D4 "" */ - 0x5, 0x3, 0xfc, 0xbf, 0xdb, 0xfe, 0x7f, 0xc1, - 0xe4, 0x0, 0x0, 0x0, 0x5, 0x3, 0xfc, 0xbf, - 0xdb, 0xfe, 0x7f, 0xc1, 0xe4, 0x0, 0x0, 0x0, - 0x5, 0x3, 0xfc, 0xbf, 0xdb, 0xfe, 0x7f, 0xc1, - 0xe4, - - /* U+E5D5 "" */ - 0x0, 0x0, 0x6a, 0x90, 0x1, 0x80, 0x0, 0xbf, - 0xff, 0xe0, 0x3e, 0x0, 0x7f, 0xff, 0xff, 0xd3, - 0xe0, 0x2f, 0xf4, 0x1, 0xff, 0x7e, 0x7, 0xf4, - 0x0, 0x1, 0xff, 0xe0, 0xfc, 0x0, 0x0, 0x7, - 0xfe, 0x2f, 0x40, 0x0, 0x0, 0x1f, 0xe3, 0xf0, - 0x0, 0x7, 0xff, 0xfe, 0x7d, 0x0, 0x0, 0xbf, - 0xff, 0xeb, 0xc0, 0x0, 0x2, 0xaa, 0xa8, 0xbc, - 0x0, 0x0, 0x0, 0x0, 0xb, 0xc0, 0x0, 0x0, - 0x0, 0x0, 0xbc, 0x0, 0x0, 0x0, 0x0, 0x7, - 0xd0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0x0, 0x0, - 0x0, 0xb, 0x42, 0xf4, 0x0, 0x0, 0x1, 0xf8, - 0xf, 0xc0, 0x0, 0x0, 0x7f, 0x0, 0x7f, 0x40, - 0x0, 0x1f, 0xd0, 0x2, 0xff, 0x40, 0x1f, 0xf8, - 0x0, 0x7, 0xff, 0xff, 0xfd, 0x0, 0x0, 0xb, - 0xff, 0xfe, 0x0, 0x0, 0x0, 0x6, 0xa9, 0x0, - 0x0, - - /* U+E63E "" */ - 0x0, 0x0, 0x1, 0xaf, 0xfa, 0x40, 0x0, 0x0, - 0x0, 0x0, 0xbf, 0xff, 0xff, 0xfe, 0x0, 0x0, - 0x0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x0, - 0x0, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, - 0x7, 0xff, 0xfe, 0x50, 0x5, 0xbf, 0xff, 0xd0, - 0x2f, 0xff, 0xd0, 0x0, 0x0, 0x7, 0xff, 0xf8, - 0x3f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfc, - 0x3f, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xfc, - 0x1a, 0x0, 0x0, 0x6b, 0xe9, 0x0, 0x0, 0xa4, - 0x0, 0x0, 0x1b, 0xff, 0xff, 0xe0, 0x0, 0x0, - 0x0, 0x0, 0xbf, 0xff, 0xff, 0xfe, 0x0, 0x0, - 0x0, 0x3, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0, - 0x0, 0x7, 0xff, 0xd4, 0x17, 0xff, 0xd0, 0x0, - 0x0, 0x3, 0xfc, 0x0, 0x0, 0x3f, 0xc0, 0x0, - 0x0, 0x0, 0x90, 0x0, 0x0, 0x6, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x6, 0x90, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x1f, 0xf4, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3f, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7f, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3f, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xb, 0xe0, 0x0, 0x0, 0x0, - - /* U+E668 "" */ - 0x0, 0x0, 0x0, 0x0, 0x1, 0x40, 0x0, 0x0, - 0x0, 0x0, 0xbc, 0x0, 0x0, 0x0, 0x0, 0x2f, - 0xc0, 0x0, 0x0, 0x0, 0xb, 0xf0, 0x0, 0x0, - 0x0, 0x2, 0xfc, 0x0, 0x0, 0x0, 0x0, 0xbf, - 0x40, 0x0, 0x0, 0x0, 0x2f, 0xd0, 0x3, 0xc0, - 0x0, 0xb, 0xf4, 0x0, 0x7f, 0x0, 0x2, 0xfd, - 0x0, 0x2, 0xfc, 0x0, 0xbf, 0x40, 0x0, 0xb, - 0xf0, 0x2f, 0xd0, 0x0, 0x0, 0x2f, 0xcb, 0xf4, - 0x0, 0x0, 0x0, 0xbf, 0xfd, 0x0, 0x0, 0x0, - 0x2, 0xff, 0x40, 0x0, 0x0, 0x0, 0xb, 0xd0, - 0x0, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, - - /* U+E745 "" */ - 0x2a, 0xaa, 0xaa, 0xa0, 0x0, 0x0, 0x2f, 0xff, - 0xff, 0xfe, 0x0, 0x0, 0x7, 0xff, 0xff, 0xff, - 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, - 0xaa, 0xaa, 0xa8, 0x0, 0x0, 0xb, 0xff, 0xff, - 0xff, 0x80, 0x0, 0x1, 0xff, 0xff, 0xff, 0xd0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x14, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3f, 0x81, 0xff, 0xff, 0x0, - 0x0, 0x3f, 0xf8, 0xbf, 0xff, 0xe0, 0x0, 0x3f, - 0xff, 0xa, 0xaa, 0xa0, 0x0, 0x2f, 0xff, 0xc0, - 0x0, 0x0, 0x0, 0x2f, 0xbf, 0xd0, 0x0, 0x0, - 0x0, 0x2f, 0xf, 0xe0, 0x0, 0x0, 0x0, 0x2f, - 0x7, 0xe0, 0x0, 0x0, 0x0, 0x2f, 0x7, 0xe0, - 0x0, 0x0, 0x0, 0xf, 0x7, 0xe0, 0x0, 0x0, - 0x0, 0x3, 0xc7, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xe0, - 0x0, 0x0, - - /* U+E770 "" */ - 0x0, 0x0, 0x2, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, - 0x40, 0x0, 0x0, 0x0, 0x3f, 0x2f, 0xe0, 0x0, - 0x0, 0x0, 0xfd, 0x7, 0xfe, 0xa4, 0x10, 0x2, - 0xf8, 0x0, 0xff, 0xfd, 0xfc, 0x7, 0xf0, 0x0, - 0x3f, 0xff, 0xff, 0x4f, 0xc0, 0x0, 0x0, 0x2f, - 0xff, 0xff, 0x80, 0x0, 0x0, 0x2f, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x2f, 0xf9, 0xfc, 0x0, 0x40, - 0x0, 0x2f, 0xf8, 0x34, 0x3, 0xe0, 0x0, 0x2f, - 0xf8, 0x0, 0xb, 0xf8, 0x0, 0x2f, 0xf8, 0x0, - 0x1f, 0xff, 0x0, 0x2f, 0xfc, 0x0, 0x3f, 0xff, - 0xd0, 0x2f, 0xff, 0x0, 0xbf, 0xff, 0xf8, 0x2f, - 0xff, 0xd1, 0xff, 0xff, 0xff, 0x2f, 0xff, 0xfb, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, - - /* U+E89C "" */ - 0x6, 0xaa, 0xaa, 0x90, 0x0, 0x3, 0xff, 0xff, - 0xff, 0x80, 0x0, 0xbf, 0xff, 0xff, 0xfe, 0x0, - 0xb, 0xc0, 0x0, 0xb, 0xf8, 0x0, 0xbc, 0x0, - 0x0, 0xbf, 0xe0, 0xb, 0xc0, 0x0, 0xb, 0xff, - 0x80, 0xbc, 0x0, 0x0, 0xbf, 0xfe, 0xb, 0xc0, - 0x0, 0xb, 0xff, 0xf8, 0xbc, 0x0, 0x0, 0xbf, - 0xff, 0xdb, 0xc0, 0x0, 0x2, 0xff, 0xfe, 0xbc, - 0x0, 0x0, 0x0, 0x3, 0xeb, 0xc0, 0x0, 0xa0, - 0x0, 0x3e, 0xbc, 0x0, 0x1f, 0x40, 0x3, 0xeb, - 0xc0, 0x1, 0xf4, 0x0, 0x3e, 0xbc, 0x0, 0x1f, - 0x40, 0x3, 0xeb, 0xc0, 0xbf, 0xff, 0xe0, 0x3e, - 0xbc, 0x1f, 0xff, 0xff, 0x43, 0xeb, 0xc0, 0xbf, - 0xff, 0xe0, 0x3e, 0xbc, 0x0, 0x1f, 0x40, 0x3, - 0xeb, 0xc0, 0x1, 0xf4, 0x0, 0x3e, 0xbc, 0x0, - 0x1f, 0x40, 0x3, 0xeb, 0xc0, 0x0, 0xa0, 0x0, - 0x3e, 0xbc, 0x0, 0x0, 0x0, 0x3, 0xeb, 0xc0, - 0x0, 0x0, 0x0, 0x3e, 0xbe, 0xaa, 0xaa, 0xaa, - 0xab, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x2f, - 0xff, 0xff, 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, - 0x0, 0x0, - - /* U+E8AF "" */ - 0x6, 0xaa, 0xaa, 0xaa, 0xa4, 0x0, 0x0, 0x1f, - 0xff, 0xff, 0xff, 0xff, 0x40, 0x0, 0x3f, 0xff, - 0xff, 0xff, 0xff, 0xc0, 0x0, 0x3e, 0x0, 0x0, - 0x0, 0xf, 0xc0, 0x0, 0x3e, 0x0, 0x0, 0x0, - 0xf, 0xc0, 0x0, 0x3e, 0x0, 0x0, 0x0, 0xf, - 0xc0, 0x0, 0x3e, 0x0, 0x0, 0x0, 0xf, 0xc0, - 0xfc, 0x3e, 0x0, 0x0, 0x0, 0xf, 0xc0, 0xfe, - 0x3e, 0x0, 0x0, 0x0, 0xf, 0xc0, 0xfe, 0x3e, - 0x0, 0x0, 0x0, 0xf, 0xc0, 0xff, 0x3e, 0x0, - 0x0, 0x0, 0xf, 0xc0, 0xff, 0x3e, 0x0, 0x0, - 0x0, 0xf, 0xc0, 0xff, 0x3e, 0x2a, 0xaa, 0xaa, - 0xaf, 0xc0, 0xff, 0x3e, 0xff, 0xff, 0xff, 0xff, - 0x80, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xfe, 0x0, - 0xff, 0x3f, 0xf0, 0x0, 0x0, 0x0, 0x1, 0xff, - 0x3f, 0xc0, 0x0, 0x0, 0x0, 0x2, 0xff, 0x3f, - 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, 0x28, 0xf, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0xb, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x0, 0x7, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x0, 0x2, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, - - /* U+E8B8 "" */ - 0x0, 0x0, 0x6, 0xa9, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xff, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x3f, - 0xff, 0xc0, 0x0, 0x0, 0x0, 0x3, 0xe0, 0xbc, - 0x0, 0x0, 0x1, 0x40, 0x7e, 0x7, 0xc0, 0x14, - 0x0, 0xbf, 0xaf, 0xd0, 0x7f, 0xaf, 0xe0, 0xf, - 0xff, 0xfc, 0x3, 0xff, 0xff, 0x3, 0xfb, 0xfd, - 0x0, 0x7, 0xfe, 0xfc, 0x7e, 0x2, 0x0, 0x0, - 0x8, 0xb, 0xdb, 0xd0, 0x0, 0x2f, 0x80, 0x0, - 0x7e, 0x7f, 0x40, 0x1f, 0xff, 0x40, 0x1f, 0xd2, - 0xfe, 0x3, 0xff, 0xfc, 0xb, 0xf8, 0x7, 0xf0, - 0x7f, 0xff, 0xe0, 0xfd, 0x0, 0x3e, 0xb, 0xff, - 0xfe, 0xb, 0xc0, 0x3, 0xe0, 0xbf, 0xff, 0xe0, - 0xbc, 0x0, 0xff, 0x7, 0xff, 0xfd, 0xf, 0xf0, - 0x3f, 0xc0, 0x2f, 0xff, 0xc0, 0x3f, 0xcb, 0xe0, - 0x0, 0xbf, 0xe0, 0x0, 0xbe, 0xbd, 0x0, 0x0, - 0x50, 0x0, 0x7, 0xe3, 0xf0, 0xb8, 0x0, 0x1, - 0xe0, 0xfc, 0x2f, 0xff, 0xf4, 0x1, 0xff, 0xff, - 0x40, 0xff, 0xff, 0xd0, 0x7f, 0xff, 0xf0, 0x3, - 0xe4, 0xbd, 0x7, 0xe1, 0xbc, 0x0, 0x0, 0x3, - 0xe0, 0xbc, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xaf, - 0xc0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xf8, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - - /* U+E8FD "" */ - 0x0, 0x0, 0x1, 0x55, 0x40, 0x0, 0x0, 0x0, - 0x0, 0x6f, 0xff, 0xfd, 0x0, 0x0, 0x0, 0x2, - 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, 0x1f, 0xfd, - 0x41, 0x6f, 0xf4, 0x0, 0x0, 0x7f, 0x80, 0x0, - 0x2, 0xfe, 0x0, 0x1, 0xfd, 0x0, 0x0, 0x0, - 0x7f, 0x40, 0x3, 0xf4, 0x1, 0xff, 0x80, 0xf, - 0xc0, 0xb, 0xd0, 0x7, 0xff, 0xf0, 0x7, 0xf0, - 0xf, 0xc0, 0xf, 0xd6, 0xf8, 0x2, 0xf4, 0x2f, - 0x40, 0xb, 0x0, 0xfc, 0x0, 0xf8, 0x3f, 0x0, - 0x0, 0x0, 0xf8, 0x0, 0xfc, 0x3e, 0x0, 0x0, - 0x1, 0xf4, 0x0, 0x7c, 0x3e, 0x0, 0x0, 0x3, - 0xe0, 0x0, 0x7d, 0x3d, 0x0, 0x0, 0xf, 0xc0, - 0x0, 0x7d, 0x3d, 0x0, 0x0, 0x3f, 0x0, 0x0, - 0x7d, 0x3e, 0x0, 0x0, 0x3d, 0x0, 0x0, 0x7d, - 0x3f, 0x0, 0x0, 0x28, 0x0, 0x0, 0xbc, 0x2f, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xfc, 0x1f, 0x40, - 0x0, 0x0, 0x0, 0x1, 0xf8, 0xf, 0xc0, 0x0, - 0x7d, 0x0, 0x3, 0xf0, 0x7, 0xf0, 0x0, 0xbe, - 0x0, 0xb, 0xe0, 0x3, 0xf8, 0x0, 0x28, 0x0, - 0x2f, 0xc0, 0x0, 0xff, 0x0, 0x0, 0x0, 0xbf, - 0x0, 0x0, 0x3f, 0xe0, 0x0, 0x7, 0xfd, 0x0, - 0x0, 0xb, 0xff, 0xaa, 0xff, 0xf0, 0x0, 0x0, - 0x1, 0xff, 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, - 0x1b, 0xff, 0xe4, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, - - /* U+E90F "" */ - 0x0, 0x0, 0x55, 0x0, 0x0, 0x0, 0x1f, 0xff, - 0xf4, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x3, - 0xfe, 0x41, 0xbf, 0xc0, 0xf, 0xe0, 0x0, 0xb, - 0xf0, 0x2f, 0x80, 0x0, 0x2, 0xf8, 0x3f, 0x0, - 0x0, 0x0, 0xfc, 0xbd, 0x0, 0x0, 0x0, 0x7e, - 0xfc, 0x0, 0x0, 0x0, 0x3f, 0xfc, 0x0, 0x0, - 0x0, 0x3f, 0xf8, 0x0, 0x0, 0x0, 0x2f, 0xfc, - 0x0, 0x0, 0x0, 0x3f, 0xfc, 0x0, 0x0, 0x0, - 0x3f, 0xbd, 0x0, 0x0, 0x0, 0x7e, 0x3f, 0x0, - 0x0, 0x0, 0xfc, 0x2f, 0xc0, 0x0, 0x2, 0xf8, - 0xf, 0xfa, 0xaa, 0xaf, 0xf0, 0x3, 0xff, 0xff, - 0xff, 0xc0, 0x0, 0xbf, 0xff, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x1a, 0xaa, 0xa4, - 0x0, 0x0, 0x3f, 0xff, 0xfd, 0x0, 0x0, 0x3f, - 0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x1, 0xaa, 0x40, 0x0, 0x0, 0x1, 0xff, - 0x40, 0x0, 0x0, 0x0, 0xbe, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, - - /* U+E92E "" */ - 0x0, 0x2, 0xff, 0xf8, 0x0, 0x2, 0xaa, 0xbf, - 0xff, 0xea, 0xa8, 0xbf, 0xff, 0xff, 0xff, 0xff, - 0xe7, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x1f, 0x40, - 0x0, 0x0, 0x1f, 0x41, 0xf4, 0x0, 0x0, 0x1, - 0xf4, 0x1f, 0x40, 0x40, 0x10, 0x1f, 0x41, 0xf4, - 0x3e, 0xb, 0xc1, 0xf4, 0x1f, 0x43, 0xe0, 0xbc, - 0x1f, 0x41, 0xf4, 0x3e, 0xb, 0xc1, 0xf4, 0x1f, - 0x43, 0xe0, 0xbc, 0x1f, 0x41, 0xf4, 0x3e, 0xb, - 0xc1, 0xf4, 0x1f, 0x43, 0xe0, 0xbc, 0x1f, 0x41, - 0xf4, 0x3e, 0xb, 0xc1, 0xf4, 0x1f, 0x43, 0xe0, - 0xbc, 0x1f, 0x41, 0xf4, 0x3e, 0xb, 0xc1, 0xf4, - 0x1f, 0x43, 0xe0, 0xbc, 0x1f, 0x41, 0xf4, 0x3e, - 0xb, 0xc1, 0xf4, 0x1f, 0x41, 0x80, 0x24, 0x1f, - 0x41, 0xf4, 0x0, 0x0, 0x1, 0xf4, 0x1f, 0x40, - 0x0, 0x0, 0x1f, 0x41, 0xfe, 0xaa, 0xaa, 0xab, - 0xf0, 0xf, 0xff, 0xff, 0xff, 0xff, 0x0, 0x3f, - 0xff, 0xff, 0xff, 0xc0, - - /* U+E9B9 "" */ - 0x5, 0x0, 0x5, 0x55, 0x55, 0x55, 0x50, 0x2f, - 0xd0, 0x2f, 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xf0, - 0x3f, 0xff, 0xff, 0xff, 0xfd, 0x7f, 0xf0, 0x3f, - 0xff, 0xff, 0xff, 0xfd, 0x3f, 0xe0, 0x3f, 0xff, - 0xff, 0xff, 0xfc, 0xb, 0x80, 0xb, 0xff, 0xff, - 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x5, 0x0, 0x5, 0x55, 0x55, 0x55, 0x50, 0x2f, - 0xd0, 0x2f, 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xf0, - 0x3f, 0xff, 0xff, 0xff, 0xfd, 0x7f, 0xf0, 0x3f, - 0xff, 0xff, 0xff, 0xfd, 0x3f, 0xe0, 0x3f, 0xff, - 0xff, 0xff, 0xfc, 0xb, 0x80, 0xb, 0xff, 0xff, - 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x5, 0x0, 0x5, 0x55, 0x55, 0x55, 0x50, 0x2f, - 0xd0, 0x2f, 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xf0, - 0x3f, 0xff, 0xff, 0xff, 0xfd, 0x7f, 0xf0, 0x3f, - 0xff, 0xff, 0xff, 0xfd, 0x3f, 0xe0, 0x3f, 0xff, - 0xff, 0xff, 0xfc, 0xb, 0x80, 0xb, 0xff, 0xff, - 0xff, 0xe0, - - /* U+E9F4 "" */ - 0x0, 0x0, 0x0, 0xb, 0xe0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3f, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xbf, 0xfe, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xfc, 0x3f, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xfc, 0x3f, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xbf, 0xfe, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3f, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xb, 0xe0, 0x0, 0x0, 0x0, - 0x1, 0x40, 0x0, 0x3, 0xc0, 0x0, 0x1, 0x40, - 0x1f, 0xf4, 0x0, 0x3, 0xc0, 0x0, 0x1f, 0xf4, - 0x7f, 0xfd, 0x0, 0x3, 0xc0, 0x0, 0x7f, 0xfd, - 0xfd, 0x7f, 0x0, 0x2f, 0xf8, 0x0, 0xfd, 0x7f, - 0xf8, 0x2f, 0x1, 0xff, 0xff, 0x40, 0xf8, 0x2f, - 0xfc, 0x3f, 0xe7, 0xf9, 0x6f, 0xdb, 0xfc, 0x3f, - 0xbf, 0xff, 0xff, 0xe0, 0xb, 0xff, 0xff, 0xfe, - 0x3f, 0xf8, 0x2f, 0xc0, 0x3, 0xf8, 0x2f, 0xf8, - 0x6, 0x90, 0xf, 0x80, 0x2, 0xf0, 0x6, 0x90, - 0x0, 0x0, 0xf, 0xc0, 0x3, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0xb, 0xd0, 0x7, 0xe0, 0x0, 0x0, - 0x0, 0x0, 0x3, 0xf4, 0x1f, 0xc0, 0x0, 0x0, - 0x0, 0x0, 0x2, 0xff, 0xff, 0x80, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x1, 0x5f, 0x45, 0x51, 0xf5, 0x40, 0x0, - 0x0, 0x2f, 0xfe, 0x0, 0x0, 0xbf, 0xf8, 0x0, - 0x0, 0x7f, 0xfd, 0x0, 0x0, 0x7f, 0xfd, 0x0, - 0x0, 0xfd, 0x7f, 0x0, 0x0, 0xfd, 0x7f, 0x0, - 0x0, 0xf8, 0x2f, 0x0, 0x0, 0xf8, 0x2f, 0x0, - 0x0, 0xfc, 0x3f, 0x0, 0x0, 0xfc, 0x3f, 0x0, - 0x0, 0xbf, 0xfe, 0x0, 0x0, 0xbf, 0xfe, 0x0, - 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x2f, 0xf8, 0x0, - 0x0, 0x6, 0x90, 0x0, 0x0, 0x6, 0x90, 0x0, - - /* U+E9F7 "" */ - 0x2f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xbf, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xaa, 0xaa, 0xaa, - 0xaa, 0xbf, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f, - 0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xf8, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xfe, 0xaa, 0xaa, 0xaa, - 0xaa, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x0, - 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f, - 0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xf8, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x0, - 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f, - 0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xf8, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x0, - 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f, - 0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xfe, 0xaa, - 0xaa, 0xaa, 0xaa, 0xbf, 0xbf, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xf8, - - /* U+EA07 "" */ - 0x0, 0x0, 0x1, 0x69, 0x40, 0x0, 0x0, 0x0, - 0x0, 0x6f, 0xff, 0xfd, 0x0, 0x0, 0x0, 0x2, - 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, 0x1f, 0xff, - 0xfb, 0xff, 0xf4, 0x0, 0x0, 0x7f, 0x8b, 0xd3, - 0xf2, 0xfe, 0x0, 0x1, 0xfd, 0xf, 0x82, 0xf4, - 0x7f, 0x40, 0x3, 0xf4, 0x2f, 0x40, 0xfc, 0xf, - 0xc0, 0xb, 0xe0, 0x3f, 0x0, 0xbc, 0x7, 0xf0, - 0xf, 0xea, 0xbf, 0xaa, 0xfe, 0xab, 0xf4, 0x2f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0x3e, 0x0, 0xfc, - 0x0, 0x3f, 0x0, 0xbc, 0x3e, 0x0, 0xfc, 0x0, - 0x2f, 0x0, 0x7d, 0x3d, 0x0, 0xfc, 0x0, 0x2f, - 0x0, 0x7d, 0x3d, 0x0, 0xfc, 0x0, 0x2f, 0x0, - 0x7d, 0x3e, 0x0, 0xfc, 0x0, 0x2f, 0x0, 0x7d, - 0x3f, 0xaa, 0xfe, 0xaa, 0xbf, 0xaa, 0xfc, 0x2f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x1f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xf8, 0xf, 0xd0, 0x3f, - 0x0, 0xbd, 0x3, 0xf0, 0x7, 0xf0, 0x3f, 0x0, - 0xfc, 0xb, 0xe0, 0x2, 0xfc, 0x1f, 0x41, 0xf8, - 0x2f, 0xc0, 0x0, 0xff, 0xf, 0xc3, 0xf0, 0xbf, - 0x0, 0x0, 0x3f, 0xeb, 0xe7, 0xfb, 0xfc, 0x0, - 0x0, 0xb, 0xff, 0xff, 0xff, 0xf0, 0x0, 0x0, - 0x1, 0xff, 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, - 0x1b, 0xff, 0xe4, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, - - /* U+EAD6 "" */ - 0x2f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xbf, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xaa, 0xaa, 0xaa, - 0xaa, 0xbf, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f, - 0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xf8, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x0, - 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f, - 0xf8, 0xff, 0x4f, 0xe7, 0x7, 0x2f, 0xf8, 0xe7, - 0xdd, 0x47, 0x4b, 0x2f, 0xf8, 0xd3, 0xdc, 0x3, - 0x8e, 0x2f, 0xf8, 0xd3, 0xdf, 0x82, 0xcd, 0x2f, - 0xf8, 0xd3, 0xde, 0x1, 0xec, 0x2f, 0xf8, 0xd3, - 0xdc, 0x0, 0xfc, 0x2f, 0xf8, 0xfb, 0xdf, 0x90, - 0xf8, 0x2f, 0xf8, 0xff, 0x4f, 0xe0, 0x70, 0x2f, - 0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xf8, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x0, - 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f, - 0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xfe, 0xaa, - 0xaa, 0xaa, 0xaa, 0xbf, 0xbf, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xf8, - - /* U+EB8E "" */ - 0x1, 0x55, 0x55, 0x55, 0x55, 0x55, 0x50, 0x1f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x3f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfd, 0x3f, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0x3e, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3e, 0x3e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, - 0x3e, 0x3, 0xe0, 0x0, 0x0, 0x0, 0x3e, 0x3e, - 0x3, 0xf8, 0x0, 0x0, 0x0, 0x3e, 0x3e, 0x0, - 0xfe, 0x0, 0x0, 0x0, 0x3e, 0x3e, 0x0, 0x3f, - 0x80, 0x0, 0x0, 0x3e, 0x3e, 0x0, 0x1f, 0xc0, - 0x0, 0x0, 0x3e, 0x3e, 0x0, 0x7f, 0x40, 0x0, - 0x0, 0x3e, 0x3e, 0x1, 0xfd, 0x0, 0x0, 0x0, - 0x3e, 0x3e, 0x3, 0xf4, 0x7, 0xff, 0xf0, 0x3e, - 0x3e, 0x3, 0xd0, 0xb, 0xff, 0xf0, 0x3e, 0x3e, - 0x0, 0x0, 0x2, 0xaa, 0x90, 0x3e, 0x3e, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3e, 0x3f, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfd, 0x2f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfc, 0x6, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xa0, - - /* U+EB97 "" */ - 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x3f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x3f, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xbe, 0x3e, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3e, 0x3e, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3e, 0x3e, 0x0, 0x0, 0x0, 0x6, - 0x0, 0x3e, 0x3e, 0x0, 0x0, 0x0, 0xf, 0x0, - 0x3e, 0x3e, 0xb, 0xff, 0xff, 0x8f, 0xf0, 0x3e, - 0x3e, 0xb, 0xff, 0xff, 0x8f, 0xf0, 0x3e, 0x3e, - 0x0, 0x0, 0x0, 0xf, 0x0, 0x3e, 0x3e, 0x0, - 0x10, 0x0, 0x1, 0x0, 0x3e, 0x3e, 0x0, 0xf0, - 0x0, 0x0, 0x0, 0x3e, 0x3e, 0x7, 0xf0, 0xff, - 0xff, 0xf0, 0x3e, 0x3e, 0xb, 0xf1, 0xff, 0xff, - 0xf0, 0x3e, 0x3e, 0x0, 0xf0, 0x0, 0x0, 0x0, - 0x3e, 0x3e, 0x0, 0x60, 0x0, 0x0, 0x0, 0x3e, - 0x3e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0x3e, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0x3f, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xbe, 0x3f, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfd, 0xf, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xf8, 0x0, 0x0, 0x3f, 0xff, 0xfe, - 0x0, 0x0, 0x0, 0x0, 0x3f, 0xff, 0xfe, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xff, 0xf8, 0x0, 0x0, - - /* U+EBCC "" */ - 0x0, 0x10, 0x0, 0x0, 0x4, 0x0, 0x0, 0xf8, - 0x0, 0x0, 0x2f, 0x0, 0x0, 0xf8, 0x0, 0x0, - 0x2f, 0x0, 0x1a, 0xfe, 0xaa, 0xaa, 0xbf, 0xa4, - 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xf8, 0x0, 0x0, 0x0, - 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f, - 0xfe, 0xaa, 0xaa, 0xaa, 0xaa, 0xbf, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f, - 0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xf8, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xf8, 0x1e, 0x3, 0xc0, - 0xb4, 0x2f, 0xf8, 0x2f, 0x3, 0xd0, 0xf8, 0x2f, - 0xf8, 0x9, 0x1, 0x80, 0x60, 0x2f, 0xf8, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x0, - 0x0, 0x2f, 0xf8, 0x9, 0x1, 0x80, 0x60, 0x2f, - 0xf8, 0x2f, 0x3, 0xd0, 0xf8, 0x2f, 0xf8, 0x1e, - 0x3, 0xc0, 0xb4, 0x2f, 0xf8, 0x0, 0x0, 0x0, - 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f, - 0xfe, 0xaa, 0xaa, 0xaa, 0xaa, 0xbf, 0xbf, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, - 0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - - /* U+EC1C "" */ - 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x3f, 0x80, - 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, - 0x3, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, 0xc0, - 0x0, 0x0, 0x0, 0x3f, 0xf8, 0x0, 0x0, 0x0, - 0xf, 0xff, 0x0, 0x0, 0x0, 0x3, 0xff, 0xd0, - 0x0, 0x0, 0x1, 0xfe, 0xfc, 0x0, 0x0, 0x0, - 0x7f, 0xaf, 0x80, 0x0, 0x0, 0x1f, 0xe3, 0xff, - 0xfe, 0x90, 0x7, 0xf8, 0xbf, 0xff, 0xff, 0xc1, - 0xfd, 0x0, 0x16, 0xbf, 0xfc, 0x3f, 0xfa, 0x50, - 0x0, 0x7f, 0x43, 0xff, 0xff, 0xfe, 0x2f, 0xd0, - 0x6, 0xbf, 0xff, 0xcb, 0xf4, 0x0, 0x0, 0x2, - 0xfa, 0xfd, 0x0, 0x0, 0x0, 0x3f, 0xbf, 0x40, - 0x0, 0x0, 0x7, 0xff, 0xc0, 0x0, 0x0, 0x0, - 0xff, 0xf0, 0x0, 0x0, 0x0, 0x2f, 0xfc, 0x0, - 0x0, 0x0, 0x3, 0xff, 0x0, 0x0, 0x0, 0x0, - 0xbf, 0xc0, 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, - 0x0, 0x0, 0x2, 0xfc, 0x0, 0x0, 0x0, 0x0, - 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x0, - 0x0, 0x0, - - /* U+EF40 "" */ - 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0xf, 0xf0, - 0xf, 0xf0, 0xf, 0xf0, 0xb, 0xfd, 0xb, 0xfd, - 0xb, 0xfd, 0x2, 0xff, 0x82, 0xff, 0x82, 0xff, - 0x80, 0x7f, 0xc0, 0x7f, 0xc0, 0x7f, 0xc0, 0x7, - 0x90, 0x7, 0x90, 0x7, 0x90, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x5, 0x0, 0x5, 0x0, 0x0, 0x0, - 0xf, 0xf0, 0xf, 0xf0, 0x0, 0x0, 0xb, 0xfd, - 0xb, 0xfd, 0x0, 0x1f, 0x42, 0xff, 0x82, 0xff, - 0x80, 0x1f, 0xf4, 0x7f, 0xc0, 0x7f, 0xc0, 0x1f, - 0xff, 0x7, 0x90, 0x7, 0x90, 0x1f, 0xff, 0xc0, - 0x0, 0x0, 0x0, 0x1f, 0xff, 0xe0, 0x0, 0x0, - 0x0, 0x1f, 0x4f, 0xe0, 0x5, 0x0, 0x0, 0x1f, - 0x43, 0xe0, 0xf, 0xf0, 0x0, 0x1f, 0x43, 0xe0, - 0xb, 0xfd, 0x0, 0xb, 0x43, 0xe0, 0x2, 0xff, - 0x80, 0x3, 0xd7, 0xe0, 0x0, 0x7f, 0xc0, 0x0, - 0xbf, 0xe0, 0x0, 0x7, 0x90, 0x0, 0x1f, 0xe0, - 0x0, 0x0, - - /* U+EF4A "" */ - 0x0, 0x0, 0x1, 0x55, 0x40, 0x0, 0x0, 0x0, - 0x0, 0x6f, 0xff, 0xfd, 0x0, 0x0, 0x0, 0x2, - 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, 0x1f, 0xfd, - 0x41, 0x6f, 0xf4, 0x0, 0x0, 0x7f, 0x80, 0x0, - 0x2, 0xfe, 0x0, 0x1, 0xfd, 0x0, 0x0, 0x0, - 0x7f, 0x40, 0x3, 0xf4, 0x0, 0x0, 0x0, 0xf, - 0xc0, 0xb, 0xd0, 0x0, 0x0, 0x0, 0x7, 0xf0, - 0xf, 0xc0, 0x0, 0x0, 0x0, 0x2, 0xf4, 0x2f, - 0x40, 0x0, 0x0, 0x0, 0x0, 0xf8, 0x3f, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xfc, 0x3e, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7c, 0x3e, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7d, 0x3d, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x7d, 0x3d, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x7d, 0x3e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7d, - 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbc, 0x2f, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xfc, 0x1f, 0x40, - 0x0, 0x0, 0x0, 0x1, 0xf8, 0xf, 0xc0, 0x0, - 0x0, 0x0, 0x3, 0xf0, 0x7, 0xf0, 0x0, 0x0, - 0x0, 0xb, 0xe0, 0x3, 0xf8, 0x0, 0x0, 0x0, - 0x2f, 0xc0, 0x0, 0xff, 0x0, 0x0, 0x0, 0xbf, - 0x0, 0x0, 0x3f, 0xe0, 0x0, 0x7, 0xfd, 0x0, - 0x0, 0xb, 0xff, 0xaa, 0xff, 0xf0, 0x0, 0x0, - 0x1, 0xff, 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, - 0x1b, 0xff, 0xe4, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, - - /* U+EF7A "" */ - 0x0, 0x1b, 0xfe, 0x0, 0x0, 0x0, 0x1, 0xff, - 0xff, 0xe0, 0x0, 0x0, 0x7, 0xff, 0xaf, 0xfc, - 0x0, 0x0, 0x1f, 0xe0, 0x1, 0xfe, 0x0, 0x0, - 0x3f, 0x40, 0x0, 0x3f, 0x40, 0x0, 0x7e, 0x0, - 0x0, 0xf, 0xc0, 0x0, 0xbc, 0x0, 0x0, 0xb, - 0xc0, 0x0, 0xfc, 0x0, 0x0, 0x7, 0xd0, 0x0, - 0xf8, 0x0, 0x0, 0x7, 0xd0, 0x0, 0xfc, 0x0, - 0x0, 0x7, 0xd0, 0x0, 0xfc, 0x0, 0x0, 0xb, - 0xc0, 0x0, 0x7d, 0x0, 0x0, 0xf, 0xc0, 0x0, - 0x3f, 0x0, 0x0, 0x3f, 0x40, 0x0, 0x1f, 0xd0, - 0x0, 0xff, 0x0, 0x0, 0xb, 0xfe, 0xaf, 0xff, - 0x80, 0x0, 0x1, 0xff, 0xff, 0xef, 0xe0, 0x0, - 0x0, 0x2f, 0xfe, 0x3, 0xf8, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3f, 0x80, 0x0, 0x0, 0x0, 0x0, 0xf, 0xe0, - 0x0, 0x0, 0x0, 0x0, 0x3, 0xf8, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xfd, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - - /* U+EFE6 "" */ - 0x0, 0x1b, 0xf4, 0x0, 0x1f, 0xf4, 0x0, 0xbf, - 0xff, 0x0, 0x2f, 0xf8, 0x1, 0xff, 0xbf, 0x80, - 0x2f, 0xf8, 0x3, 0xf0, 0xf, 0xc0, 0xbf, 0xfe, - 0x3, 0xe0, 0x7, 0xd0, 0xff, 0xff, 0x7, 0xd0, - 0x3, 0xe0, 0xff, 0xff, 0x7, 0xd0, 0x3, 0xe0, - 0xff, 0xff, 0x7, 0xd0, 0x3, 0xe0, 0xff, 0xff, - 0x7, 0xd0, 0x3, 0xe0, 0xff, 0xff, 0x7, 0xd0, - 0x3, 0xe0, 0x1b, 0xe4, 0x7, 0xd0, 0x3, 0xe0, - 0x7, 0xd0, 0x7, 0xd0, 0x3, 0xe0, 0x7, 0xd0, - 0x7, 0xd0, 0x3, 0xe0, 0x7, 0xd0, 0x7, 0xd0, - 0x3, 0xe0, 0x7, 0xd0, 0x1b, 0xe4, 0x3, 0xe0, - 0x7, 0xd0, 0xff, 0xff, 0x3, 0xe0, 0x7, 0xd0, - 0xff, 0xff, 0x3, 0xe0, 0x7, 0xd0, 0xff, 0xff, - 0x3, 0xe0, 0x7, 0xd0, 0xff, 0xff, 0x3, 0xe0, - 0x7, 0xd0, 0xff, 0xff, 0x3, 0xe0, 0xb, 0xc0, - 0xbf, 0xfe, 0x3, 0xf4, 0xf, 0xc0, 0x2f, 0xf8, - 0x1, 0xff, 0xff, 0x80, 0x2f, 0xf8, 0x0, 0x7f, - 0xfe, 0x0, 0x1f, 0xf4, 0x0, 0x1b, 0xf4, 0x0, - - /* U+F028 "" */ - 0xa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x3, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xbf, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xeb, 0xc0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, 0xbc, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3, 0xeb, 0xc0, 0x0, - 0x4, 0x1, 0x0, 0x0, 0x3e, 0xbc, 0xf, 0x3, - 0xe0, 0x7c, 0xf, 0x3, 0xeb, 0xc0, 0xf0, 0x3e, - 0x7, 0xc0, 0xf0, 0x3e, 0xbc, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3, 0xeb, 0xc0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3e, 0xbc, 0xa, 0x1, 0xd0, 0x34, - 0xa, 0x3, 0xeb, 0xc1, 0xf4, 0x3e, 0xb, 0xc1, - 0xf4, 0x3e, 0xbc, 0xf, 0x2, 0xd0, 0x38, 0xf, - 0x3, 0xeb, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3e, 0xbc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, - 0xeb, 0xc0, 0x0, 0xff, 0xff, 0xf0, 0x0, 0x3e, - 0xbc, 0x0, 0x1f, 0xff, 0xff, 0x40, 0x3, 0xeb, - 0xc0, 0x0, 0xaa, 0xaa, 0xa0, 0x0, 0x3e, 0xbc, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xeb, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xa0, - - /* U+F090 "" */ - 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf4, 0x0, 0x0, 0x0, 0x0, 0xf, 0x80, 0x0, - 0x0, 0x0, 0x0, 0xf8, 0x0, 0x0, 0x0, 0x0, - 0xf, 0x80, 0x0, 0x0, 0x0, 0x0, 0xf8, 0x0, - 0x0, 0x0, 0x0, 0xf, 0x80, 0x0, 0x0, 0x0, - 0x0, 0xf8, 0x0, 0x0, 0x0, 0x18, 0xf, 0x82, - 0x80, 0x0, 0x3, 0xf0, 0xf8, 0xbd, 0x0, 0x0, - 0x2f, 0xdf, 0xaf, 0xc0, 0x0, 0x0, 0xbf, 0xff, - 0xf0, 0x0, 0x0, 0x2, 0xff, 0xfc, 0x0, 0x0, - 0x0, 0xb, 0xff, 0x0, 0x0, 0x0, 0x0, 0x2f, - 0xc0, 0x0, 0x7, 0x80, 0x0, 0xb0, 0x0, 0x2d, - 0xbc, 0x0, 0x0, 0x0, 0x3, 0xeb, 0xc0, 0x0, - 0x0, 0x0, 0x3e, 0xbc, 0x0, 0x0, 0x0, 0x3, - 0xeb, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, - 0xff, 0xff, 0xff, 0xc0, 0xaa, 0xaa, 0xaa, 0xaa, - 0xa0, - - /* U+F15C "" */ - 0x0, 0x0, 0x0, 0x6a, 0x90, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7f, 0xff, 0xe0, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0xff, 0xff, 0xc0, 0x0, 0x0, 0x0, - 0xf, 0xf8, 0x1, 0xff, 0x0, 0x0, 0x0, 0x2, - 0xfc, 0x0, 0x2, 0xfc, 0x0, 0x0, 0x0, 0x7f, - 0x0, 0x0, 0xb, 0xe0, 0x0, 0x0, 0xb, 0xc0, - 0x0, 0x0, 0x3f, 0x0, 0x0, 0x6, 0xfc, 0x0, - 0x0, 0x1, 0xf4, 0x0, 0x2, 0xff, 0x80, 0x0, - 0x0, 0xf, 0x40, 0x0, 0xff, 0xe4, 0x0, 0x0, - 0x0, 0xf8, 0x0, 0x2f, 0xc0, 0x0, 0x0, 0x0, - 0xf, 0xf8, 0x3, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xf0, 0x7d, 0x0, 0x0, 0x0, 0x0, 0x5, - 0x7f, 0xcb, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xfd, 0xbc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, - 0xeb, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, - 0x7e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xe3, - 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbd, 0x1f, - 0xe0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xc0, 0xbf, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x1, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x1, 0xaa, - 0xaa, 0xaa, 0xaa, 0xa9, 0x0, - - /* U+F720 "" */ - 0x0, 0x0, 0x1, 0x40, 0x0, 0x0, 0x0, 0x0, - 0x7, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, - 0xf8, 0x0, 0x0, 0x0, 0x2f, 0xf9, 0xff, 0xd0, - 0x0, 0x0, 0xbf, 0xe0, 0x7, 0xff, 0x0, 0x1, - 0xff, 0xd0, 0x0, 0x2f, 0xf8, 0x3, 0xff, 0x40, - 0x0, 0x0, 0xbf, 0xd3, 0xfe, 0x0, 0x0, 0x0, - 0x7, 0xfc, 0xff, 0xe0, 0x0, 0x0, 0x7, 0xff, - 0x7f, 0xff, 0x40, 0x0, 0xb, 0xff, 0xdf, 0x9f, - 0xfd, 0x0, 0x2f, 0xf9, 0xf7, 0xe0, 0xbf, 0xe0, - 0x7f, 0xf0, 0x3d, 0xf8, 0x2, 0xff, 0xff, 0xd0, - 0xf, 0x7e, 0x0, 0xf, 0xff, 0x40, 0x3, 0xdf, - 0x80, 0x0, 0x7f, 0x0, 0x0, 0xf7, 0xe0, 0x0, - 0xf, 0x80, 0x0, 0x3d, 0xf8, 0x0, 0x3, 0xe0, - 0x0, 0xf, 0x7e, 0x0, 0x0, 0xf8, 0x0, 0x3, - 0xdf, 0x80, 0x0, 0x3e, 0x0, 0x0, 0xf7, 0xf4, - 0x0, 0xf, 0x80, 0x0, 0xfd, 0xbf, 0xd0, 0x3, - 0xe0, 0x2, 0xff, 0x7, 0xff, 0x0, 0xf8, 0xb, - 0xfe, 0x0, 0x2f, 0xf8, 0x3e, 0x1f, 0xfd, 0x0, - 0x0, 0xbf, 0xef, 0xbf, 0xf4, 0x0, 0x0, 0x7, - 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x1f, 0xff, - 0x80, 0x0, 0x0, 0x0, 0x0, 0xbf, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - - /* U+F8C7 "" */ - 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3d, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, - 0x0, 0x0, 0x0, 0x1, 0xe0, 0x0, 0x3e, 0x0, - 0x3, 0xc0, 0x3, 0xf0, 0x0, 0x3e, 0x0, 0xb, - 0xe0, 0xb, 0xe0, 0x0, 0x3e, 0x0, 0x3, 0xf0, - 0xf, 0xc0, 0x0, 0x3e, 0x0, 0x1, 0xf8, 0x1f, - 0x40, 0x0, 0x3e, 0x0, 0x0, 0xfc, 0x3f, 0x0, - 0x0, 0x3e, 0x0, 0x0, 0x7d, 0x3e, 0x0, 0x0, - 0x3e, 0x0, 0x0, 0x3e, 0x3e, 0x0, 0x0, 0x3e, - 0x0, 0x0, 0x3e, 0x3d, 0x0, 0x0, 0x3e, 0x0, - 0x0, 0x3e, 0x3d, 0x0, 0x0, 0x3d, 0x0, 0x0, - 0x3e, 0x3e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, - 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7d, 0x2f, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xbc, 0x1f, 0x80, - 0x0, 0x0, 0x0, 0x0, 0xfc, 0xf, 0xc0, 0x0, - 0x0, 0x0, 0x2, 0xf4, 0x7, 0xf0, 0x0, 0x0, - 0x0, 0x7, 0xf0, 0x2, 0xf8, 0x0, 0x0, 0x0, - 0x1f, 0xd0, 0x0, 0xff, 0x0, 0x0, 0x0, 0x7f, - 0x40, 0x0, 0x3f, 0xe0, 0x0, 0x7, 0xfd, 0x0, - 0x0, 0xb, 0xff, 0xaa, 0xbf, 0xf4, 0x0, 0x0, - 0x1, 0xff, 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, - 0x1b, 0xff, 0xe4, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, - - /* U+FFF75 "󿽵" */ - 0x2a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x40, 0x3f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x3f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0x3e, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xbd, 0x3e, 0x7, 0x0, 0x1c, - 0x0, 0x70, 0x3e, 0x3e, 0xb, 0x0, 0x2c, 0x0, - 0x70, 0x3e, 0x3e, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3e, 0x3f, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xbe, - 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, - 0x6, 0xff, 0xf8, 0x0, 0x7e, 0x0, 0x0, 0xbf, - 0xfe, 0x42, 0x40, 0x3e, 0x0, 0x1f, 0xff, 0xd0, - 0x3, 0x80, 0x3e, 0x2, 0xff, 0xf8, 0x1c, 0x0, - 0x1, 0xfd, 0xf, 0xfe, 0x40, 0x2c, 0x0, 0x6f, - 0xf8, 0x3f, 0xe0, 0xd0, 0x0, 0xb, 0xff, 0xe0, - 0x3e, 0x1, 0xd0, 0x2, 0xff, 0xfd, 0x0, 0x3f, - 0x0, 0x0, 0x7f, 0xff, 0x80, 0x0, 0x3f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xbe, 0x3e, 0x1, 0x0, 0x4, 0x0, - 0x10, 0x3e, 0x3e, 0xb, 0x0, 0x2c, 0x0, 0xb4, - 0x3e, 0x3e, 0x1, 0x0, 0x4, 0x0, 0x10, 0x3e, - 0x3f, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xbe, 0x1f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0 -}; - - -/*--------------------- - * GLYPH DESCRIPTION - *--------------------*/ - -static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { - {.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */, - {.bitmap_index = 0, .adv_w = 512, .box_w = 20, .box_h = 20, .ofs_x = 6, .ofs_y = 6}, - {.bitmap_index = 100, .adv_w = 512, .box_w = 28, .box_h = 22, .ofs_x = 2, .ofs_y = 5}, - {.bitmap_index = 254, .adv_w = 512, .box_w = 17, .box_h = 26, .ofs_x = 7, .ofs_y = 3}, - {.bitmap_index = 365, .adv_w = 512, .box_w = 20, .box_h = 27, .ofs_x = 6, .ofs_y = 2}, - {.bitmap_index = 500, .adv_w = 512, .box_w = 30, .box_h = 30, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 725, .adv_w = 512, .box_w = 28, .box_h = 22, .ofs_x = 2, .ofs_y = 5}, - {.bitmap_index = 879, .adv_w = 512, .box_w = 28, .box_h = 28, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 1075, .adv_w = 512, .box_w = 16, .box_h = 9, .ofs_x = 8, .ofs_y = 12}, - {.bitmap_index = 1111, .adv_w = 512, .box_w = 28, .box_h = 22, .ofs_x = 2, .ofs_y = 5}, - {.bitmap_index = 1265, .adv_w = 512, .box_w = 28, .box_h = 28, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 1461, .adv_w = 512, .box_w = 24, .box_h = 24, .ofs_x = 4, .ofs_y = 4}, - {.bitmap_index = 1605, .adv_w = 512, .box_w = 16, .box_h = 24, .ofs_x = 8, .ofs_y = 4}, - {.bitmap_index = 1701, .adv_w = 512, .box_w = 22, .box_h = 24, .ofs_x = 5, .ofs_y = 4}, - {.bitmap_index = 1833, .adv_w = 512, .box_w = 22, .box_h = 22, .ofs_x = 5, .ofs_y = 5}, - {.bitmap_index = 1954, .adv_w = 512, .box_w = 18, .box_h = 18, .ofs_x = 7, .ofs_y = 7}, - {.bitmap_index = 2035, .adv_w = 512, .box_w = 24, .box_h = 16, .ofs_x = 4, .ofs_y = 8}, - {.bitmap_index = 2131, .adv_w = 512, .box_w = 6, .box_h = 22, .ofs_x = 13, .ofs_y = 5}, - {.bitmap_index = 2164, .adv_w = 512, .box_w = 22, .box_h = 22, .ofs_x = 5, .ofs_y = 5}, - {.bitmap_index = 2285, .adv_w = 512, .box_w = 32, .box_h = 23, .ofs_x = 0, .ofs_y = 4}, - {.bitmap_index = 2469, .adv_w = 512, .box_w = 22, .box_h = 16, .ofs_x = 5, .ofs_y = 8}, - {.bitmap_index = 2557, .adv_w = 512, .box_w = 25, .box_h = 22, .ofs_x = 5, .ofs_y = 5}, - {.bitmap_index = 2695, .adv_w = 512, .box_w = 24, .box_h = 22, .ofs_x = 4, .ofs_y = 5}, - {.bitmap_index = 2827, .adv_w = 512, .box_w = 22, .box_h = 28, .ofs_x = 5, .ofs_y = 2}, - {.bitmap_index = 2981, .adv_w = 512, .box_w = 28, .box_h = 26, .ofs_x = 2, .ofs_y = 4}, - {.bitmap_index = 3163, .adv_w = 512, .box_w = 26, .box_h = 28, .ofs_x = 3, .ofs_y = 2}, - {.bitmap_index = 3345, .adv_w = 512, .box_w = 28, .box_h = 28, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 3541, .adv_w = 512, .box_w = 20, .box_h = 28, .ofs_x = 6, .ofs_y = 2}, - {.bitmap_index = 3681, .adv_w = 512, .box_w = 22, .box_h = 24, .ofs_x = 5, .ofs_y = 4}, - {.bitmap_index = 3813, .adv_w = 512, .box_w = 28, .box_h = 22, .ofs_x = 2, .ofs_y = 5}, - {.bitmap_index = 3967, .adv_w = 512, .box_w = 32, .box_h = 31, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 4215, .adv_w = 512, .box_w = 24, .box_h = 24, .ofs_x = 4, .ofs_y = 4}, - {.bitmap_index = 4359, .adv_w = 512, .box_w = 28, .box_h = 28, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 4555, .adv_w = 512, .box_w = 24, .box_h = 24, .ofs_x = 4, .ofs_y = 4}, - {.bitmap_index = 4699, .adv_w = 512, .box_w = 28, .box_h = 22, .ofs_x = 2, .ofs_y = 5}, - {.bitmap_index = 4853, .adv_w = 512, .box_w = 28, .box_h = 24, .ofs_x = 2, .ofs_y = 4}, - {.bitmap_index = 5021, .adv_w = 512, .box_w = 24, .box_h = 28, .ofs_x = 4, .ofs_y = 2}, - {.bitmap_index = 5189, .adv_w = 512, .box_w = 22, .box_h = 28, .ofs_x = 5, .ofs_y = 2}, - {.bitmap_index = 5343, .adv_w = 512, .box_w = 25, .box_h = 22, .ofs_x = 5, .ofs_y = 5}, - {.bitmap_index = 5481, .adv_w = 512, .box_w = 28, .box_h = 28, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 5677, .adv_w = 512, .box_w = 24, .box_h = 24, .ofs_x = 4, .ofs_y = 4}, - {.bitmap_index = 5821, .adv_w = 512, .box_w = 24, .box_h = 24, .ofs_x = 4, .ofs_y = 4}, - {.bitmap_index = 5965, .adv_w = 512, .box_w = 30, .box_h = 22, .ofs_x = 1, .ofs_y = 5}, - {.bitmap_index = 6130, .adv_w = 512, .box_w = 22, .box_h = 22, .ofs_x = 5, .ofs_y = 5}, - {.bitmap_index = 6251, .adv_w = 512, .box_w = 30, .box_h = 22, .ofs_x = 1, .ofs_y = 5}, - {.bitmap_index = 6416, .adv_w = 512, .box_w = 25, .box_h = 28, .ofs_x = 4, .ofs_y = 2}, - {.bitmap_index = 6591, .adv_w = 512, .box_w = 28, .box_h = 28, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 6787, .adv_w = 512, .box_w = 28, .box_h = 28, .ofs_x = 2, .ofs_y = 2} -}; - -/*--------------------- - * CHARACTER MAPPING - *--------------------*/ - -static const uint16_t unicode_list_0[] = { - 0x0, 0x14, 0x62, 0x9b, 0x148, 0x182, 0x1ca, 0x1d1, - 0x1e1, 0x26a, 0x2af, 0x2c0, 0x418, 0x47e, 0x488, 0x48d, - 0x48f, 0x490, 0x4f9, 0x523, 0x600, 0x62b, 0x757, 0x76a, - 0x773, 0x7b8, 0x7ca, 0x7e9, 0x874, 0x8af, 0x8b2, 0x8c2, - 0x991, 0xa49, 0xa52, 0xa87, 0xad7, 0xdfb, 0xe05, 0xe35, - 0xea1, 0xee3, 0xf4b, 0x1017, 0x15db, 0x1782 -}; - -/*Collect the unicode lists and glyph_id offsets*/ -static const lv_font_fmt_txt_cmap_t cmaps[] = -{ - { - .range_start = 57669, .range_length = 6019, .glyph_id_start = 1, - .unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 46, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY - }, - { - .range_start = 1048437, .range_length = 1, .glyph_id_start = 47, - .unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY - } -}; - - - -/*-------------------- - * ALL CUSTOM DATA - *--------------------*/ - -#if LVGL_VERSION_MAJOR == 8 -/*Store all the custom data of the font*/ -static lv_font_fmt_txt_glyph_cache_t cache; -#endif - -#if LVGL_VERSION_MAJOR >= 8 -static const lv_font_fmt_txt_dsc_t font_dsc = { -#else -static lv_font_fmt_txt_dsc_t font_dsc = { -#endif - .glyph_bitmap = glyph_bitmap, - .glyph_dsc = glyph_dsc, - .cmaps = cmaps, - .kern_dsc = NULL, - .kern_scale = 0, - .cmap_num = 2, - .bpp = 2, - .kern_classes = 0, - .bitmap_format = 0, -#if LVGL_VERSION_MAJOR == 8 - .cache = &cache -#endif -}; - - - -/*----------------- - * PUBLIC FONT - *----------------*/ - -/*Initialize a public general font descriptor*/ -#if LVGL_VERSION_MAJOR >= 8 -const lv_font_t material_symbols_shared_32 = { -#else -lv_font_t material_symbols_shared_32 = { -#endif - .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ - .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ - .line_height = 31, /*The maximum line height required by the font*/ - .base_line = -1, /*Baseline measured from the bottom of the line*/ -#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) - .subpx = LV_FONT_SUBPX_NONE, -#endif -#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 - .underline_position = 0, - .underline_thickness = 0, -#endif - .dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ -#if LV_VERSION_CHECK(8, 2, 0) || LVGL_VERSION_MAJOR >= 9 - .fallback = NULL, -#endif - .user_data = NULL, -}; - - - -#endif /*#if MATERIAL_SYMBOLS_SHARED_32*/ - diff --git a/Modules/lvgl-module/source-fonts/material_symbols_shared_40.c b/Modules/lvgl-module/source-fonts/material_symbols_shared_40.c deleted file mode 100644 index ae335b8c0..000000000 --- a/Modules/lvgl-module/source-fonts/material_symbols_shared_40.c +++ /dev/null @@ -1,1632 +0,0 @@ -/******************************************************************************* - * Size: 40 px - * Bpp: 2 - * Opts: --no-compress --no-prefilter --bpp 2 --size 40 --font MaterialSymbolsRounded.ttf -r 0xE145,0xE5C3,0xE770,0xEF40,0xEBCC,0xEFE6,0xEF4A,0xE5CD,0xF15C,0xE668,0xE92E,0xE326,0xEB97,0xE745,0xEC1C,0xE2C7,0xF720,0xF090,0xE8AF,0xE30F,0xE8FD,0xE9F4,0xE3F4,0xE316,0xE90F,0xEA07,0xE9B9,0xE159,0xE5D2,0xE28D,0xE5D4,0xE405,0xE89C,0xF8C7,0xE5D5,0xEF7A,0xE8B8,0xE9F7,0xE55D,0xF028,0xE1E0,0xE63E,0xE1A7,0xEB8E,0xEAD6,0xE3AF,0xFFF75 --format lvgl -o source-fonts/material_symbols_shared_40.c --force-fast-kern-format - ******************************************************************************/ - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -#ifndef MATERIAL_SYMBOLS_SHARED_40 -#define MATERIAL_SYMBOLS_SHARED_40 1 -#endif - -#if MATERIAL_SYMBOLS_SHARED_40 - -/*----------------- - * BITMAPS - *----------------*/ - -/*Store the image of the glyphs*/ -static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { - /* U+E145 "" */ - 0x0, 0x0, 0x1, 0x40, 0x0, 0x0, 0x0, 0x0, - 0xb, 0xd0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xe0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xe0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xe0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xe0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xe0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xe0, 0x0, 0x0, 0x15, 0x55, 0x5f, 0xf5, - 0x55, 0x54, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0xbf, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, - 0xff, 0xff, 0xff, 0xf8, 0x0, 0x0, 0xf, 0xe0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xe0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xe0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xe0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xe0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xe0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xe0, - 0x0, 0x0, 0x0, 0x0, 0x3, 0x80, 0x0, 0x0, - - /* U+E159 "" */ - 0x1, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x50, - 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xf4, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfd, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x2f, 0xdf, 0xfe, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x1f, 0xfd, 0xff, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xff, 0xdf, 0xef, 0xfc, 0x0, 0x0, - 0x0, 0xb, 0xfe, 0xfd, 0xfd, 0x2f, 0xf8, 0x0, - 0x0, 0x7, 0xff, 0x4f, 0xdf, 0xd0, 0x3f, 0xf4, - 0x0, 0x2, 0xff, 0x80, 0xfd, 0xfd, 0x0, 0x7f, - 0xe0, 0x1, 0xff, 0xc0, 0xf, 0xdf, 0xd0, 0x0, - 0xbf, 0xd0, 0xff, 0xd0, 0x0, 0xfd, 0xfd, 0x0, - 0x1, 0xff, 0xff, 0xe0, 0x0, 0xf, 0xdf, 0xd0, - 0x0, 0x2, 0xff, 0xf4, 0x0, 0x0, 0xfd, 0xfd, - 0x0, 0x0, 0x7, 0xf8, 0x0, 0x0, 0xf, 0xdf, - 0xd0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0xfd, - 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xdf, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xfd, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xdf, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xfd, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xdf, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xfd, 0xfd, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xdf, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xfd, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xd7, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x40, 0x15, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x0, - - /* U+E1A7 "" */ - 0x0, 0x0, 0x7, 0xc0, 0x0, 0x0, 0x0, 0x3, - 0xfc, 0x0, 0x0, 0x0, 0x0, 0xff, 0xc0, 0x0, - 0x0, 0x0, 0x3f, 0xfc, 0x0, 0x0, 0x0, 0xf, - 0xff, 0xc0, 0xb, 0x80, 0x3, 0xff, 0xfc, 0x3, - 0xf8, 0x0, 0xfd, 0xbf, 0xc0, 0xff, 0x80, 0x3f, - 0x4b, 0xfc, 0xf, 0xf8, 0xf, 0xd0, 0xbf, 0x80, - 0xff, 0x83, 0xf4, 0x3f, 0xd0, 0xf, 0xf8, 0xfd, - 0x3f, 0xe0, 0x0, 0xff, 0xbf, 0xbf, 0xe0, 0x0, - 0xf, 0xff, 0xff, 0xe0, 0x0, 0x0, 0xff, 0xff, - 0xe0, 0x0, 0x0, 0xf, 0xff, 0xe0, 0x0, 0x0, - 0x0, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x3f, 0xf8, - 0x0, 0x0, 0x0, 0x3f, 0xff, 0x80, 0x0, 0x0, - 0x3f, 0xff, 0xf8, 0x0, 0x0, 0x3f, 0xff, 0xff, - 0x80, 0x0, 0x3f, 0xef, 0xef, 0xf8, 0x0, 0x3f, - 0xe3, 0xf4, 0xff, 0x80, 0x3f, 0xe0, 0xfd, 0xf, - 0xf4, 0x3f, 0xe0, 0x3f, 0x42, 0xfe, 0x3f, 0xe0, - 0xf, 0xd2, 0xff, 0xf, 0xe0, 0x3, 0xf6, 0xff, - 0x2, 0xe0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x3f, 0xff, 0x0, 0x0, 0x0, 0xf, 0xff, 0x0, - 0x0, 0x0, 0x3, 0xff, 0x0, 0x0, 0x0, 0x0, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x1f, 0x0, 0x0, - - /* U+E1E0 "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3, 0xc0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xe0, - 0x0, 0x0, 0x0, 0x0, 0x1f, 0xf4, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0xfc, 0x0, 0x0, 0x0, 0x0, - 0xbf, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x0, 0xb, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0xb, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0xb, 0xf0, 0x0, 0x0, 0x6, 0x80, 0xb, 0xf0, - 0x1a, 0xa8, 0x3f, 0xf0, 0xb, 0xf0, 0x3f, 0xfe, - 0x7f, 0xf8, 0xb, 0xf0, 0x3f, 0xfe, 0xbf, 0xfc, - 0xb, 0xf0, 0x3f, 0xfe, 0xbf, 0xfc, 0xb, 0xf0, - 0x3f, 0xfe, 0x3f, 0xf4, 0xb, 0xf0, 0x3f, 0xfe, - 0xf, 0xd0, 0xb, 0xf0, 0x3f, 0xfd, 0xf, 0xd0, - 0xb, 0xf0, 0x7, 0xf0, 0xf, 0xd0, 0xb, 0xf0, - 0x7, 0xf0, 0xf, 0xd0, 0xb, 0xf0, 0x7, 0xf0, - 0xf, 0xfa, 0xaf, 0xfa, 0xaf, 0xf0, 0xb, 0xff, - 0xff, 0xff, 0xff, 0xe0, 0x3, 0xff, 0xff, 0xff, - 0xff, 0xc0, 0x0, 0xaa, 0xaf, 0xfa, 0xaa, 0x0, - 0x0, 0x0, 0xb, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0xb, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0xb, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x2f, 0xfc, 0x0, 0x0, 0x0, 0x0, - 0x3f, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0x1f, 0xf8, 0x0, 0x0, 0x0, 0x0, - 0x2, 0x90, 0x0, 0x0, - - /* U+E28D "" */ - 0x0, 0x0, 0x0, 0x0, 0x14, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0x80, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, - 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, - 0xc3, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3f, 0x41, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0x41, 0xfc, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0x41, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3f, 0x41, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3f, 0x41, 0xfc, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0x41, 0xfc, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0x41, - 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, - 0x41, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3f, 0x41, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0x41, 0xfc, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0x41, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3f, 0x41, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0x2a, 0xaa, 0xbf, 0xeb, 0xfe, 0xaa, - 0xa8, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x0, 0x2, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x80, 0x3, 0xfe, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xbf, 0xc0, 0x3, 0xf4, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x1f, 0xc0, 0x3, 0xf4, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xc0, 0x3, - 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xc0, - 0x3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xc0, 0x7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xd0, 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xe0, 0xf, 0xe5, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x5b, 0xf0, 0xf, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7, 0xf0, 0x1f, 0xc0, 0x78, - 0x0, 0x3c, 0x0, 0x2d, 0x3, 0xf4, 0x2f, 0xc0, - 0xfd, 0x0, 0xbe, 0x0, 0x7f, 0x3, 0xf8, 0x3f, - 0x80, 0xfd, 0x0, 0xbe, 0x0, 0x7f, 0x2, 0xfc, - 0x3f, 0x40, 0xfd, 0x0, 0xbe, 0x0, 0x7f, 0x1, - 0xfc, 0x7f, 0x0, 0xfd, 0x0, 0xbe, 0x0, 0x7f, - 0x0, 0xfd, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfd, 0x3f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xf4, 0x1, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x40, - - /* U+E2C7 "" */ - 0x1, 0x55, 0x55, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x2, 0xff, 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, - 0x0, 0x7f, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xff, 0xff, 0xff, 0xf4, 0x0, 0x0, - 0x0, 0x0, 0xfd, 0x0, 0x0, 0x7f, 0xff, 0xff, - 0xff, 0xfe, 0xf, 0xd0, 0x0, 0x1, 0xff, 0xff, - 0xff, 0xff, 0xfc, 0xfd, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xff, 0xff, 0xdf, 0xd0, 0x0, 0x0, 0x15, - 0x55, 0x55, 0x55, 0xfd, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xdf, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xfd, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xdf, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xfd, 0xfd, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xdf, 0xd0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfd, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xdf, - 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfd, - 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xdf, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xfd, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xdf, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xfd, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xdf, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xfd, 0xfd, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xdf, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xfd, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xd7, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x40, 0x15, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x0, - - /* U+E30F "" */ - 0x0, 0x0, 0x0, 0x15, 0x55, 0x40, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xff, 0xfe, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xfc, 0x7, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xc0, 0x7f, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfc, 0x7, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xc0, - 0x7f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfd, - 0xb, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xf6, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x7f, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x7f, 0xff, - 0xe0, 0x3, 0xfc, 0x0, 0xff, 0xff, 0xcf, 0xff, - 0xff, 0x80, 0xa, 0x0, 0x3f, 0xff, 0xfd, 0xff, - 0xff, 0xfe, 0x0, 0x0, 0xf, 0xff, 0xff, 0xdf, - 0xe5, 0x5f, 0xf8, 0x0, 0x3, 0xfe, 0x55, 0xfd, - 0xfd, 0x0, 0x3f, 0xd0, 0x0, 0xbf, 0x80, 0xf, - 0xdf, 0xd0, 0x3, 0xfd, 0x0, 0xb, 0xf8, 0x0, - 0xfd, 0xfe, 0x55, 0xff, 0x80, 0x0, 0x3f, 0xe5, - 0x5f, 0xdf, 0xff, 0xff, 0xe0, 0x0, 0x0, 0xff, - 0xff, 0xfd, 0xff, 0xff, 0xf8, 0x0, 0xa0, 0x3, - 0xff, 0xff, 0xd7, 0xff, 0xfe, 0x0, 0x3f, 0xc0, - 0xf, 0xff, 0xfc, 0x0, 0x0, 0x0, 0xf, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, - 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xbf, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xe0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xfc, 0x7, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xc0, 0x7f, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xfc, 0x7, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xc0, 0x7f, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xfe, 0x5b, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xb, 0xff, 0xfd, 0x0, 0x0, - 0x0, - - /* U+E316 "" */ - 0x0, 0x0, 0x3d, 0x0, 0x0, 0x0, 0x0, 0xff, - 0x40, 0x0, 0x0, 0x3, 0xff, 0xd0, 0x0, 0x0, - 0xf, 0xff, 0xf4, 0x0, 0x0, 0x3f, 0xe7, 0xfd, - 0x0, 0x0, 0xff, 0x81, 0xff, 0x40, 0x3, 0xfe, - 0x0, 0x7f, 0xd0, 0xf, 0xf8, 0x0, 0x1f, 0xf4, - 0x3f, 0xe0, 0x0, 0x7, 0xfc, 0x3f, 0x80, 0x0, - 0x1, 0xfd, 0x2e, 0x0, 0x0, 0x0, 0x78, - - /* U+E326 "" */ - 0x0, 0x15, 0x55, 0x55, 0x55, 0x55, 0x55, 0x50, - 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xd0, 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfe, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xd0, 0xf, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xfd, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x55, 0x55, 0x50, 0xf, 0xd0, 0x0, 0x0, - 0x0, 0x7f, 0xff, 0xff, 0xc0, 0xfd, 0x0, 0x0, - 0x0, 0xf, 0xff, 0xff, 0xfd, 0xf, 0xd0, 0x0, - 0x0, 0x0, 0xff, 0xff, 0xff, 0xd0, 0xfd, 0x0, - 0x0, 0x0, 0xf, 0xd0, 0x0, 0xfd, 0xf, 0xd0, - 0x0, 0x0, 0x0, 0xfd, 0x4, 0xf, 0xd0, 0xfd, - 0x0, 0x0, 0x0, 0xf, 0xd1, 0xf0, 0xfd, 0xf, - 0xd0, 0x0, 0x0, 0x0, 0xfd, 0xa, 0xf, 0xd0, - 0xfd, 0x0, 0x0, 0x0, 0xf, 0xd0, 0x0, 0xfd, - 0xf, 0xd0, 0x0, 0x0, 0x0, 0xfd, 0x0, 0xf, - 0xd0, 0xfd, 0x0, 0x0, 0x0, 0xf, 0xd0, 0x0, - 0xfd, 0xf, 0xd0, 0x0, 0x0, 0x0, 0xfd, 0x0, - 0xf, 0xd0, 0xff, 0xff, 0xff, 0xf4, 0xf, 0xd0, - 0x0, 0xfd, 0xb, 0xff, 0xff, 0xff, 0xc0, 0xfd, - 0x0, 0xf, 0xd0, 0x2f, 0xff, 0xff, 0xf8, 0xf, - 0xd0, 0x0, 0xfd, 0x0, 0x15, 0x55, 0x55, 0x0, - 0xfd, 0x0, 0xf, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xd0, 0x0, 0xfd, 0x3f, 0xff, 0xff, 0xff, - 0x40, 0xff, 0xff, 0xff, 0xdb, 0xff, 0xff, 0xff, - 0xfc, 0xf, 0xff, 0xff, 0xfd, 0x7f, 0xff, 0xff, - 0xff, 0x80, 0x3f, 0xff, 0xff, 0x80, 0x55, 0x55, - 0x55, 0x50, 0x0, 0x55, 0x55, 0x40, - - /* U+E3AF "" */ - 0x0, 0x0, 0x0, 0x5, 0x55, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff, 0x80, - 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, - 0x40, 0x0, 0x0, 0xb, 0xff, 0x90, 0xb, 0xaf, - 0xfe, 0x0, 0x0, 0x3, 0xff, 0x80, 0x0, 0xf0, - 0x2f, 0xf8, 0x0, 0x0, 0xbf, 0xc0, 0x0, 0x2c, - 0x0, 0x3f, 0xe0, 0x0, 0x2f, 0xf0, 0x0, 0x7, - 0x80, 0x0, 0xff, 0x40, 0x3, 0xff, 0x0, 0x0, - 0xf0, 0x0, 0x3, 0xfc, 0x0, 0xff, 0x78, 0x0, - 0x2d, 0x0, 0x0, 0xf, 0xe0, 0x1f, 0xd2, 0xd0, - 0x3, 0xc0, 0x0, 0x0, 0xbf, 0x2, 0xfc, 0xf, - 0x0, 0xb8, 0x0, 0x0, 0x3, 0xf8, 0x3f, 0x40, - 0x74, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc7, 0xf0, - 0x3, 0xc3, 0xff, 0xff, 0xaa, 0xaa, 0xfc, 0xbf, - 0x0, 0x1f, 0xbf, 0xff, 0xd0, 0x0, 0xf, 0xdb, - 0xe0, 0x0, 0xbf, 0xff, 0xff, 0x0, 0x0, 0xfd, - 0xbe, 0x0, 0x3, 0xff, 0xff, 0xf4, 0x0, 0xf, - 0xeb, 0xe0, 0x0, 0x2f, 0xff, 0xff, 0xc0, 0x0, - 0xfe, 0xbe, 0x0, 0x0, 0xff, 0xff, 0xfe, 0x0, - 0xf, 0xeb, 0xf0, 0x0, 0xb, 0xff, 0xfe, 0xf0, - 0x0, 0xfd, 0x7f, 0xaa, 0xaa, 0xff, 0xff, 0x83, - 0x80, 0x1f, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xf0, - 0x2d, 0x2, 0xfc, 0x3f, 0xc0, 0x0, 0x0, 0x3e, - 0x0, 0xf0, 0x3f, 0x82, 0xfd, 0x0, 0x0, 0x3, - 0xc0, 0xb, 0x4b, 0xf4, 0xf, 0xf0, 0x0, 0x0, - 0xb4, 0x0, 0x3d, 0xff, 0x0, 0x7f, 0x80, 0x0, - 0xf, 0x0, 0x1, 0xff, 0xd0, 0x3, 0xfe, 0x0, - 0x3, 0xd0, 0x0, 0xf, 0xf8, 0x0, 0xf, 0xf8, - 0x0, 0x78, 0x0, 0x3, 0xff, 0x0, 0x0, 0x7f, - 0xf4, 0xf, 0x0, 0x1, 0xff, 0xc0, 0x0, 0x1, - 0xff, 0xf6, 0xe0, 0x1, 0xff, 0xf0, 0x0, 0x0, - 0x3, 0xff, 0xfe, 0xab, 0xff, 0xf8, 0x0, 0x0, - 0x0, 0x7, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0xb, 0xff, 0xff, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x6, 0xbf, 0xe4, 0x0, 0x0, - 0x0, - - /* U+E3F4 "" */ - 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x47, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe5, - 0x55, 0x55, 0x55, 0x55, 0x55, 0xbf, 0xfd, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7f, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7f, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7f, 0xfd, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x7, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x7f, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x7, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x7f, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x40, 0x0, 0x7f, - 0xfd, 0x0, 0x0, 0x0, 0x1f, 0x0, 0x7, 0xff, - 0xd0, 0x2, 0x80, 0x3, 0xf8, 0x0, 0x7f, 0xfd, - 0x0, 0x7d, 0x0, 0xff, 0xd0, 0x7, 0xff, 0xd0, - 0xf, 0xf0, 0x2f, 0xff, 0x0, 0x7f, 0xfd, 0x3, - 0xff, 0xc7, 0xff, 0xfc, 0x7, 0xff, 0xd0, 0xbf, - 0xfe, 0xff, 0xff, 0xe0, 0x7f, 0xfd, 0xf, 0xff, - 0xff, 0xff, 0xff, 0x7, 0xff, 0xd0, 0x15, 0x55, - 0x55, 0x55, 0x40, 0x7f, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7f, 0xfe, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x5b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xd1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xf4, - - /* U+E405 "" */ - 0x0, 0x0, 0x7, 0xff, 0xfd, 0x0, 0x0, 0xf, - 0xff, 0xff, 0x0, 0x0, 0xf, 0xff, 0xff, 0x0, - 0x0, 0xf, 0xff, 0xff, 0x0, 0x0, 0xf, 0xff, - 0xff, 0x0, 0x0, 0xf, 0xff, 0xff, 0x0, 0x0, - 0xf, 0xfa, 0xa8, 0x0, 0x0, 0xf, 0xd0, 0x0, - 0x0, 0x0, 0xf, 0xd0, 0x0, 0x0, 0x0, 0xf, - 0xd0, 0x0, 0x0, 0x0, 0xf, 0xd0, 0x0, 0x0, - 0x0, 0xf, 0xd0, 0x0, 0x0, 0x0, 0xf, 0xd0, - 0x0, 0x0, 0x0, 0xf, 0xd0, 0x0, 0x0, 0x0, - 0xf, 0xd0, 0x0, 0x0, 0x0, 0xf, 0xd0, 0x0, - 0x0, 0x4, 0xf, 0xd0, 0x0, 0x2, 0xff, 0xef, - 0xd0, 0x0, 0xf, 0xff, 0xff, 0xd0, 0x0, 0x3f, - 0xff, 0xff, 0xd0, 0x0, 0x7f, 0xff, 0xff, 0xd0, - 0x0, 0xbf, 0xff, 0xff, 0xd0, 0x0, 0xff, 0xff, - 0xff, 0xd0, 0x0, 0xff, 0xff, 0xff, 0xd0, 0x0, - 0xff, 0xff, 0xff, 0xc0, 0x0, 0xbf, 0xff, 0xff, - 0xc0, 0x0, 0x3f, 0xff, 0xff, 0x80, 0x0, 0x2f, - 0xff, 0xff, 0x0, 0x0, 0xb, 0xff, 0xfc, 0x0, - 0x0, 0x0, 0xbf, 0x90, 0x0, 0x0, - - /* U+E55D "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7d, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, - 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, - 0xc0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xc0, - 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0xe0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xeb, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x2f, 0xc3, 0xf8, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0x82, 0xfc, 0x0, 0x0, 0x0, 0x0, - 0x7f, 0x0, 0xfd, 0x0, 0x0, 0x0, 0x0, 0xff, - 0x0, 0xff, 0x0, 0x0, 0x0, 0x1, 0xfd, 0x0, - 0x7f, 0x40, 0x0, 0x0, 0x3, 0xfc, 0x0, 0x3f, - 0xc0, 0x0, 0x0, 0x3, 0xf4, 0x0, 0x1f, 0xc0, - 0x0, 0x0, 0xb, 0xf0, 0x0, 0xf, 0xe0, 0x0, - 0x0, 0xf, 0xe0, 0x0, 0xb, 0xf0, 0x0, 0x0, - 0x2f, 0xc0, 0x0, 0x3, 0xf8, 0x0, 0x0, 0x3f, - 0x80, 0x0, 0x2, 0xfc, 0x0, 0x0, 0x7f, 0x0, - 0x0, 0x0, 0xfd, 0x0, 0x0, 0xff, 0x0, 0x0, - 0x0, 0xff, 0x0, 0x1, 0xfd, 0x0, 0x14, 0x0, - 0x7f, 0x40, 0x3, 0xfc, 0x2, 0xff, 0x80, 0x3f, - 0xc0, 0x3, 0xf4, 0x6f, 0xff, 0xf9, 0x1f, 0xc0, - 0xb, 0xfb, 0xff, 0xff, 0xff, 0xef, 0xe0, 0xf, - 0xff, 0xff, 0x82, 0xff, 0xff, 0xf0, 0x2f, 0xff, - 0xf4, 0x0, 0x1f, 0xff, 0xf8, 0x3f, 0xff, 0x40, - 0x0, 0x1, 0xff, 0xfc, 0x3f, 0xe0, 0x0, 0x0, - 0x0, 0xb, 0xfc, 0x19, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x64, - - /* U+E5C3 "" */ - 0x1, 0x40, 0x0, 0x14, 0x0, 0x1, 0x40, 0x1f, - 0xf4, 0x1, 0xff, 0x40, 0x1f, 0xf4, 0x3f, 0xfc, - 0x3, 0xff, 0xc0, 0x3f, 0xfc, 0x3f, 0xfd, 0x3, - 0xff, 0xd0, 0x3f, 0xfd, 0x3f, 0xfd, 0x3, 0xff, - 0xd0, 0x3f, 0xfd, 0x2f, 0xfc, 0x2, 0xff, 0xc0, - 0x2f, 0xfc, 0xb, 0xf0, 0x0, 0xbf, 0x0, 0xb, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x40, - 0x0, 0x14, 0x0, 0x1, 0x40, 0x1f, 0xf4, 0x1, - 0xff, 0x40, 0x1f, 0xf4, 0x3f, 0xfc, 0x3, 0xff, - 0xc0, 0x3f, 0xfc, 0x3f, 0xfd, 0x3, 0xff, 0xd0, - 0x3f, 0xfd, 0x3f, 0xfd, 0x3, 0xff, 0xd0, 0x3f, - 0xfd, 0x2f, 0xfc, 0x2, 0xff, 0xc0, 0x2f, 0xfc, - 0xb, 0xf0, 0x0, 0xbf, 0x0, 0xb, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x1, 0x40, 0x0, 0x14, - 0x0, 0x1, 0x40, 0x1f, 0xf4, 0x1, 0xff, 0x40, - 0x1f, 0xf4, 0x3f, 0xfc, 0x3, 0xff, 0xc0, 0x3f, - 0xfc, 0x3f, 0xfd, 0x3, 0xff, 0xd0, 0x3f, 0xfd, - 0x3f, 0xfd, 0x3, 0xff, 0xd0, 0x3f, 0xfd, 0x2f, - 0xfc, 0x2, 0xff, 0xc0, 0x2f, 0xfc, 0xb, 0xf0, - 0x0, 0xbf, 0x0, 0xb, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, - - /* U+E5CD "" */ - 0x78, 0x0, 0x0, 0x0, 0x2, 0xdf, 0xf0, 0x0, - 0x0, 0x0, 0xff, 0xbf, 0xc0, 0x0, 0x0, 0x3f, - 0xe3, 0xff, 0x0, 0x0, 0xf, 0xfc, 0xf, 0xfc, - 0x0, 0x3, 0xff, 0x0, 0x3f, 0xf0, 0x0, 0xff, - 0xc0, 0x0, 0xff, 0xc0, 0x3f, 0xf0, 0x0, 0x3, - 0xff, 0xf, 0xfc, 0x0, 0x0, 0xf, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x3f, 0xff, 0xc0, 0x0, 0x0, - 0x0, 0xff, 0xf0, 0x0, 0x0, 0x0, 0xf, 0xff, - 0x0, 0x0, 0x0, 0x3, 0xff, 0xfc, 0x0, 0x0, - 0x0, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x3f, 0xf0, - 0xff, 0xc0, 0x0, 0xf, 0xfc, 0x3, 0xff, 0x0, - 0x3, 0xff, 0x0, 0xf, 0xfc, 0x0, 0xff, 0xc0, - 0x0, 0x3f, 0xf0, 0x3f, 0xf0, 0x0, 0x0, 0xff, - 0xcb, 0xfc, 0x0, 0x0, 0x3, 0xfe, 0xff, 0x0, - 0x0, 0x0, 0xf, 0xf7, 0x80, 0x0, 0x0, 0x0, - 0x2d, - - /* U+E5D2 "" */ - 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe1, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x54, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x15, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x4f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x15, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x4b, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, - - /* U+E5D4 "" */ - 0x1, 0x40, 0x1f, 0xf4, 0x3f, 0xfc, 0x3f, 0xfd, - 0x3f, 0xfd, 0x2f, 0xfc, 0xb, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x1, 0x40, 0x1f, 0xf4, - 0x3f, 0xfc, 0x3f, 0xfd, 0x3f, 0xfd, 0x2f, 0xfc, - 0xb, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x40, 0x1f, 0xf4, 0x3f, 0xfc, 0x3f, 0xfd, - 0x3f, 0xfd, 0x2f, 0xfc, 0xb, 0xf0, 0x0, 0x0, - - /* U+E5D5 "" */ - 0x0, 0x0, 0x0, 0x14, 0x0, 0x0, 0x10, 0x0, - 0x0, 0x2f, 0xff, 0xf8, 0x0, 0xbc, 0x0, 0x2, - 0xff, 0xff, 0xff, 0x80, 0xfd, 0x0, 0x1f, 0xff, - 0xff, 0xff, 0xf0, 0xfd, 0x0, 0x7f, 0xf9, 0x0, - 0x6f, 0xfd, 0xfd, 0x1, 0xff, 0x80, 0x0, 0x2, - 0xff, 0xfd, 0x3, 0xfd, 0x0, 0x0, 0x0, 0x7f, - 0xfd, 0xb, 0xf4, 0x0, 0x0, 0x0, 0x1f, 0xfd, - 0xf, 0xe0, 0x0, 0x0, 0x0, 0xb, 0xfd, 0x2f, - 0xc0, 0x0, 0x0, 0xbf, 0xff, 0xfd, 0x3f, 0x80, - 0x0, 0x1, 0xff, 0xff, 0xfd, 0x3f, 0x40, 0x0, - 0x0, 0xff, 0xff, 0xfc, 0x3f, 0x0, 0x0, 0x0, - 0x15, 0x55, 0x50, 0x7f, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7f, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3f, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, - 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xc0, - 0x0, 0x0, 0x0, 0x3, 0xe0, 0xf, 0xe0, 0x0, - 0x0, 0x0, 0xb, 0xf0, 0xb, 0xf4, 0x0, 0x0, - 0x0, 0x1f, 0xe0, 0x3, 0xfd, 0x0, 0x0, 0x0, - 0x7f, 0xc0, 0x1, 0xff, 0x80, 0x0, 0x2, 0xff, - 0x40, 0x0, 0x7f, 0xf9, 0x0, 0x6f, 0xfd, 0x0, - 0x0, 0x1f, 0xff, 0xff, 0xff, 0xf4, 0x0, 0x0, - 0x2, 0xff, 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, - 0x2f, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x14, 0x0, 0x0, 0x0, - - /* U+E63E "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x6, 0xff, 0xff, 0xf9, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, - 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, 0x6f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x90, 0x0, 0x0, 0x2f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0, - 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x80, 0xf, 0xff, 0xff, 0xe4, 0x0, 0x1, 0xbf, - 0xff, 0xff, 0x3, 0xff, 0xff, 0x40, 0x0, 0x0, - 0x0, 0x1f, 0xff, 0xfc, 0xff, 0xff, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x1f, 0xff, 0xff, 0xff, 0x40, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, 0xbf, - 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, - 0xe1, 0x90, 0x0, 0x1, 0xbf, 0xff, 0xe4, 0x0, - 0x0, 0x64, 0x0, 0x0, 0x1, 0xff, 0xff, 0xff, - 0xf4, 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xff, - 0xff, 0xff, 0xf4, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, - 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0, - 0x0, 0x3, 0xff, 0xf9, 0x0, 0x6, 0xff, 0xfc, - 0x0, 0x0, 0x0, 0x1f, 0xf8, 0x0, 0x0, 0x2, - 0xff, 0x40, 0x0, 0x0, 0x0, 0x68, 0x0, 0x0, - 0x0, 0x2, 0x90, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xf4, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xff, - 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, - 0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3, 0xff, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0x80, - 0x0, 0x0, 0x0, 0x0, - - /* U+E668 "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7e, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x1f, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0x7, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, - 0x40, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0x1f, 0xf4, 0x0, 0x0, 0x0, - 0x0, 0x7, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x1, - 0xff, 0x40, 0x7, 0xc0, 0x0, 0x0, 0x7f, 0xd0, - 0x0, 0xff, 0x0, 0x0, 0x1f, 0xf4, 0x0, 0xb, - 0xfc, 0x0, 0x7, 0xfd, 0x0, 0x0, 0x2f, 0xf0, - 0x1, 0xff, 0x40, 0x0, 0x0, 0xbf, 0xc0, 0x7f, - 0xd0, 0x0, 0x0, 0x2, 0xff, 0x1f, 0xf4, 0x0, - 0x0, 0x0, 0xb, 0xff, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x2f, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, - 0xbf, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xf4, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, - - /* U+E745 "" */ - 0x5, 0x55, 0x55, 0x55, 0x50, 0x0, 0x0, 0x0, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x3, - 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0, 0x0, 0xb, - 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x55, - 0x55, 0x55, 0x54, 0x0, 0x0, 0x0, 0x3f, 0xff, - 0xff, 0xff, 0xfc, 0x0, 0x0, 0x0, 0xff, 0xff, - 0xff, 0xff, 0xf0, 0x0, 0x0, 0x2, 0xff, 0xff, - 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x1, 0xff, 0x2, 0xff, 0xff, 0xf0, - 0x0, 0x0, 0x1f, 0xff, 0xf, 0xff, 0xff, 0xd0, - 0x0, 0x1, 0xff, 0xfd, 0x3f, 0xff, 0xff, 0x0, - 0x0, 0x1f, 0xff, 0xf8, 0x15, 0x55, 0x50, 0x0, - 0x1, 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0x1f, 0xdf, 0xff, 0x0, 0x0, 0x0, 0x0, 0x1, - 0xfc, 0x1f, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x1f, - 0xc0, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x1, 0xfd, - 0xb, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xd0, - 0xbf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3d, 0xb, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf4, 0xbf, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0x50, 0x0, - 0x0, - - /* U+E770 "" */ - 0x0, 0x0, 0x0, 0x6, 0x40, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x2, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7f, 0xfd, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, - 0x3, 0xfc, 0x7f, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0xbf, 0x41, 0xff, 0xd5, 0x40, 0x0, 0x0, 0x1f, - 0xe0, 0x3, 0xff, 0xff, 0x82, 0x40, 0x3, 0xfc, - 0x0, 0xb, 0xff, 0xfe, 0xfe, 0x0, 0xff, 0x40, - 0x0, 0x1f, 0xff, 0xff, 0xfc, 0x2f, 0xe0, 0x0, - 0x0, 0x0, 0x7f, 0xff, 0xfb, 0xfc, 0x0, 0x0, - 0x0, 0x7, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x7f, 0xfe, 0xff, 0xd0, 0x0, 0x0, 0x0, - 0x7, 0xff, 0xd3, 0xf8, 0x0, 0x10, 0x0, 0x0, - 0x7f, 0xfd, 0xb, 0x0, 0xf, 0x80, 0x0, 0x7, - 0xff, 0xd0, 0x0, 0x2, 0xff, 0x0, 0x0, 0x7f, - 0xfd, 0x0, 0x0, 0x7f, 0xfd, 0x0, 0x7, 0xff, - 0xd0, 0x0, 0xf, 0xff, 0xf8, 0x0, 0x7f, 0xfe, - 0x0, 0x3, 0xff, 0xff, 0xf0, 0x7, 0xff, 0xf8, - 0x0, 0xbf, 0xff, 0xff, 0xc0, 0x7f, 0xff, 0xf0, - 0x1f, 0xff, 0xff, 0xff, 0x47, 0xff, 0xff, 0xd3, - 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xf5, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, - - /* U+E89C "" */ - 0x1, 0x55, 0x55, 0x55, 0x40, 0x0, 0x0, 0x1f, - 0xff, 0xff, 0xff, 0xf4, 0x0, 0x0, 0x3f, 0xff, - 0xff, 0xff, 0xfd, 0x0, 0x0, 0x7f, 0xff, 0xff, - 0xff, 0xff, 0x40, 0x0, 0x7f, 0x0, 0x0, 0x1, - 0xff, 0xd0, 0x0, 0x7f, 0x0, 0x0, 0x1, 0xff, - 0xf4, 0x0, 0x7f, 0x0, 0x0, 0x1, 0xff, 0xfd, - 0x0, 0x7f, 0x0, 0x0, 0x1, 0xff, 0xff, 0x40, - 0x7f, 0x0, 0x0, 0x1, 0xff, 0xff, 0xd0, 0x7f, - 0x0, 0x0, 0x1, 0xff, 0xff, 0xf4, 0x7f, 0x0, - 0x0, 0x1, 0xff, 0xff, 0xfc, 0x7f, 0x0, 0x0, - 0x0, 0xff, 0xff, 0xfc, 0x7f, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xfd, 0x7f, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xfd, 0x7f, 0x0, 0x0, 0x7d, 0x0, 0x0, - 0xfd, 0x7f, 0x0, 0x0, 0xbe, 0x0, 0x0, 0xfd, - 0x7f, 0x0, 0x0, 0xbe, 0x0, 0x0, 0xfd, 0x7f, - 0x0, 0x0, 0xbe, 0x0, 0x0, 0xfd, 0x7f, 0x0, - 0x0, 0xbe, 0x0, 0x0, 0xfd, 0x7f, 0x1, 0xff, - 0xff, 0xff, 0x40, 0xfd, 0x7f, 0x2, 0xff, 0xff, - 0xff, 0x80, 0xfd, 0x7f, 0x1, 0xff, 0xff, 0xff, - 0x40, 0xfd, 0x7f, 0x0, 0x0, 0xbe, 0x0, 0x0, - 0xfd, 0x7f, 0x0, 0x0, 0xbe, 0x0, 0x0, 0xfd, - 0x7f, 0x0, 0x0, 0xbe, 0x0, 0x0, 0xfd, 0x7f, - 0x0, 0x0, 0xbe, 0x0, 0x0, 0xfd, 0x7f, 0x0, - 0x0, 0x7d, 0x0, 0x0, 0xfd, 0x7f, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xfd, 0x7f, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xfd, 0x7f, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xfd, 0x7f, 0x55, 0x55, 0x55, 0x55, 0x55, - 0xfd, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, - 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x7, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xd0, - - /* U+E8AF "" */ - 0x5, 0x55, 0x55, 0x55, 0x55, 0x54, 0x0, 0x0, - 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0, - 0x0, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, - 0x0, 0xf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, - 0x0, 0x0, 0xfd, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xc0, 0x0, 0xf, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0xfc, 0x0, 0x0, 0xfd, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xc0, 0x0, 0xf, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0xfc, 0xb, 0x90, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xc0, 0xff, 0x4f, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0xfc, 0xf, 0xfc, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xc0, 0xff, 0xcf, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0xfc, 0xf, 0xfc, 0xfd, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xc0, 0xff, 0xcf, 0xd0, - 0x0, 0x0, 0x0, 0x0, 0xfc, 0xf, 0xfc, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xc0, 0xff, 0xcf, - 0xd1, 0x55, 0x55, 0x55, 0x56, 0xfc, 0xf, 0xfc, - 0xfd, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xff, - 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, 0xf, - 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x0, - 0xff, 0xcf, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xfc, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xff, 0xcf, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x7f, 0xfc, 0x7c, 0x3, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xc0, 0x0, 0x3f, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfc, 0x0, 0x3, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0, 0x2f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0x0, 0x0, 0xbf, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xc0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xfc, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xc0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, - - /* U+E8B8 "" */ - 0x0, 0x0, 0x0, 0x5, 0x55, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xff, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xbf, 0xff, 0xe0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xfd, 0x7, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xc0, 0x3f, - 0x0, 0x0, 0x0, 0x0, 0xff, 0x87, 0xfc, 0x3, - 0xfd, 0x2f, 0xf0, 0x0, 0x2f, 0xff, 0xff, 0xc0, - 0x3f, 0xff, 0xff, 0x80, 0x7, 0xff, 0xff, 0xf4, - 0x1, 0xff, 0xff, 0xfd, 0x0, 0xff, 0x6f, 0xf0, - 0x0, 0x1, 0xff, 0x9f, 0xf0, 0x1f, 0xd0, 0x18, - 0x0, 0x0, 0x2, 0x80, 0x7f, 0x43, 0xfc, 0x0, - 0x0, 0x1a, 0x40, 0x0, 0x3, 0xfc, 0x3f, 0xd0, - 0x0, 0x1f, 0xff, 0x40, 0x0, 0x7f, 0xc1, 0xff, - 0x80, 0x7, 0xff, 0xfe, 0x0, 0x2f, 0xf4, 0xb, - 0xff, 0x0, 0xff, 0xff, 0xf0, 0xf, 0xfe, 0x0, - 0x1f, 0xf0, 0x1f, 0xff, 0xff, 0x80, 0xff, 0x40, - 0x0, 0x7f, 0x2, 0xff, 0xff, 0xfc, 0xf, 0xd0, - 0x0, 0x7, 0xf0, 0x2f, 0xff, 0xff, 0xc0, 0xfd, - 0x0, 0x0, 0xbf, 0x2, 0xff, 0xff, 0xfc, 0xf, - 0xe0, 0x0, 0x3f, 0xf0, 0x1f, 0xff, 0xff, 0x40, - 0xff, 0xc0, 0xf, 0xfd, 0x0, 0xbf, 0xff, 0xf0, - 0x7, 0xff, 0x2, 0xff, 0x0, 0x3, 0xff, 0xfc, - 0x0, 0xf, 0xf8, 0x3f, 0xc0, 0x0, 0x7, 0xfe, - 0x0, 0x0, 0x3f, 0xc2, 0xfc, 0x0, 0x40, 0x0, - 0x0, 0x0, 0x3, 0xf8, 0xf, 0xf0, 0xbd, 0x0, - 0x0, 0x7, 0xe0, 0xff, 0x0, 0xbf, 0xff, 0xfd, - 0x0, 0x7, 0xff, 0xff, 0xd0, 0x3, 0xff, 0xff, - 0xfc, 0x3, 0xff, 0xff, 0xfc, 0x0, 0x1f, 0xfe, - 0xff, 0xc0, 0x3f, 0xfb, 0xff, 0x0, 0x0, 0x29, - 0x2, 0xfc, 0x3, 0xf8, 0x6, 0x80, 0x0, 0x0, - 0x0, 0xf, 0xc0, 0x3f, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xfe, 0x5b, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7f, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x1, 0xff, 0xf4, 0x0, 0x0, - 0x0, - - /* U+E8FD "" */ - 0x0, 0x0, 0x0, 0x5, 0x55, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0x80, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff, 0x80, - 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, - 0x40, 0x0, 0x0, 0xb, 0xff, 0x90, 0x0, 0x6f, - 0xfe, 0x0, 0x0, 0x3, 0xff, 0x80, 0x0, 0x0, - 0x2f, 0xf8, 0x0, 0x0, 0xff, 0xc0, 0x0, 0x0, - 0x0, 0x3f, 0xe0, 0x0, 0x2f, 0xe0, 0x0, 0x6f, - 0x90, 0x0, 0xff, 0x40, 0x7, 0xfc, 0x0, 0x3f, - 0xff, 0xc0, 0x3, 0xfc, 0x0, 0xff, 0x0, 0xf, - 0xff, 0xff, 0x0, 0xf, 0xe0, 0x1f, 0xd0, 0x1, - 0xfd, 0x7, 0xf8, 0x0, 0xbf, 0x3, 0xfc, 0x0, - 0xb, 0x0, 0x2f, 0xc0, 0x3, 0xf8, 0x3f, 0x40, - 0x0, 0x0, 0x1, 0xfc, 0x0, 0x2f, 0xc7, 0xf0, - 0x0, 0x0, 0x0, 0x2f, 0x80, 0x1, 0xfc, 0xbf, - 0x0, 0x0, 0x0, 0xb, 0xf0, 0x0, 0xf, 0xdb, - 0xe0, 0x0, 0x0, 0x1, 0xfd, 0x0, 0x0, 0xfd, - 0xbe, 0x0, 0x0, 0x0, 0x7f, 0x40, 0x0, 0xf, - 0xeb, 0xe0, 0x0, 0x0, 0xf, 0xd0, 0x0, 0x0, - 0xfe, 0xbe, 0x0, 0x0, 0x1, 0xf8, 0x0, 0x0, - 0xf, 0xeb, 0xf0, 0x0, 0x0, 0x2f, 0x40, 0x0, - 0x0, 0xfd, 0x7f, 0x0, 0x0, 0x0, 0x90, 0x0, - 0x0, 0xf, 0xc3, 0xf4, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x1, 0xfc, 0x3f, 0x80, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0x82, 0xfc, 0x0, 0x0, 0x2f, - 0x40, 0x0, 0x7, 0xf4, 0xf, 0xe0, 0x0, 0x3, - 0xfc, 0x0, 0x0, 0xff, 0x0, 0x7f, 0x80, 0x0, - 0x3f, 0xc0, 0x0, 0x2f, 0xd0, 0x3, 0xfd, 0x0, - 0x2, 0xf4, 0x0, 0xb, 0xf8, 0x0, 0xf, 0xf4, - 0x0, 0x0, 0x0, 0x2, 0xff, 0x0, 0x0, 0x7f, - 0xe0, 0x0, 0x0, 0x0, 0xff, 0xc0, 0x0, 0x1, - 0xff, 0xe0, 0x0, 0x1, 0xbf, 0xf0, 0x0, 0x0, - 0x3, 0xff, 0xfa, 0xaa, 0xff, 0xfc, 0x0, 0x0, - 0x0, 0xb, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0xb, 0xff, 0xff, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x6, 0xbf, 0xe4, 0x0, 0x0, - 0x0, - - /* U+E90F "" */ - 0x0, 0x0, 0x1, 0x54, 0x0, 0x0, 0x0, 0x0, - 0xb, 0xff, 0xfe, 0x0, 0x0, 0x0, 0xb, 0xff, - 0xff, 0xfe, 0x0, 0x0, 0x3, 0xff, 0xff, 0xff, - 0xfc, 0x0, 0x0, 0xff, 0xe0, 0x0, 0xbf, 0xf0, - 0x0, 0x3f, 0xe0, 0x0, 0x0, 0xbf, 0xc0, 0xb, - 0xf8, 0x0, 0x0, 0x2, 0xfe, 0x0, 0xfe, 0x0, - 0x0, 0x0, 0xb, 0xf0, 0x2f, 0xc0, 0x0, 0x0, - 0x0, 0x3f, 0x83, 0xf8, 0x0, 0x0, 0x0, 0x2, - 0xfc, 0x3f, 0x0, 0x0, 0x0, 0x0, 0xf, 0xc7, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0xfd, 0x7f, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xd7, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0xfd, 0x7f, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xd3, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xfc, - 0x3f, 0x80, 0x0, 0x0, 0x0, 0x2f, 0xc2, 0xfc, - 0x0, 0x0, 0x0, 0x3, 0xf8, 0xf, 0xe0, 0x0, - 0x0, 0x0, 0xbf, 0x0, 0xbf, 0x80, 0x0, 0x0, - 0x2f, 0xe0, 0x3, 0xfe, 0x55, 0x55, 0x5b, 0xfc, - 0x0, 0xf, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, - 0x7f, 0xff, 0xff, 0xff, 0xc0, 0x0, 0x0, 0xbf, - 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x15, 0x55, 0x55, 0x40, - 0x0, 0x0, 0xb, 0xff, 0xff, 0xfd, 0x0, 0x0, - 0x0, 0xbf, 0xff, 0xff, 0xe0, 0x0, 0x0, 0x3, - 0xff, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0x55, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0xb, 0xfe, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x2f, 0x40, 0x0, 0x0, - - /* U+E92E "" */ - 0x0, 0x0, 0x1f, 0xff, 0xf4, 0x0, 0x0, 0x5, - 0x55, 0x7f, 0xff, 0xfd, 0x55, 0x50, 0x3f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfd, 0x2f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfc, 0xb, 0xe0, 0x0, 0x0, 0x0, - 0xb, 0xe0, 0xb, 0xe0, 0x0, 0x0, 0x0, 0xb, - 0xe0, 0xb, 0xe0, 0x0, 0x0, 0x0, 0xb, 0xe0, - 0xb, 0xe0, 0x9, 0x0, 0x60, 0xb, 0xe0, 0xb, - 0xe0, 0x3f, 0x0, 0xfc, 0xb, 0xe0, 0xb, 0xe0, - 0x3f, 0x41, 0xfc, 0xb, 0xe0, 0xb, 0xe0, 0x3f, - 0x41, 0xfc, 0xb, 0xe0, 0xb, 0xe0, 0x3f, 0x41, - 0xfc, 0xb, 0xe0, 0xb, 0xe0, 0x3f, 0x41, 0xfc, - 0xb, 0xe0, 0xb, 0xe0, 0x3f, 0x41, 0xfc, 0xb, - 0xe0, 0xb, 0xe0, 0x3f, 0x41, 0xfc, 0xb, 0xe0, - 0xb, 0xe0, 0x3f, 0x41, 0xfc, 0xb, 0xe0, 0xb, - 0xe0, 0x3f, 0x41, 0xfc, 0xb, 0xe0, 0xb, 0xe0, - 0x3f, 0x41, 0xfc, 0xb, 0xe0, 0xb, 0xe0, 0x3f, - 0x41, 0xfc, 0xb, 0xe0, 0xb, 0xe0, 0x3f, 0x41, - 0xfc, 0xb, 0xe0, 0xb, 0xe0, 0x3f, 0x41, 0xfc, - 0xb, 0xe0, 0xb, 0xe0, 0x2f, 0x0, 0xf8, 0xb, - 0xe0, 0xb, 0xe0, 0x4, 0x0, 0x10, 0xb, 0xe0, - 0xb, 0xe0, 0x0, 0x0, 0x0, 0xb, 0xe0, 0xb, - 0xe0, 0x0, 0x0, 0x0, 0xb, 0xe0, 0xb, 0xf5, - 0x55, 0x55, 0x55, 0x5b, 0xe0, 0xb, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xe0, 0x3, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xc0, 0x0, 0xbf, 0xff, 0xff, 0xff, - 0xff, 0x0, - - /* U+E9B9 "" */ - 0x5, 0x40, 0x0, 0x5a, 0xaa, 0xaa, 0xaa, 0xa4, - 0x2, 0xff, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, - 0xf8, 0x7f, 0xf8, 0x7, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xdb, 0xff, 0xc0, 0xbf, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0xbf, 0xfc, 0xb, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xd3, 0xff, 0x40, 0x3f, 0xff, 0xff, - 0xff, 0xff, 0xfc, 0x1f, 0xe0, 0x1, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0x40, 0x0, - 0x5a, 0xaa, 0xaa, 0xaa, 0xa4, 0x2, 0xff, 0x0, - 0x2f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x7f, 0xf8, - 0x7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdb, 0xff, - 0xc0, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xbf, - 0xfc, 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd3, - 0xff, 0x40, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xfc, - 0x1f, 0xe0, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x5, 0x40, 0x0, 0x5a, 0xaa, 0xaa, - 0xaa, 0xa4, 0x2, 0xff, 0x0, 0x2f, 0xff, 0xff, - 0xff, 0xff, 0xf8, 0x7f, 0xf8, 0x7, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xdb, 0xff, 0xc0, 0xbf, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0xbf, 0xfc, 0xb, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xd3, 0xff, 0x40, 0x3f, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0x1f, 0xe0, 0x1, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - - /* U+E9F4 "" */ - 0x0, 0x0, 0x0, 0x0, 0x1f, 0xf4, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xfe, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, - 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3, 0xfe, 0x7f, 0xc0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xf8, 0x1f, 0xc0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xf8, 0x1f, - 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, - 0xfe, 0x7f, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x1, 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7f, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xf4, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xfd, - 0x0, 0x0, 0x3, 0xd0, 0x0, 0x0, 0x7f, 0xd0, - 0x2f, 0xff, 0x80, 0x0, 0x3, 0xd0, 0x0, 0x2, - 0xff, 0xf8, 0x7f, 0xff, 0xd0, 0x0, 0x7, 0xe0, - 0x0, 0x7, 0xff, 0xfd, 0xff, 0x5f, 0xf0, 0x0, - 0xbf, 0xff, 0x0, 0xf, 0xf5, 0xff, 0xfd, 0x7, - 0xf0, 0x3, 0xff, 0xff, 0xc0, 0xf, 0xd0, 0x7f, - 0xfe, 0xb, 0xf9, 0xf, 0xfe, 0xbf, 0xf0, 0x6f, - 0xe0, 0xbf, 0xbf, 0xaf, 0xff, 0xff, 0xe0, 0xb, - 0xff, 0xff, 0xfa, 0xfe, 0x3f, 0xff, 0xef, 0xff, - 0x80, 0x2, 0xff, 0xfb, 0xff, 0xfc, 0x1f, 0xff, - 0x41, 0xff, 0x0, 0x0, 0xff, 0x41, 0xff, 0xf4, - 0x2, 0xf8, 0x0, 0x7f, 0x0, 0x0, 0xfd, 0x0, - 0x2f, 0x80, 0x0, 0x0, 0x0, 0x7f, 0x0, 0x0, - 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, - 0x0, 0x0, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0xc0, 0x2, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xe0, 0xb, 0xf8, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0xbf, 0xfe, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x14, 0xbe, 0x5, 0x50, 0xbe, 0x14, - 0x0, 0x0, 0x0, 0x3, 0xff, 0xfc, 0x0, 0x0, - 0x3f, 0xff, 0xc0, 0x0, 0x0, 0xf, 0xff, 0xf0, - 0x0, 0x0, 0xf, 0xff, 0xf0, 0x0, 0x0, 0x2f, - 0xff, 0xf8, 0x0, 0x0, 0x2f, 0xff, 0xf8, 0x0, - 0x0, 0x3f, 0x82, 0xfc, 0x0, 0x0, 0x3f, 0x82, - 0xfc, 0x0, 0x0, 0x3f, 0x41, 0xfc, 0x0, 0x0, - 0x3f, 0x41, 0xfc, 0x0, 0x0, 0x3f, 0xc3, 0xfc, - 0x0, 0x0, 0x3f, 0xc3, 0xfc, 0x0, 0x0, 0x2f, - 0xff, 0xf8, 0x0, 0x0, 0x2f, 0xff, 0xf8, 0x0, - 0x0, 0xf, 0xff, 0xf0, 0x0, 0x0, 0xf, 0xff, - 0xf0, 0x0, 0x0, 0x2, 0xff, 0x80, 0x0, 0x0, - 0x2, 0xff, 0x80, 0x0, 0x0, 0x0, 0x14, 0x0, - 0x0, 0x0, 0x0, 0x14, 0x0, 0x0, - - /* U+E9F7 "" */ - 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x47, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe5, - 0x55, 0x55, 0x55, 0x55, 0x55, 0xbf, 0xfd, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7f, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7f, 0xfe, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x5b, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x7, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x7f, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, - 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, 0xd0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xfd, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7f, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7f, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7f, 0xfe, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x5b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xd1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xf4, - - /* U+EA07 "" */ - 0x0, 0x0, 0x0, 0x5, 0x54, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff, 0x80, - 0x0, 0x0, 0x0, 0x1f, 0xff, 0xff, 0xff, 0xff, - 0x40, 0x0, 0x0, 0xb, 0xff, 0xff, 0xaf, 0xff, - 0xfe, 0x0, 0x0, 0x3, 0xff, 0x8f, 0xf0, 0xfe, - 0x2f, 0xf8, 0x0, 0x0, 0xbf, 0xc1, 0xfd, 0xb, - 0xf0, 0x7f, 0xe0, 0x0, 0x2f, 0xf0, 0x2f, 0xc0, - 0x3f, 0x80, 0xff, 0x40, 0x3, 0xfc, 0x3, 0xf4, - 0x2, 0xfc, 0x3, 0xfc, 0x0, 0xff, 0x0, 0x7f, - 0x0, 0x1f, 0xc0, 0x1f, 0xe0, 0x1f, 0xf5, 0x5f, - 0xf5, 0x55, 0xfe, 0x55, 0xff, 0x2, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xbf, - 0x0, 0x1f, 0xc0, 0x0, 0x3f, 0x0, 0xf, 0xdb, - 0xe0, 0x1, 0xfc, 0x0, 0x3, 0xf4, 0x0, 0xfd, - 0xbe, 0x0, 0x2f, 0xc0, 0x0, 0x3f, 0x40, 0xf, - 0xef, 0xe0, 0x2, 0xfc, 0x0, 0x3, 0xf4, 0x0, - 0xfe, 0xbe, 0x0, 0x2f, 0xc0, 0x0, 0x3f, 0x40, - 0xf, 0xeb, 0xf0, 0x1, 0xfc, 0x0, 0x3, 0xf4, - 0x0, 0xfd, 0x7f, 0x55, 0x6f, 0xd5, 0x55, 0xbf, - 0x95, 0x6f, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x82, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf4, 0xf, 0xf0, 0x7, 0xf0, - 0x0, 0xfd, 0x0, 0xff, 0x0, 0x7f, 0x80, 0x3f, - 0x40, 0x1f, 0xc0, 0x2f, 0xd0, 0x3, 0xfd, 0x3, - 0xf8, 0x3, 0xf8, 0xb, 0xf8, 0x0, 0xf, 0xf4, - 0x1f, 0xc0, 0x7f, 0x42, 0xff, 0x0, 0x0, 0x7f, - 0xe0, 0xfe, 0xf, 0xf0, 0xff, 0xc0, 0x0, 0x1, - 0xff, 0xeb, 0xf5, 0xfe, 0xbf, 0xf0, 0x0, 0x0, - 0x3, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x0, 0x0, - 0x0, 0xb, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0xb, 0xff, 0xff, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x6, 0xbf, 0xe4, 0x0, 0x0, - 0x0, - - /* U+EAD6 "" */ - 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x47, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe5, - 0x55, 0x55, 0x55, 0x55, 0x55, 0xbf, 0xfd, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7f, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7f, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7f, 0xfd, 0x2f, 0xf4, 0xff, 0xcb, - 0x2, 0xc7, 0xff, 0xd3, 0xff, 0xcf, 0xfc, 0xb4, - 0x3c, 0x7f, 0xfd, 0x3c, 0x3c, 0xf0, 0x7, 0x83, - 0xc7, 0xff, 0xd3, 0xc3, 0xcf, 0x0, 0x3c, 0x78, - 0x7f, 0xfd, 0x3c, 0x3c, 0xfe, 0x3, 0xcb, 0x47, - 0xff, 0xd3, 0xc3, 0xcf, 0xe0, 0x2d, 0xf0, 0x7f, - 0xfd, 0x3c, 0x3c, 0xf0, 0x1, 0xff, 0x7, 0xff, - 0xd3, 0xc3, 0xcf, 0x0, 0xf, 0xd0, 0x7f, 0xfd, - 0x3f, 0xfc, 0xff, 0xc0, 0xfc, 0x7, 0xff, 0xd2, - 0xff, 0x4f, 0xfc, 0x7, 0x80, 0x7f, 0xfd, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7f, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7f, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7f, 0xfe, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x5b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xd1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xf4, - - /* U+EB8E "" */ - 0x6, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa4, - 0x3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xf4, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xdf, 0xe0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xfd, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xdf, 0xd0, 0x1, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xfd, 0xfd, 0x0, 0xfc, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xdf, 0xd0, 0x1f, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0xfd, 0xfd, 0x0, - 0xbf, 0xc0, 0x0, 0x0, 0x0, 0xf, 0xdf, 0xd0, - 0x3, 0xff, 0x0, 0x0, 0x0, 0x0, 0xfd, 0xfd, - 0x0, 0xf, 0xfc, 0x0, 0x0, 0x0, 0xf, 0xdf, - 0xd0, 0x0, 0x3f, 0xc0, 0x0, 0x0, 0x0, 0xfd, - 0xfd, 0x0, 0xb, 0xfc, 0x0, 0x0, 0x0, 0xf, - 0xdf, 0xd0, 0x2, 0xff, 0x0, 0x0, 0x0, 0x0, - 0xfd, 0xfd, 0x0, 0xbf, 0xc0, 0x0, 0x0, 0x0, - 0xf, 0xdf, 0xd0, 0xf, 0xf0, 0x2, 0xff, 0xff, - 0x40, 0xfd, 0xfd, 0x0, 0xfc, 0x0, 0x3f, 0xff, - 0xf8, 0xf, 0xdf, 0xd0, 0x6, 0x0, 0x3, 0xff, - 0xff, 0x80, 0xfd, 0xfd, 0x0, 0x0, 0x0, 0x5, - 0x55, 0x40, 0xf, 0xdf, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xfd, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xd7, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x40, 0x15, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x0, - - /* U+EB97 "" */ - 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0x7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfc, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xdf, 0xe5, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0xfd, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xdf, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xfd, 0xfd, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xdf, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0xf0, 0x0, 0xfd, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0xf, 0x40, 0xf, 0xdf, 0xd0, 0x3f, 0xff, - 0xff, 0xf0, 0xff, 0x80, 0xfd, 0xfd, 0x3, 0xff, - 0xff, 0xff, 0xf, 0xf8, 0xf, 0xdf, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0xf4, 0x0, 0xfd, 0xfd, 0x0, - 0x0, 0x0, 0x0, 0xf, 0x0, 0xf, 0xdf, 0xd0, - 0x1, 0xd0, 0x0, 0x0, 0x0, 0x0, 0xfd, 0xfd, - 0x0, 0x2f, 0x0, 0x0, 0x0, 0x0, 0xf, 0xdf, - 0xd0, 0x2f, 0xf0, 0xbf, 0xff, 0xfe, 0x0, 0xfd, - 0xfd, 0x3, 0xff, 0x2f, 0xff, 0xff, 0xf8, 0xf, - 0xdf, 0xd0, 0x3f, 0xf1, 0xff, 0xff, 0xff, 0x40, - 0xfd, 0xfd, 0x0, 0x3f, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xdf, 0xd0, 0x2, 0xe0, 0x0, 0x0, 0x0, - 0x0, 0xfd, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xdf, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xfd, 0xfd, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xdf, 0xe5, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0xfd, 0xbf, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xf8, 0xb, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, - 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xbf, 0xff, 0xff, 0xc0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - - /* U+EBCC "" */ - 0x0, 0x9, 0x0, 0x0, 0x0, 0x6, 0x0, 0x0, - 0x3, 0xf0, 0x0, 0x0, 0x0, 0xfc, 0x0, 0x0, - 0x3f, 0x40, 0x0, 0x0, 0x1f, 0xc0, 0x0, 0x17, - 0xf9, 0x55, 0x55, 0x56, 0xfd, 0x40, 0x2f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x8b, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7f, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7f, 0xfe, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x5b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, - 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xd0, 0x2d, 0x1, 0xf0, 0x7, 0x80, 0x7f, 0xfd, - 0x7, 0xf0, 0x2f, 0x80, 0xfd, 0x7, 0xff, 0xd0, - 0x3e, 0x1, 0xf4, 0xb, 0xc0, 0x7f, 0xfd, 0x0, - 0x40, 0x0, 0x0, 0x10, 0x7, 0xff, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7f, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7, 0xff, 0xd0, 0x4, 0x0, - 0x0, 0x1, 0x0, 0x7f, 0xfd, 0x3, 0xe0, 0x1f, - 0x40, 0xbc, 0x7, 0xff, 0xd0, 0x7f, 0x2, 0xf8, - 0xf, 0xd0, 0x7f, 0xfd, 0x2, 0xd0, 0x1f, 0x0, - 0x78, 0x7, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x7f, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x7, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x7f, 0xfe, 0x55, 0x55, 0x55, 0x55, 0x55, 0x5b, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd1, - 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe4, - - /* U+EC1C "" */ - 0x0, 0x0, 0x0, 0x0, 0x2, 0x40, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x1f, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7f, 0xc0, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x7, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfe, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xfc, 0x0, - 0x0, 0x0, 0x0, 0x1, 0xff, 0xf8, 0x0, 0x0, - 0x0, 0x0, 0xb, 0xff, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x2f, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0xbf, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x2, 0xff, - 0xbf, 0x40, 0x0, 0x0, 0x0, 0xb, 0xfd, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x2f, 0xf1, 0xff, 0xfe, - 0x94, 0x0, 0x0, 0xbf, 0xc3, 0xff, 0xff, 0xff, - 0xf4, 0x3, 0xff, 0x6, 0xff, 0xff, 0xff, 0xfc, - 0xf, 0xfc, 0x0, 0x0, 0x5a, 0xff, 0xf8, 0x2f, - 0xff, 0xa5, 0x0, 0x0, 0x3f, 0xf0, 0x3f, 0xff, - 0xff, 0xff, 0x80, 0xff, 0xc0, 0x1f, 0xff, 0xff, - 0xff, 0xc3, 0xfe, 0x0, 0x0, 0x16, 0xbf, 0xff, - 0x4f, 0xf8, 0x0, 0x0, 0x0, 0x0, 0xff, 0x3f, - 0xe0, 0x0, 0x0, 0x0, 0x1, 0xfe, 0xff, 0x80, - 0x0, 0x0, 0x0, 0x3, 0xff, 0xfe, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xf8, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0x2f, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, 0x3f, - 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xf4, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0x2, 0xff, 0x40, 0x0, 0x0, - 0x0, 0x0, 0x3, 0xfd, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x7, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x80, 0x0, 0x0, 0x0, 0x0, - - /* U+EF40 "" */ - 0x1, 0x40, 0x0, 0x14, 0x0, 0x1, 0x40, 0x0, - 0x7f, 0xd0, 0x7, 0xfd, 0x0, 0x7f, 0xd0, 0x3, - 0xff, 0xc0, 0x3f, 0xfc, 0x3, 0xff, 0xc0, 0xf, - 0xff, 0x40, 0xff, 0xf4, 0xf, 0xff, 0x40, 0x3f, - 0xfd, 0x3, 0xff, 0xd0, 0x3f, 0xfd, 0x0, 0xbf, - 0xf0, 0xb, 0xff, 0x0, 0xbf, 0xf0, 0x0, 0xbf, - 0x0, 0xb, 0xf0, 0x0, 0xbf, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x14, 0x0, - 0x1, 0x40, 0x0, 0x0, 0x0, 0x7, 0xfd, 0x0, - 0x7f, 0xd0, 0x0, 0x0, 0x0, 0x3f, 0xfc, 0x3, - 0xff, 0xc0, 0x0, 0x1e, 0x0, 0xff, 0xf4, 0xf, - 0xff, 0x40, 0x2, 0xff, 0x3, 0xff, 0xd0, 0x3f, - 0xfd, 0x0, 0x2f, 0xff, 0xb, 0xff, 0x0, 0xbf, - 0xf0, 0x2, 0xff, 0xfe, 0xb, 0xf0, 0x0, 0xbf, - 0x0, 0x2f, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, - 0x2, 0xff, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0x2f, 0xdf, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x2, - 0xfc, 0x1f, 0xe0, 0x1, 0x40, 0x0, 0x0, 0x2f, - 0xc0, 0xfe, 0x0, 0x7f, 0xd0, 0x0, 0x2, 0xfc, - 0xf, 0xe0, 0x3, 0xff, 0xc0, 0x0, 0xf, 0xc0, - 0xfe, 0x0, 0xf, 0xff, 0x40, 0x0, 0x3d, 0xf, - 0xe0, 0x0, 0x3f, 0xfd, 0x0, 0x0, 0xf9, 0xfe, - 0x0, 0x0, 0xbf, 0xf0, 0x0, 0x3, 0xff, 0xe0, - 0x0, 0x0, 0xbf, 0x0, 0x0, 0xf, 0xfe, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, - - /* U+EF4A "" */ - 0x0, 0x0, 0x0, 0x5, 0x55, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0x80, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff, 0x80, - 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, - 0x40, 0x0, 0x0, 0xb, 0xff, 0x90, 0x0, 0x6f, - 0xfe, 0x0, 0x0, 0x3, 0xff, 0x80, 0x0, 0x0, - 0x2f, 0xf8, 0x0, 0x0, 0xff, 0xc0, 0x0, 0x0, - 0x0, 0x3f, 0xe0, 0x0, 0x2f, 0xe0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0x40, 0x7, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0x3, 0xfc, 0x0, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xe0, 0x1f, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xbf, 0x3, 0xfc, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3, 0xf8, 0x3f, 0x40, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xc7, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xfc, 0xbf, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xdb, - 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfd, - 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xeb, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xfe, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xeb, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xfd, 0x7f, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xc3, 0xf4, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x1, 0xfc, 0x3f, 0x80, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0x82, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xf4, 0xf, 0xe0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0x0, 0x7f, 0x80, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xd0, 0x3, 0xfd, 0x0, - 0x0, 0x0, 0x0, 0xb, 0xf8, 0x0, 0xf, 0xf4, - 0x0, 0x0, 0x0, 0x2, 0xff, 0x0, 0x0, 0x7f, - 0xe0, 0x0, 0x0, 0x0, 0xff, 0xc0, 0x0, 0x1, - 0xff, 0xe0, 0x0, 0x1, 0xbf, 0xf0, 0x0, 0x0, - 0x3, 0xff, 0xfa, 0xaa, 0xff, 0xfc, 0x0, 0x0, - 0x0, 0xb, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0xb, 0xff, 0xff, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x6, 0xbf, 0xe4, 0x0, 0x0, - 0x0, - - /* U+EF7A "" */ - 0x0, 0x1, 0xff, 0xe4, 0x0, 0x0, 0x0, 0x0, - 0x2, 0xff, 0xff, 0xf4, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x3f, - 0xf9, 0x5b, 0xff, 0x80, 0x0, 0x0, 0xf, 0xf8, - 0x0, 0x7, 0xfe, 0x0, 0x0, 0x2, 0xfe, 0x0, - 0x0, 0xf, 0xf0, 0x0, 0x0, 0x3f, 0x80, 0x0, - 0x0, 0x3f, 0x80, 0x0, 0x7, 0xf0, 0x0, 0x0, - 0x2, 0xfc, 0x0, 0x0, 0xbe, 0x0, 0x0, 0x0, - 0xf, 0xd0, 0x0, 0xf, 0xd0, 0x0, 0x0, 0x0, - 0xfd, 0x0, 0x0, 0xfd, 0x0, 0x0, 0x0, 0xf, - 0xe0, 0x0, 0xf, 0xd0, 0x0, 0x0, 0x0, 0xfe, - 0x0, 0x0, 0xfd, 0x0, 0x0, 0x0, 0xf, 0xd0, - 0x0, 0xb, 0xf0, 0x0, 0x0, 0x0, 0xfc, 0x0, - 0x0, 0x7f, 0x0, 0x0, 0x0, 0x2f, 0xc0, 0x0, - 0x3, 0xfc, 0x0, 0x0, 0x7, 0xf8, 0x0, 0x0, - 0x2f, 0xe0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, - 0xff, 0xd0, 0x0, 0x7f, 0xe0, 0x0, 0x0, 0x3, - 0xff, 0xea, 0xbf, 0xff, 0x80, 0x0, 0x0, 0xf, - 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x1f, - 0xff, 0xfe, 0xf, 0xf8, 0x0, 0x0, 0x0, 0x1a, - 0xf9, 0x0, 0x3f, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x10, - - /* U+EFE6 "" */ - 0x0, 0x2, 0xff, 0x40, 0x0, 0xb, 0xfe, 0x0, - 0x1, 0xff, 0xff, 0x0, 0x1, 0xff, 0xf4, 0x0, - 0x3f, 0xff, 0xfc, 0x0, 0x1f, 0xff, 0x40, 0xf, - 0xf9, 0x7f, 0xe0, 0x2, 0xff, 0xf8, 0x1, 0xfe, - 0x0, 0xbf, 0x0, 0xff, 0xff, 0xf0, 0x2f, 0xc0, - 0x3, 0xf4, 0xf, 0xff, 0xff, 0x2, 0xf8, 0x0, - 0x3f, 0x40, 0xff, 0xff, 0xf0, 0x2f, 0x80, 0x3, - 0xf4, 0xf, 0xff, 0xff, 0x2, 0xf8, 0x0, 0x3f, - 0x40, 0xff, 0xff, 0xf0, 0x2f, 0x80, 0x3, 0xf4, - 0xf, 0xff, 0xff, 0x2, 0xf8, 0x0, 0x3f, 0x40, - 0xff, 0xff, 0xf0, 0x2f, 0x80, 0x3, 0xf4, 0x2, - 0xbf, 0xe8, 0x2, 0xf8, 0x0, 0x3f, 0x40, 0x2, - 0xf8, 0x0, 0x2f, 0x80, 0x3, 0xf4, 0x0, 0x2f, - 0x80, 0x2, 0xf8, 0x0, 0x3f, 0x40, 0x2, 0xf8, - 0x0, 0x2f, 0x80, 0x3, 0xf4, 0x0, 0x2f, 0x80, - 0x2, 0xf8, 0x0, 0x3f, 0x40, 0x2, 0xf8, 0x0, - 0x2f, 0x80, 0x3, 0xf4, 0x0, 0x2f, 0x80, 0x2b, - 0xfe, 0x80, 0x3f, 0x40, 0x2, 0xf8, 0xf, 0xff, - 0xff, 0x3, 0xf4, 0x0, 0x2f, 0x80, 0xff, 0xff, - 0xf0, 0x3f, 0x40, 0x2, 0xf8, 0xf, 0xff, 0xff, - 0x3, 0xf4, 0x0, 0x2f, 0x80, 0xff, 0xff, 0xf0, - 0x3f, 0x40, 0x2, 0xf8, 0xf, 0xff, 0xff, 0x3, - 0xf4, 0x0, 0x2f, 0x80, 0xff, 0xff, 0xf0, 0x3f, - 0x80, 0x3, 0xf8, 0xf, 0xff, 0xff, 0x2, 0xfd, - 0x0, 0xbf, 0x40, 0x2f, 0xff, 0x80, 0xf, 0xf9, - 0x7f, 0xf0, 0x1, 0xff, 0xf4, 0x0, 0x7f, 0xff, - 0xfc, 0x0, 0x1f, 0xff, 0x40, 0x1, 0xff, 0xff, - 0x0, 0x0, 0xbf, 0xe0, 0x0, 0x2, 0xff, 0x40, - 0x0, - - /* U+F028 "" */ - 0x0, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x50, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xd7, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xfd, 0x7f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xd7, 0xf0, 0xa, 0x0, 0x24, 0x1, - 0x80, 0xa, 0x0, 0xfd, 0x7f, 0x2, 0xf8, 0xf, - 0xc0, 0x7f, 0x2, 0xf8, 0xf, 0xd7, 0xf0, 0x2f, - 0x80, 0xfc, 0x7, 0xf0, 0x2f, 0x80, 0xfd, 0x7f, - 0x0, 0xa0, 0x2, 0x40, 0x18, 0x0, 0xa0, 0xf, - 0xd7, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xfd, 0x7f, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xd7, 0xf0, 0xa, 0x0, 0x78, - 0x2, 0xd0, 0xa, 0x0, 0xfd, 0x7f, 0x2, 0xf8, - 0xf, 0xc0, 0x7f, 0x2, 0xf8, 0xf, 0xd7, 0xf0, - 0x1f, 0x40, 0xfc, 0x3, 0xf0, 0x1f, 0x40, 0xfd, - 0x7f, 0x0, 0x50, 0x1, 0x0, 0x14, 0x0, 0x50, - 0xf, 0xd7, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xfd, 0x7f, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xd7, 0xf0, 0x0, 0x3, - 0xff, 0xff, 0xfc, 0x0, 0x0, 0xfd, 0x7f, 0x0, - 0x0, 0xbf, 0xff, 0xff, 0xe0, 0x0, 0xf, 0xd7, - 0xf0, 0x0, 0x7, 0xff, 0xff, 0xfd, 0x0, 0x0, - 0xfd, 0x7f, 0x0, 0x0, 0x5, 0x55, 0x55, 0x0, - 0x0, 0xf, 0xd7, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xfd, 0x3f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xf, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x0, 0x5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x0, - - /* U+F090 "" */ - 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xbc, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfd, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xfd, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x1, - 0x0, 0xfd, 0x1, 0x0, 0x0, 0x0, 0xb, 0xd0, - 0xfd, 0xb, 0xc0, 0x0, 0x0, 0xf, 0xf4, 0xfd, - 0x3f, 0xd0, 0x0, 0x0, 0x7, 0xfd, 0xfd, 0xff, - 0xc0, 0x0, 0x0, 0x1, 0xff, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x7f, 0xff, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0x1f, 0xff, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x7, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xff, 0x0, 0x0, 0x0, 0x2d, 0x0, 0x0, - 0x7c, 0x0, 0x0, 0x78, 0x7f, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xfd, 0x7f, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xfd, 0x7f, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xfd, 0x7f, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfd, - 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x3f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xf, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x0, - - /* U+F15C "" */ - 0x0, 0x0, 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0x90, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, - 0xff, 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, - 0xb, 0xfe, 0x40, 0x1f, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x2, 0xff, 0x40, 0x0, 0x1f, 0xf4, 0x0, - 0x0, 0x0, 0x0, 0x3f, 0xc0, 0x0, 0x0, 0x7f, - 0xc0, 0x0, 0x0, 0x0, 0xb, 0xf0, 0x0, 0x0, - 0x1, 0xfd, 0x0, 0x0, 0x0, 0x0, 0xfe, 0x0, - 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, 0x6f, - 0xc0, 0x0, 0x0, 0x0, 0x7f, 0x0, 0x0, 0x0, - 0x7f, 0xfc, 0x0, 0x0, 0x0, 0x3, 0xf4, 0x0, - 0x0, 0x1f, 0xff, 0x80, 0x0, 0x0, 0x0, 0x3f, - 0x40, 0x0, 0x7, 0xff, 0x50, 0x0, 0x0, 0x0, - 0x3, 0xfd, 0x0, 0x0, 0xff, 0x40, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x2f, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xff, 0xfc, 0x3, 0xf8, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x2a, 0xff, 0xf0, - 0x3f, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xbf, 0x87, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x2, 0xfc, 0x7f, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xc3, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xfd, 0x3f, 0x40, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xd2, - 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, - 0xfc, 0x1f, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0xc0, 0xbf, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x1f, 0xf4, 0x3, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0xb, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0, - 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd0, - 0x0, 0x0, 0x1, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x40, 0x0, - - /* U+F720 "" */ - 0x0, 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xb, 0xfd, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x7, 0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, - 0x7, 0xff, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x2, - 0xff, 0xe1, 0xff, 0xf4, 0x0, 0x0, 0x2, 0xff, - 0xf0, 0x1, 0xff, 0xf4, 0x0, 0x1, 0xff, 0xf4, - 0x0, 0x2, 0xff, 0xe0, 0x0, 0xff, 0xf8, 0x0, - 0x0, 0x3, 0xff, 0xe0, 0x7f, 0xf8, 0x0, 0x0, - 0x0, 0x7, 0xff, 0xcf, 0xfe, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xfd, 0xff, 0xf8, 0x0, 0x0, 0x0, - 0x7, 0xff, 0xef, 0xff, 0xf4, 0x0, 0x0, 0x2, - 0xff, 0xfe, 0xfe, 0xff, 0xf0, 0x0, 0x2, 0xff, - 0xff, 0xef, 0xd2, 0xff, 0xe0, 0x1, 0xff, 0xf4, - 0xfe, 0xfd, 0x3, 0xff, 0xd0, 0xff, 0xf8, 0xf, - 0xef, 0xd0, 0x7, 0xff, 0xff, 0xf8, 0x0, 0xfe, - 0xfd, 0x0, 0xb, 0xff, 0xfd, 0x0, 0xf, 0xef, - 0xd0, 0x0, 0xf, 0xfe, 0x0, 0x0, 0xfe, 0xfd, - 0x0, 0x0, 0x3f, 0x40, 0x0, 0xf, 0xef, 0xd0, - 0x0, 0x3, 0xf4, 0x0, 0x0, 0xfe, 0xfd, 0x0, - 0x0, 0x3f, 0x40, 0x0, 0xf, 0xef, 0xd0, 0x0, - 0x3, 0xf4, 0x0, 0x0, 0xfe, 0xfd, 0x0, 0x0, - 0x3f, 0x40, 0x0, 0xf, 0xef, 0xd0, 0x0, 0x3, - 0xf4, 0x0, 0x0, 0xfe, 0xff, 0x80, 0x0, 0x3f, - 0x40, 0x0, 0x3f, 0xdb, 0xff, 0x40, 0x3, 0xf4, - 0x0, 0x2f, 0xfc, 0x2f, 0xff, 0x0, 0x3f, 0x40, - 0x1f, 0xff, 0x0, 0x3f, 0xfe, 0x3, 0xf4, 0xf, - 0xff, 0x80, 0x0, 0x7f, 0xfd, 0x3f, 0x4b, 0xff, - 0x80, 0x0, 0x0, 0xbf, 0xff, 0xff, 0xff, 0xd0, - 0x0, 0x0, 0x0, 0xbf, 0xff, 0xff, 0xd0, 0x0, - 0x0, 0x0, 0x1, 0xff, 0xff, 0xe0, 0x0, 0x0, - 0x0, 0x0, 0x1, 0xff, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x2, 0xe4, 0x0, 0x0, 0x0, - - /* U+F8C7 "" */ - 0x0, 0x0, 0x0, 0x0, 0x50, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x2f, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3, 0xf4, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xf4, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0x40, - 0x0, 0x0, 0x0, 0x0, 0xf4, 0x0, 0x3, 0xf4, - 0x0, 0x2, 0xd0, 0x0, 0x2f, 0xc0, 0x0, 0x3f, - 0x40, 0x0, 0x7f, 0x0, 0x7, 0xf8, 0x0, 0x3, - 0xf4, 0x0, 0x3, 0xfc, 0x0, 0xff, 0x0, 0x0, - 0x3f, 0x40, 0x0, 0x2f, 0xd0, 0x1f, 0xd0, 0x0, - 0x3, 0xf4, 0x0, 0x0, 0xff, 0x3, 0xfc, 0x0, - 0x0, 0x3f, 0x40, 0x0, 0x7, 0xf0, 0x3f, 0x40, - 0x0, 0x3, 0xf4, 0x0, 0x0, 0x3f, 0x87, 0xf0, - 0x0, 0x0, 0x3f, 0x40, 0x0, 0x2, 0xfc, 0xbf, - 0x0, 0x0, 0x3, 0xf4, 0x0, 0x0, 0x1f, 0xcb, - 0xe0, 0x0, 0x0, 0x3f, 0x40, 0x0, 0x0, 0xfc, - 0xbe, 0x0, 0x0, 0x3, 0xf4, 0x0, 0x0, 0xf, - 0xcf, 0xe0, 0x0, 0x0, 0x3f, 0x40, 0x0, 0x0, - 0xfc, 0xbe, 0x0, 0x0, 0x1, 0xe0, 0x0, 0x0, - 0xf, 0xcb, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xfc, 0x7f, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x2f, 0xc3, 0xf4, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3, 0xf8, 0x3f, 0x80, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0x42, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xb, 0xf0, 0xf, 0xe0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xfe, 0x0, 0x7f, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x3f, 0xc0, 0x3, 0xfd, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xf4, 0x0, 0xf, 0xf4, - 0x0, 0x0, 0x0, 0x3, 0xfe, 0x0, 0x0, 0x7f, - 0xe0, 0x0, 0x0, 0x1, 0xff, 0xc0, 0x0, 0x1, - 0xff, 0xe0, 0x0, 0x1, 0xff, 0xe0, 0x0, 0x0, - 0x3, 0xff, 0xfa, 0xab, 0xff, 0xf8, 0x0, 0x0, - 0x0, 0xb, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0xb, 0xff, 0xff, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x6, 0xbf, 0xe4, 0x0, 0x0, - 0x0, - - /* U+FFF75 "󿽵" */ - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x50, - 0xf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xd0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x4f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfc, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x1f, 0xdf, 0xd0, 0x3c, 0x0, 0xf, 0x0, - 0x7, 0x40, 0xfd, 0xfd, 0x3, 0xc0, 0x1, 0xf0, - 0x0, 0xb8, 0xf, 0xdf, 0xd0, 0x14, 0x0, 0x4, - 0x0, 0x1, 0x0, 0xfd, 0xfe, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x4f, 0xdf, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x0, - 0x0, 0x6f, 0xff, 0xf4, 0x0, 0x1f, 0xd0, 0x0, - 0x0, 0x7f, 0xff, 0xe0, 0x10, 0x0, 0xfd, 0x0, - 0x1, 0xbf, 0xff, 0x90, 0xb, 0x80, 0xf, 0xd0, - 0x1, 0xff, 0xff, 0x80, 0x0, 0xb4, 0x0, 0xfd, - 0x2, 0xff, 0xfe, 0x40, 0xe0, 0x0, 0x0, 0xbf, - 0xc1, 0xff, 0xfd, 0x0, 0x1f, 0x0, 0x1, 0xff, - 0xf8, 0x7f, 0xf8, 0x10, 0x0, 0x90, 0x7, 0xff, - 0xfe, 0xb, 0xf4, 0x7, 0xc0, 0x0, 0x1b, 0xff, - 0xfe, 0x0, 0xfe, 0x0, 0x78, 0x0, 0x2f, 0xff, - 0xf9, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x7f, 0xff, - 0xf4, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xdf, 0xe5, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0xfd, 0xfd, 0x1, 0x40, - 0x0, 0x40, 0x0, 0x10, 0xf, 0xdf, 0xd0, 0x3c, - 0x0, 0x1f, 0x0, 0xb, 0x80, 0xfd, 0xfd, 0x3, - 0xc0, 0x0, 0xf0, 0x0, 0x78, 0xf, 0xdf, 0xe0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfd, 0xbf, - 0x95, 0x55, 0x55, 0x55, 0x55, 0x55, 0x5f, 0xd3, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xd0, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfd -}; - - -/*--------------------- - * GLYPH DESCRIPTION - *--------------------*/ - -static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { - {.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */, - {.bitmap_index = 0, .adv_w = 640, .box_w = 24, .box_h = 24, .ofs_x = 8, .ofs_y = 8}, - {.bitmap_index = 144, .adv_w = 640, .box_w = 34, .box_h = 28, .ofs_x = 3, .ofs_y = 6}, - {.bitmap_index = 382, .adv_w = 640, .box_w = 21, .box_h = 32, .ofs_x = 8, .ofs_y = 4}, - {.bitmap_index = 550, .adv_w = 640, .box_w = 24, .box_h = 34, .ofs_x = 8, .ofs_y = 3}, - {.bitmap_index = 754, .adv_w = 640, .box_w = 36, .box_h = 38, .ofs_x = 2, .ofs_y = 1}, - {.bitmap_index = 1096, .adv_w = 640, .box_w = 34, .box_h = 28, .ofs_x = 3, .ofs_y = 6}, - {.bitmap_index = 1334, .adv_w = 640, .box_w = 34, .box_h = 34, .ofs_x = 3, .ofs_y = 3}, - {.bitmap_index = 1623, .adv_w = 640, .box_w = 20, .box_h = 11, .ofs_x = 10, .ofs_y = 15}, - {.bitmap_index = 1678, .adv_w = 640, .box_w = 34, .box_h = 28, .ofs_x = 3, .ofs_y = 6}, - {.bitmap_index = 1916, .adv_w = 640, .box_w = 34, .box_h = 34, .ofs_x = 3, .ofs_y = 3}, - {.bitmap_index = 2205, .adv_w = 640, .box_w = 30, .box_h = 30, .ofs_x = 5, .ofs_y = 5}, - {.bitmap_index = 2430, .adv_w = 640, .box_w = 20, .box_h = 30, .ofs_x = 10, .ofs_y = 5}, - {.bitmap_index = 2580, .adv_w = 640, .box_w = 28, .box_h = 30, .ofs_x = 6, .ofs_y = 5}, - {.bitmap_index = 2790, .adv_w = 640, .box_w = 28, .box_h = 28, .ofs_x = 6, .ofs_y = 6}, - {.bitmap_index = 2986, .adv_w = 640, .box_w = 22, .box_h = 22, .ofs_x = 9, .ofs_y = 9}, - {.bitmap_index = 3107, .adv_w = 640, .box_w = 30, .box_h = 20, .ofs_x = 5, .ofs_y = 10}, - {.bitmap_index = 3257, .adv_w = 640, .box_w = 8, .box_h = 28, .ofs_x = 16, .ofs_y = 6}, - {.bitmap_index = 3313, .adv_w = 640, .box_w = 28, .box_h = 28, .ofs_x = 6, .ofs_y = 6}, - {.bitmap_index = 3509, .adv_w = 640, .box_w = 38, .box_h = 29, .ofs_x = 1, .ofs_y = 5}, - {.bitmap_index = 3785, .adv_w = 640, .box_w = 26, .box_h = 20, .ofs_x = 7, .ofs_y = 10}, - {.bitmap_index = 3915, .adv_w = 640, .box_w = 31, .box_h = 28, .ofs_x = 6, .ofs_y = 6}, - {.bitmap_index = 4132, .adv_w = 640, .box_w = 30, .box_h = 28, .ofs_x = 5, .ofs_y = 6}, - {.bitmap_index = 4342, .adv_w = 640, .box_w = 28, .box_h = 34, .ofs_x = 6, .ofs_y = 3}, - {.bitmap_index = 4580, .adv_w = 640, .box_w = 34, .box_h = 32, .ofs_x = 3, .ofs_y = 5}, - {.bitmap_index = 4852, .adv_w = 640, .box_w = 34, .box_h = 34, .ofs_x = 3, .ofs_y = 3}, - {.bitmap_index = 5141, .adv_w = 640, .box_w = 34, .box_h = 34, .ofs_x = 3, .ofs_y = 3}, - {.bitmap_index = 5430, .adv_w = 640, .box_w = 26, .box_h = 34, .ofs_x = 7, .ofs_y = 3}, - {.bitmap_index = 5651, .adv_w = 640, .box_w = 28, .box_h = 30, .ofs_x = 6, .ofs_y = 5}, - {.bitmap_index = 5861, .adv_w = 640, .box_w = 34, .box_h = 28, .ofs_x = 3, .ofs_y = 6}, - {.bitmap_index = 6099, .adv_w = 640, .box_w = 40, .box_h = 39, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 6489, .adv_w = 640, .box_w = 30, .box_h = 30, .ofs_x = 5, .ofs_y = 5}, - {.bitmap_index = 6714, .adv_w = 640, .box_w = 34, .box_h = 34, .ofs_x = 3, .ofs_y = 3}, - {.bitmap_index = 7003, .adv_w = 640, .box_w = 30, .box_h = 30, .ofs_x = 5, .ofs_y = 5}, - {.bitmap_index = 7228, .adv_w = 640, .box_w = 34, .box_h = 28, .ofs_x = 3, .ofs_y = 6}, - {.bitmap_index = 7466, .adv_w = 640, .box_w = 34, .box_h = 31, .ofs_x = 3, .ofs_y = 4}, - {.bitmap_index = 7730, .adv_w = 640, .box_w = 30, .box_h = 34, .ofs_x = 5, .ofs_y = 3}, - {.bitmap_index = 7985, .adv_w = 640, .box_w = 28, .box_h = 34, .ofs_x = 6, .ofs_y = 3}, - {.bitmap_index = 8223, .adv_w = 640, .box_w = 31, .box_h = 28, .ofs_x = 6, .ofs_y = 6}, - {.bitmap_index = 8440, .adv_w = 640, .box_w = 34, .box_h = 34, .ofs_x = 3, .ofs_y = 3}, - {.bitmap_index = 8729, .adv_w = 640, .box_w = 30, .box_h = 30, .ofs_x = 5, .ofs_y = 5}, - {.bitmap_index = 8954, .adv_w = 640, .box_w = 30, .box_h = 30, .ofs_x = 5, .ofs_y = 5}, - {.bitmap_index = 9179, .adv_w = 640, .box_w = 38, .box_h = 28, .ofs_x = 1, .ofs_y = 6}, - {.bitmap_index = 9445, .adv_w = 640, .box_w = 28, .box_h = 28, .ofs_x = 6, .ofs_y = 6}, - {.bitmap_index = 9641, .adv_w = 640, .box_w = 38, .box_h = 28, .ofs_x = 1, .ofs_y = 6}, - {.bitmap_index = 9907, .adv_w = 640, .box_w = 30, .box_h = 34, .ofs_x = 5, .ofs_y = 3}, - {.bitmap_index = 10162, .adv_w = 640, .box_w = 34, .box_h = 34, .ofs_x = 3, .ofs_y = 3}, - {.bitmap_index = 10451, .adv_w = 640, .box_w = 34, .box_h = 34, .ofs_x = 3, .ofs_y = 3} -}; - -/*--------------------- - * CHARACTER MAPPING - *--------------------*/ - -static const uint16_t unicode_list_0[] = { - 0x0, 0x14, 0x62, 0x9b, 0x148, 0x182, 0x1ca, 0x1d1, - 0x1e1, 0x26a, 0x2af, 0x2c0, 0x418, 0x47e, 0x488, 0x48d, - 0x48f, 0x490, 0x4f9, 0x523, 0x600, 0x62b, 0x757, 0x76a, - 0x773, 0x7b8, 0x7ca, 0x7e9, 0x874, 0x8af, 0x8b2, 0x8c2, - 0x991, 0xa49, 0xa52, 0xa87, 0xad7, 0xdfb, 0xe05, 0xe35, - 0xea1, 0xee3, 0xf4b, 0x1017, 0x15db, 0x1782 -}; - -/*Collect the unicode lists and glyph_id offsets*/ -static const lv_font_fmt_txt_cmap_t cmaps[] = -{ - { - .range_start = 57669, .range_length = 6019, .glyph_id_start = 1, - .unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 46, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY - }, - { - .range_start = 1048437, .range_length = 1, .glyph_id_start = 47, - .unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY - } -}; - - - -/*-------------------- - * ALL CUSTOM DATA - *--------------------*/ - -#if LVGL_VERSION_MAJOR == 8 -/*Store all the custom data of the font*/ -static lv_font_fmt_txt_glyph_cache_t cache; -#endif - -#if LVGL_VERSION_MAJOR >= 8 -static const lv_font_fmt_txt_dsc_t font_dsc = { -#else -static lv_font_fmt_txt_dsc_t font_dsc = { -#endif - .glyph_bitmap = glyph_bitmap, - .glyph_dsc = glyph_dsc, - .cmaps = cmaps, - .kern_dsc = NULL, - .kern_scale = 0, - .cmap_num = 2, - .bpp = 2, - .kern_classes = 0, - .bitmap_format = 0, -#if LVGL_VERSION_MAJOR == 8 - .cache = &cache -#endif -}; - - - -/*----------------- - * PUBLIC FONT - *----------------*/ - -/*Initialize a public general font descriptor*/ -#if LVGL_VERSION_MAJOR >= 8 -const lv_font_t material_symbols_shared_40 = { -#else -lv_font_t material_symbols_shared_40 = { -#endif - .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ - .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ - .line_height = 39, /*The maximum line height required by the font*/ - .base_line = -1, /*Baseline measured from the bottom of the line*/ -#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) - .subpx = LV_FONT_SUBPX_NONE, -#endif -#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 - .underline_position = 0, - .underline_thickness = 0, -#endif - .dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ -#if LV_VERSION_CHECK(8, 2, 0) || LVGL_VERSION_MAJOR >= 9 - .fallback = NULL, -#endif - .user_data = NULL, -}; - - - -#endif /*#if MATERIAL_SYMBOLS_SHARED_40*/ - diff --git a/Modules/lvgl-module/source-fonts/material_symbols_shared_48.c b/Modules/lvgl-module/source-fonts/material_symbols_shared_48.c deleted file mode 100644 index 2e187cea4..000000000 --- a/Modules/lvgl-module/source-fonts/material_symbols_shared_48.c +++ /dev/null @@ -1,2130 +0,0 @@ -/******************************************************************************* - * Size: 48 px - * Bpp: 2 - * Opts: --no-compress --no-prefilter --bpp 2 --size 48 --font MaterialSymbolsRounded.ttf -r 0xE145,0xE5C3,0xE770,0xEF40,0xEBCC,0xEFE6,0xEF4A,0xE5CD,0xF15C,0xE668,0xE92E,0xE326,0xEB97,0xE745,0xEC1C,0xE2C7,0xF720,0xF090,0xE8AF,0xE30F,0xE8FD,0xE9F4,0xE3F4,0xE316,0xE90F,0xEA07,0xE9B9,0xE159,0xE5D2,0xE28D,0xE5D4,0xE405,0xE89C,0xF8C7,0xE5D5,0xEF7A,0xE8B8,0xE9F7,0xE55D,0xF028,0xE1E0,0xE63E,0xE1A7,0xEB8E,0xEAD6,0xE3AF,0xFFF75 --format lvgl -o source-fonts/material_symbols_shared_48.c --force-fast-kern-format - ******************************************************************************/ - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -#ifndef MATERIAL_SYMBOLS_SHARED_48 -#define MATERIAL_SYMBOLS_SHARED_48 1 -#endif - -#if MATERIAL_SYMBOLS_SHARED_48 - -/*----------------- - * BITMAPS - *----------------*/ - -/*Store the image of the glyphs*/ -static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { - /* U+E145 "" */ - 0x0, 0x0, 0x0, 0x7d, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0x0, 0x0, 0x0, 0x7f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x7d, 0x0, 0x0, 0x0, - - /* U+E159 "" */ - 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfc, 0xbf, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x2, 0xff, 0xff, 0xf4, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x1f, 0xff, 0xff, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, - 0xe0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0xff, - 0xff, 0x7f, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x7f, - 0xfd, 0xff, 0xff, 0xb, 0xff, 0x80, 0x0, 0x0, - 0x2, 0xff, 0xe0, 0xff, 0xff, 0x0, 0xff, 0xf4, - 0x0, 0x0, 0x1f, 0xff, 0x0, 0xff, 0xff, 0x0, - 0x1f, 0xff, 0x0, 0x0, 0xff, 0xf4, 0x0, 0xff, - 0xff, 0x0, 0x2, 0xff, 0xe0, 0xb, 0xff, 0x80, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x7f, 0xfd, 0x7f, - 0xfd, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xb, - 0xff, 0xff, 0xe0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x1f, 0xf4, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x2, 0x80, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xb, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, - - /* U+E1A7 "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x1f, 0x40, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xf8, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0x80, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xf8, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0xff, 0x80, 0x0, 0x0, 0x0, - 0xf, 0xff, 0xf8, 0x0, 0xbd, 0x0, 0x3, 0xff, - 0xff, 0x80, 0x3f, 0xd0, 0x0, 0xff, 0x3f, 0xf8, - 0xf, 0xfd, 0x0, 0x3f, 0xc3, 0xff, 0x81, 0xff, - 0xd0, 0xf, 0xf0, 0x3f, 0xf4, 0x1f, 0xfd, 0x3, - 0xfc, 0x7, 0xfe, 0x1, 0xff, 0xd0, 0xff, 0x7, - 0xff, 0x0, 0x1f, 0xfd, 0x3f, 0xc7, 0xff, 0x40, - 0x1, 0xff, 0xdf, 0xf7, 0xff, 0x40, 0x0, 0x1f, - 0xff, 0xff, 0xff, 0x40, 0x0, 0x1, 0xff, 0xff, - 0xff, 0x40, 0x0, 0x0, 0x1f, 0xff, 0xff, 0x40, - 0x0, 0x0, 0x1, 0xff, 0xff, 0x40, 0x0, 0x0, - 0x0, 0x1f, 0xff, 0x40, 0x0, 0x0, 0x0, 0x7, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x7, 0xff, 0xfd, - 0x0, 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, - 0x0, 0x7, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x7, - 0xff, 0xff, 0xff, 0xd0, 0x0, 0x7, 0xff, 0x7f, - 0xdf, 0xfd, 0x0, 0x7, 0xff, 0x4f, 0xf1, 0xff, - 0xd0, 0x7, 0xff, 0x43, 0xfc, 0x1f, 0xfc, 0x7, - 0xff, 0x40, 0xff, 0x1, 0xff, 0x87, 0xff, 0x40, - 0x3f, 0xc0, 0xff, 0xd3, 0xff, 0x40, 0xf, 0xf0, - 0xff, 0xd0, 0xff, 0x40, 0x3, 0xfc, 0xff, 0xd0, - 0x2f, 0x40, 0x0, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x3f, 0xff, 0xd0, 0x0, 0x0, 0x0, 0xf, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xd0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0x7, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, - - /* U+E1E0 "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3c, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, - 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xd0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x3f, 0xff, 0xfc, 0x0, - 0x0, 0x0, 0x0, 0x3f, 0xff, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0x0, 0x0, 0x0, 0xb, 0xe0, 0x0, 0xff, - 0x0, 0xff, 0xff, 0x3f, 0xfc, 0x0, 0xff, 0x0, - 0xff, 0xff, 0xbf, 0xfe, 0x0, 0xff, 0x0, 0xff, - 0xff, 0xff, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, - 0xff, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0xbf, - 0xfe, 0x0, 0xff, 0x0, 0xff, 0xff, 0x3f, 0xfc, - 0x0, 0xff, 0x0, 0xff, 0xff, 0xf, 0xf0, 0x0, - 0xff, 0x0, 0xff, 0xff, 0xf, 0xf0, 0x0, 0xff, - 0x0, 0xf, 0xf0, 0xf, 0xf0, 0x0, 0xff, 0x0, - 0xf, 0xf0, 0xf, 0xf0, 0x0, 0xff, 0x0, 0xf, - 0xf0, 0xf, 0xf0, 0x0, 0xff, 0x0, 0xf, 0xf0, - 0xf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xb, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x3, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0, 0xbf, 0xff, - 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, - 0xb, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0xe0, - 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xc0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xbe, 0x0, 0x0, 0x0, - - /* U+E28D "" */ - 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0xff, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0x82, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x0, 0x0, - 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfc, 0x0, 0x0, 0xbf, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, - 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0x0, 0x0, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x1, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x40, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x80, 0x3, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0x3, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0xc0, 0x7, 0xf8, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x2f, 0xd0, 0xb, 0xf4, - 0x7, 0xd0, 0x0, 0x7d, 0x0, 0x7, 0xd0, 0x1f, - 0xe0, 0xf, 0xf0, 0xf, 0xf0, 0x0, 0xff, 0x0, - 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, - 0x0, 0xff, 0x0, 0xf, 0xf0, 0xf, 0xf0, 0x1f, - 0xe0, 0xf, 0xf0, 0x0, 0xff, 0x0, 0xf, 0xf0, - 0xb, 0xf4, 0x2f, 0xd0, 0xf, 0xf0, 0x0, 0xff, - 0x0, 0xf, 0xf0, 0x7, 0xf8, 0x3f, 0xc0, 0xf, - 0xf0, 0x0, 0xff, 0x0, 0xf, 0xf0, 0x3, 0xfc, - 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xf, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xf0, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x80, - - /* U+E2C7 "" */ - 0xb, 0xff, 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0xff, 0xff, 0xff, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xbf, 0xff, 0xff, 0xff, - 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, - 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0x0, 0x0, 0x3, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xe0, 0xff, 0x0, 0x0, 0x0, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfc, 0xff, 0x0, 0x0, 0x0, - 0x3f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x0, - 0x0, 0x0, 0xf, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xb, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, - - /* U+E30F "" */ - 0x0, 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xf0, 0xf, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf0, 0xf, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xf0, 0xf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xf0, 0xf, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xf0, 0xf, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf0, 0xf, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xfc, 0x3f, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2, 0xff, 0xff, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0xfd, 0x0, - 0x2f, 0xf4, 0x0, 0x7f, 0xff, 0xfd, 0xff, 0xff, - 0xff, 0x80, 0x7, 0xd0, 0x1, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xe0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x0, 0x0, - 0x1f, 0xff, 0xff, 0xff, 0xff, 0x0, 0xf, 0xfd, - 0x0, 0x0, 0x7f, 0xf0, 0x0, 0xff, 0xff, 0x0, - 0x3, 0xff, 0x0, 0x0, 0xff, 0xc0, 0x0, 0xff, - 0xff, 0x0, 0x3, 0xff, 0x0, 0x0, 0xff, 0xc0, - 0x0, 0xff, 0xff, 0x0, 0xf, 0xfd, 0x0, 0x0, - 0x7f, 0xf0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xf4, - 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0xb, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x40, 0x7, 0xd0, 0x2, 0xff, - 0xff, 0xff, 0x7f, 0xff, 0xfd, 0x0, 0x1f, 0xf8, - 0x0, 0x7f, 0xff, 0xfd, 0x0, 0x0, 0x0, 0x0, - 0x7f, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x1, 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfc, 0x3f, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xf0, 0xf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xf0, 0xf, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xf0, 0xf, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf0, 0xf, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xf0, 0xf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xf0, 0xf, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, 0x0, - - /* U+E316 "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x7, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xf8, - 0x0, 0x0, 0x0, 0x0, 0x7f, 0xfe, 0x0, 0x0, - 0x0, 0x1, 0xff, 0xff, 0x80, 0x0, 0x0, 0x7, - 0xff, 0xff, 0xe0, 0x0, 0x0, 0x1f, 0xfc, 0x3f, - 0xf8, 0x0, 0x0, 0x7f, 0xf0, 0xf, 0xfe, 0x0, - 0x1, 0xff, 0xc0, 0x3, 0xff, 0x80, 0x7, 0xff, - 0x0, 0x0, 0xff, 0xe0, 0x1f, 0xfc, 0x0, 0x0, - 0x3f, 0xf4, 0x3f, 0xf0, 0x0, 0x0, 0xf, 0xfc, - 0x3f, 0xc0, 0x0, 0x0, 0x3, 0xfc, 0x1f, 0x0, - 0x0, 0x0, 0x0, 0xf4, - - /* U+E326 "" */ - 0x0, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xd0, 0x3, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf0, 0xb, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd0, - 0xf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, - 0xff, 0xf8, 0xf, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0xbf, 0xff, 0xff, 0xfe, 0xf, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xf, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, - 0xf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, - 0x0, 0xff, 0xf, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0x0, 0x0, 0xff, 0xf, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0x3, 0xc0, 0xff, 0xf, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0x7, 0xd0, 0xff, - 0xf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x3, - 0xc0, 0xff, 0xf, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0x0, 0x0, 0xff, 0xf, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0x0, 0x0, 0xff, 0xf, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0xff, - 0xf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, - 0x0, 0xff, 0xf, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0x0, 0x0, 0xff, 0xf, 0xff, 0xff, 0xff, - 0xfd, 0x0, 0xff, 0x0, 0x0, 0xff, 0xb, 0xff, - 0xff, 0xff, 0xff, 0x0, 0xff, 0x0, 0x0, 0xff, - 0x3, 0xff, 0xff, 0xff, 0xff, 0x0, 0xff, 0x0, - 0x0, 0xff, 0x0, 0xbf, 0xff, 0xff, 0xfd, 0x0, - 0xff, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0x0, 0x0, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0xff, - 0x7f, 0xff, 0xff, 0xff, 0xfd, 0x0, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x0, 0xbf, 0xff, 0xff, 0xfe, 0x7f, 0xff, - 0xff, 0xff, 0xfd, 0x0, 0x2f, 0xff, 0xff, 0xf8, - - /* U+E3AF "" */ - 0x0, 0x0, 0x0, 0x1, 0xbf, 0xfe, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xff, 0xff, - 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, - 0xff, 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x0, - 0x0, 0x2, 0xff, 0xfe, 0x40, 0xf, 0xff, 0xff, - 0x80, 0x0, 0x0, 0xb, 0xff, 0xd0, 0x0, 0x2f, - 0x7, 0xff, 0xe0, 0x0, 0x0, 0x2f, 0xfe, 0x0, - 0x0, 0x3c, 0x0, 0x7f, 0xf8, 0x0, 0x0, 0xbf, - 0xf4, 0x0, 0x0, 0xb8, 0x0, 0xf, 0xfe, 0x0, - 0x1, 0xff, 0xc0, 0x0, 0x1, 0xf0, 0x0, 0x3, - 0xff, 0x40, 0x3, 0xff, 0xd0, 0x0, 0x3, 0xd0, - 0x0, 0x0, 0xff, 0xc0, 0xb, 0xfe, 0xf0, 0x0, - 0x7, 0xc0, 0x0, 0x0, 0x3f, 0xe0, 0xf, 0xf8, - 0xf4, 0x0, 0xf, 0x40, 0x0, 0x0, 0x1f, 0xf0, - 0x2f, 0xf0, 0x7c, 0x0, 0x2e, 0x0, 0x0, 0x0, - 0xf, 0xf8, 0x3f, 0xd0, 0x2e, 0x0, 0x3f, 0x0, - 0x0, 0x0, 0x7, 0xfc, 0x3f, 0xc0, 0xf, 0x0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0x80, - 0xb, 0xc1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0xbf, 0x40, 0x3, 0xd3, 0xff, 0xff, 0xe0, 0x0, - 0x1, 0xfe, 0xff, 0x0, 0x1, 0xff, 0xff, 0xff, - 0xd0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, - 0xff, 0xff, 0xf0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x3f, 0xff, 0xff, 0xf8, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xfc, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0xf, 0xff, 0xff, - 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x7, - 0xff, 0xff, 0xff, 0x40, 0x0, 0xff, 0xbf, 0x40, - 0x0, 0xb, 0xff, 0xff, 0xc7, 0xc0, 0x1, 0xfe, - 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x43, 0xe0, - 0x2, 0xfd, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x0, 0xf0, 0x3, 0xfc, 0x3f, 0xd0, 0x0, 0x0, - 0x0, 0xfc, 0x0, 0xb8, 0x7, 0xfc, 0x2f, 0xf0, - 0x0, 0x0, 0x0, 0xf8, 0x0, 0x3d, 0xf, 0xf8, - 0xf, 0xf4, 0x0, 0x0, 0x1, 0xf0, 0x0, 0x1f, - 0x2f, 0xf0, 0xb, 0xfc, 0x0, 0x0, 0x3, 0xd0, - 0x0, 0xf, 0xbf, 0xe0, 0x3, 0xff, 0x0, 0x0, - 0x7, 0xc0, 0x0, 0x7, 0xff, 0xc0, 0x1, 0xff, - 0xc0, 0x0, 0xf, 0x40, 0x0, 0x3, 0xff, 0x40, - 0x0, 0xbf, 0xf0, 0x0, 0x2e, 0x0, 0x0, 0x1f, - 0xfe, 0x0, 0x0, 0x2f, 0xfd, 0x0, 0x3c, 0x0, - 0x0, 0xbf, 0xf8, 0x0, 0x0, 0xb, 0xff, 0xd0, - 0xf8, 0x0, 0x7, 0xff, 0xe0, 0x0, 0x0, 0x2, - 0xff, 0xfe, 0xf0, 0x1, 0xbf, 0xff, 0x80, 0x0, - 0x0, 0x0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0xff, 0xff, - 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, - 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x1, 0xbf, 0xfe, 0x40, 0x0, 0x0, 0x0, - - /* U+E3F4 "" */ - 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xe0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfc, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x4, - 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x2e, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x7f, 0x40, 0x0, 0xff, 0xff, 0x0, 0x3, - 0xc0, 0x0, 0xff, 0xc0, 0x0, 0xff, 0xff, 0x0, - 0xf, 0xf0, 0x3, 0xff, 0xf0, 0x0, 0xff, 0xff, - 0x0, 0x2f, 0xf8, 0xb, 0xff, 0xf8, 0x0, 0xff, - 0xff, 0x0, 0x7f, 0xfd, 0x1f, 0xff, 0xfd, 0x0, - 0xff, 0xff, 0x0, 0xff, 0xff, 0x7f, 0xff, 0xff, - 0x0, 0xff, 0xff, 0x3, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xc0, 0xff, 0xff, 0x3, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xc0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfc, 0xb, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xe0, - - /* U+E405 "" */ - 0x0, 0x0, 0x0, 0x7f, 0xff, 0xfd, 0x0, 0x0, - 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0xff, - 0xff, 0xff, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, - 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, - 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0xff, - 0xff, 0xff, 0x0, 0x0, 0x0, 0xff, 0xff, 0xfd, - 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, - 0x0, 0x2f, 0xf8, 0xff, 0x0, 0x0, 0x2, 0xff, - 0xff, 0xff, 0x0, 0x0, 0xb, 0xff, 0xff, 0xff, - 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff, 0x0, 0x0, - 0x3f, 0xff, 0xff, 0xff, 0x0, 0x0, 0xbf, 0xff, - 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, - 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, - 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, - 0xff, 0xff, 0x0, 0x0, 0xbf, 0xff, 0xff, 0xfe, - 0x0, 0x0, 0x3f, 0xff, 0xff, 0xfc, 0x0, 0x0, - 0x2f, 0xff, 0xff, 0xf8, 0x0, 0x0, 0xb, 0xff, - 0xff, 0xe0, 0x0, 0x0, 0x2, 0xff, 0xff, 0x80, - 0x0, 0x0, 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x0, - - /* U+E55D "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x1f, 0xf4, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3f, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7f, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x2, 0xfe, 0xbf, 0x80, 0x0, 0x0, - 0x0, 0x0, 0x3, 0xfc, 0x3f, 0xc0, 0x0, 0x0, - 0x0, 0x0, 0xb, 0xfc, 0x3f, 0xe0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xf4, 0x1f, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x1f, 0xf0, 0xf, 0xf4, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0xd0, 0x7, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0x7f, 0xc0, 0x3, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0xff, 0x80, 0x2, 0xff, 0x0, 0x0, - 0x0, 0x0, 0xff, 0x0, 0x0, 0xff, 0x0, 0x0, - 0x0, 0x2, 0xfe, 0x0, 0x0, 0xbf, 0x80, 0x0, - 0x0, 0x3, 0xfc, 0x0, 0x0, 0x3f, 0xc0, 0x0, - 0x0, 0xb, 0xfc, 0x0, 0x0, 0x3f, 0xe0, 0x0, - 0x0, 0xf, 0xf4, 0x0, 0x0, 0x1f, 0xf0, 0x0, - 0x0, 0x1f, 0xf0, 0x0, 0x0, 0xf, 0xf4, 0x0, - 0x0, 0x3f, 0xd0, 0x0, 0x0, 0x7, 0xfc, 0x0, - 0x0, 0x7f, 0xc0, 0x0, 0x0, 0x3, 0xfd, 0x0, - 0x0, 0xff, 0x80, 0x0, 0x0, 0x2, 0xff, 0x0, - 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, - 0x2, 0xfe, 0x0, 0x1f, 0xf4, 0x0, 0xbf, 0x80, - 0x3, 0xfc, 0x1, 0xff, 0xff, 0x40, 0x3f, 0xc0, - 0xb, 0xfc, 0x2f, 0xff, 0xff, 0xf8, 0x3f, 0xe0, - 0xf, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xef, 0xf0, - 0x1f, 0xff, 0xff, 0xf8, 0x2f, 0xff, 0xff, 0xf4, - 0x3f, 0xff, 0xff, 0x40, 0x1, 0xff, 0xff, 0xfc, - 0x7f, 0xff, 0xf4, 0x0, 0x0, 0x1f, 0xff, 0xfd, - 0xbf, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xfe, - 0x7f, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xfd, - 0x19, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x64, - - /* U+E5C3 "" */ - 0xb, 0xe0, 0x0, 0xb, 0xe0, 0x0, 0xb, 0xe0, - 0x3f, 0xfc, 0x0, 0x3f, 0xfc, 0x0, 0x3f, 0xfc, - 0xbf, 0xfe, 0x0, 0xbf, 0xfe, 0x0, 0xbf, 0xfe, - 0xff, 0xff, 0x0, 0xff, 0xff, 0x0, 0xff, 0xff, - 0xff, 0xff, 0x0, 0xff, 0xff, 0x0, 0xff, 0xff, - 0xbf, 0xfe, 0x0, 0xbf, 0xfe, 0x0, 0xbf, 0xfe, - 0x3f, 0xfc, 0x0, 0x3f, 0xfc, 0x0, 0x3f, 0xfc, - 0xb, 0xe0, 0x0, 0xb, 0xe0, 0x0, 0xb, 0xe0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xb, 0xe0, 0x0, 0xb, 0xe0, 0x0, 0xb, 0xe0, - 0x3f, 0xfc, 0x0, 0x3f, 0xfc, 0x0, 0x3f, 0xfc, - 0xbf, 0xfe, 0x0, 0xbf, 0xfe, 0x0, 0xbf, 0xfe, - 0xff, 0xff, 0x0, 0xff, 0xff, 0x0, 0xff, 0xff, - 0xff, 0xff, 0x0, 0xff, 0xff, 0x0, 0xff, 0xff, - 0xbf, 0xfe, 0x0, 0xbf, 0xfe, 0x0, 0xbf, 0xfe, - 0x3f, 0xfc, 0x0, 0x3f, 0xfc, 0x0, 0x3f, 0xfc, - 0xb, 0xe0, 0x0, 0xb, 0xe0, 0x0, 0xb, 0xe0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xb, 0xe0, 0x0, 0xb, 0xe0, 0x0, 0xb, 0xe0, - 0x3f, 0xfc, 0x0, 0x3f, 0xfc, 0x0, 0x3f, 0xfc, - 0xbf, 0xfe, 0x0, 0xbf, 0xfe, 0x0, 0xbf, 0xfe, - 0xff, 0xff, 0x0, 0xff, 0xff, 0x0, 0xff, 0xff, - 0xff, 0xff, 0x0, 0xff, 0xff, 0x0, 0xff, 0xff, - 0xbf, 0xfe, 0x0, 0xbf, 0xfe, 0x0, 0xbf, 0xfe, - 0x3f, 0xfc, 0x0, 0x3f, 0xfc, 0x0, 0x3f, 0xfc, - 0xb, 0xe0, 0x0, 0xb, 0xe0, 0x0, 0xb, 0xe0, - - /* U+E5CD "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, - 0x40, 0x0, 0x0, 0x0, 0x1, 0xf8, 0x3f, 0xd0, - 0x0, 0x0, 0x0, 0x7, 0xfc, 0x3f, 0xf4, 0x0, - 0x0, 0x0, 0x1f, 0xfc, 0x1f, 0xfd, 0x0, 0x0, - 0x0, 0x7f, 0xf4, 0x7, 0xff, 0x40, 0x0, 0x1, - 0xff, 0xd0, 0x1, 0xff, 0xd0, 0x0, 0x7, 0xff, - 0x40, 0x0, 0x7f, 0xf4, 0x0, 0x1f, 0xfd, 0x0, - 0x0, 0x1f, 0xfd, 0x0, 0x7f, 0xf4, 0x0, 0x0, - 0x7, 0xff, 0x41, 0xff, 0xd0, 0x0, 0x0, 0x1, - 0xff, 0xd7, 0xff, 0x40, 0x0, 0x0, 0x0, 0x7f, - 0xff, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, - 0xf4, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, 0xd0, - 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0x1f, 0xff, 0xf4, 0x0, 0x0, - 0x0, 0x0, 0x7f, 0xff, 0xfd, 0x0, 0x0, 0x0, - 0x1, 0xff, 0xd7, 0xff, 0x40, 0x0, 0x0, 0x7, - 0xff, 0x41, 0xff, 0xd0, 0x0, 0x0, 0x1f, 0xfd, - 0x0, 0x7f, 0xf4, 0x0, 0x0, 0x7f, 0xf4, 0x0, - 0x1f, 0xfd, 0x0, 0x1, 0xff, 0xd0, 0x0, 0x7, - 0xff, 0x40, 0x7, 0xff, 0x40, 0x0, 0x1, 0xff, - 0xd0, 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x7f, 0xf4, - 0x3f, 0xf4, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x3f, - 0xd0, 0x0, 0x0, 0x0, 0x7, 0xfc, 0x2f, 0x40, - 0x0, 0x0, 0x0, 0x1, 0xf8, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, - - /* U+E5D2 "" */ - 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, - - /* U+E5D4 "" */ - 0xb, 0xe0, 0x3f, 0xfc, 0xbf, 0xfe, 0xff, 0xff, - 0xff, 0xff, 0xbf, 0xfe, 0x3f, 0xfc, 0xb, 0xe0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xb, 0xe0, 0x3f, 0xfc, 0xbf, 0xfe, 0xff, 0xff, - 0xff, 0xff, 0xbf, 0xfe, 0x3f, 0xfc, 0xb, 0xe0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xb, 0xe0, 0x3f, 0xfc, 0xbf, 0xfe, 0xff, 0xff, - 0xff, 0xff, 0xbf, 0xfe, 0x3f, 0xfc, 0xb, 0xe0, - - /* U+E5D5 "" */ - 0x0, 0x0, 0x1, 0xbf, 0xfe, 0x40, 0x0, 0x7d, - 0x0, 0x0, 0x2f, 0xff, 0xff, 0xf8, 0x0, 0xff, - 0x0, 0x2, 0xff, 0xff, 0xff, 0xff, 0x80, 0xff, - 0x0, 0xf, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, - 0x0, 0x3f, 0xff, 0x90, 0x6, 0xff, 0xfc, 0xff, - 0x0, 0xff, 0xf4, 0x0, 0x0, 0x1f, 0xff, 0xff, - 0x3, 0xff, 0x80, 0x0, 0x0, 0x2, 0xff, 0xff, - 0xb, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xff, - 0xf, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, - 0x2f, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, - 0x3f, 0xd0, 0x0, 0x0, 0x7, 0xff, 0xff, 0xff, - 0x7f, 0xc0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xff, - 0xbf, 0x80, 0x0, 0x0, 0xf, 0xff, 0xff, 0xff, - 0xff, 0x40, 0x0, 0x0, 0x7, 0xff, 0xff, 0xfd, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xbf, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x7f, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, - 0x3f, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xf0, - 0x2f, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf4, - 0xf, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xf0, - 0xb, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xe0, - 0x3, 0xff, 0x80, 0x0, 0x0, 0x2, 0xff, 0xc0, - 0x0, 0xff, 0xf4, 0x0, 0x0, 0x1f, 0xff, 0x0, - 0x0, 0x3f, 0xff, 0x90, 0x6, 0xff, 0xfc, 0x0, - 0x0, 0xf, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0, - 0x0, 0x2, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0, - 0x0, 0x0, 0x2f, 0xff, 0xff, 0xf8, 0x0, 0x0, - 0x0, 0x0, 0x1, 0xbf, 0xfe, 0x40, 0x0, 0x0, - - /* U+E63E "" */ - 0x0, 0x0, 0x0, 0x0, 0x6b, 0xff, 0xfe, 0x90, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0xff, - 0xff, 0xff, 0xff, 0xf9, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x40, 0x0, 0x0, 0xf, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0x0, 0x0, 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0x0, 0x3, 0xff, 0xff, - 0xff, 0xe4, 0x0, 0x1, 0xbf, 0xff, 0xff, 0xfc, - 0x1, 0xff, 0xff, 0xfe, 0x40, 0x0, 0x0, 0x0, - 0x1b, 0xff, 0xff, 0xf4, 0x3f, 0xff, 0xfd, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, 0xff, 0xcb, - 0xff, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x7, 0xff, 0xfe, 0xbf, 0xfe, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0xe7, 0xff, - 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x1f, 0xfd, 0x1f, 0x80, 0x0, 0x0, 0x1a, 0xff, - 0xfa, 0x40, 0x0, 0x0, 0x2f, 0x40, 0x0, 0x0, - 0x0, 0x2f, 0xff, 0xff, 0xff, 0x80, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0xff, 0xff, - 0xff, 0x90, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0, 0x0, - 0x0, 0x0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0xff, 0xf9, 0x0, 0x6, 0xff, 0xff, - 0xc0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xf4, 0x0, - 0x0, 0x1, 0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, - 0x1f, 0xf4, 0x0, 0x0, 0x0, 0x1, 0xff, 0x40, - 0x0, 0x0, 0x0, 0x0, 0x14, 0x0, 0x0, 0x0, - 0x0, 0x1, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x7f, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, 0x80, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, - 0xff, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0xe0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xfe, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x7f, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0xf8, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x7, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, - - /* U+E668 "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfc, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xf8, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xe0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0x80, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfe, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xf8, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xe0, 0x0, - 0x4, 0x0, 0x0, 0x0, 0x3, 0xff, 0x80, 0x0, - 0x3f, 0x40, 0x0, 0x0, 0xf, 0xfe, 0x0, 0x0, - 0x7f, 0xd0, 0x0, 0x0, 0x3f, 0xf8, 0x0, 0x0, - 0x3f, 0xf4, 0x0, 0x0, 0xff, 0xe0, 0x0, 0x0, - 0x1f, 0xfd, 0x0, 0x3, 0xff, 0x80, 0x0, 0x0, - 0x7, 0xff, 0x40, 0xf, 0xfe, 0x0, 0x0, 0x0, - 0x1, 0xff, 0xd0, 0x3f, 0xf8, 0x0, 0x0, 0x0, - 0x0, 0x7f, 0xf4, 0xff, 0xe0, 0x0, 0x0, 0x0, - 0x0, 0x1f, 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, - 0x0, 0x7, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x1, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7f, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x1f, 0x80, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - - /* U+E745 "" */ - 0x7f, 0xff, 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0, - 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, - 0x0, 0x0, 0x0, 0x7f, 0xff, 0xff, 0xff, 0xff, - 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x7f, 0xff, 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0, - 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, - 0x0, 0x0, 0x0, 0x7f, 0xff, 0xff, 0xff, 0xff, - 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0x80, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xf0, - 0x7f, 0xff, 0xff, 0xd0, 0x0, 0x0, 0x2, 0xff, - 0xfc, 0xff, 0xff, 0xff, 0xf0, 0x0, 0x0, 0xb, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xf0, 0x0, 0x0, - 0x2f, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xd0, 0x0, - 0x0, 0xbf, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x2, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xb, 0xf9, 0xff, 0xf8, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xe0, 0x7f, 0xe0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xbf, 0x80, 0xbf, 0x80, - 0x0, 0x0, 0x0, 0x0, 0x2, 0xfe, 0x2, 0xfe, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xf8, 0xb, - 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xe0, - 0x2f, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xc0, 0xbf, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xc2, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xff, 0xe0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7, 0xff, 0x80, 0x0, 0x0, - - /* U+E770 "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xc0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xf4, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, - 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xff, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x2f, 0xf5, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x7f, 0xe0, 0x3f, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xc0, 0xb, 0xff, 0xff, 0xe0, - 0x0, 0x0, 0x3, 0xff, 0x0, 0x2, 0xff, 0xff, - 0xfc, 0x7d, 0x0, 0x7, 0xfd, 0x0, 0x0, 0x7f, - 0xff, 0xfe, 0xff, 0x80, 0xf, 0xf8, 0x0, 0x0, - 0xf, 0xff, 0xff, 0xff, 0xf0, 0x3f, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0xfd, 0xbf, 0xd0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, - 0x80, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, - 0x7f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0xf, 0xf4, 0x0, 0x18, 0x0, 0x0, 0x0, - 0xff, 0xff, 0x2, 0xe0, 0x0, 0x3f, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x40, 0x0, 0xff, 0xd0, - 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x2, 0xff, - 0xf4, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x7, - 0xff, 0xfe, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, - 0xf, 0xff, 0xff, 0xc0, 0x0, 0xff, 0xff, 0x40, - 0x0, 0x2f, 0xff, 0xff, 0xf4, 0x0, 0xff, 0xff, - 0xe0, 0x0, 0x7f, 0xff, 0xff, 0xfe, 0x0, 0xff, - 0xff, 0xfc, 0x0, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xff, 0xff, 0xff, 0x3, 0xff, 0xff, 0xff, 0xff, - 0xf4, 0xff, 0xff, 0xff, 0xdb, 0xff, 0xff, 0xff, - 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, - - /* U+E89C "" */ - 0xb, 0xff, 0xff, 0xff, 0xff, 0x40, 0x0, 0x0, - 0x3f, 0xff, 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0xbf, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x0, 0x0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, - 0xff, 0x0, 0x0, 0x0, 0xf, 0xff, 0x80, 0x0, - 0xff, 0x0, 0x0, 0x0, 0xf, 0xff, 0xe0, 0x0, - 0xff, 0x0, 0x0, 0x0, 0xf, 0xff, 0xf8, 0x0, - 0xff, 0x0, 0x0, 0x0, 0xf, 0xff, 0xfe, 0x0, - 0xff, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0x80, - 0xff, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xe0, - 0xff, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xf4, - 0xff, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xfd, - 0xff, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x7, 0xff, 0xff, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x7, 0xd0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x7f, 0xff, 0xff, 0xfd, 0x0, 0xff, - 0xff, 0x0, 0xff, 0xff, 0xff, 0xff, 0x0, 0xff, - 0xff, 0x0, 0xff, 0xff, 0xff, 0xff, 0x0, 0xff, - 0xff, 0x0, 0x7f, 0xff, 0xff, 0xfd, 0x0, 0xff, - 0xff, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x7, 0xd0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, - 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, - - /* U+E8AF "" */ - 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, - 0x0, 0x0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xc0, 0x0, 0x0, 0xbf, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xe0, 0x0, 0x0, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0, 0x0, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf0, - 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xf0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf0, - 0xf, 0xe0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xf0, 0xf, 0xfc, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xf0, 0xf, 0xfe, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xf0, 0xf, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf0, - 0xf, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xf0, 0xf, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xf0, 0xf, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xf0, 0xf, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf0, - 0xf, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xf0, 0xf, 0xff, 0xff, 0xf, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf0, 0xf, 0xff, 0xff, 0x3f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xf, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0xf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfe, 0x0, 0xf, 0xff, 0xff, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xf4, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3f, 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x1, 0xff, 0xff, 0x7d, 0x0, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x0, 0x0, 0xbf, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x3f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, - 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xbf, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x2f, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x7d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, - - /* U+E8B8 "" */ - 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xff, - 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, - 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xf0, 0xf, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf0, 0xf, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x1e, 0x40, 0x2f, - 0xe0, 0xb, 0xf8, 0x1, 0xb4, 0x0, 0x0, 0xff, - 0xf9, 0xff, 0xe0, 0xb, 0xff, 0x6f, 0xff, 0x0, - 0x2, 0xff, 0xff, 0xff, 0xd0, 0x7, 0xff, 0xff, - 0xff, 0x80, 0x3, 0xff, 0xff, 0xff, 0x80, 0x2, - 0xff, 0xff, 0xff, 0xc0, 0xb, 0xfd, 0xff, 0xf4, - 0x0, 0x0, 0x1f, 0xff, 0x7f, 0xe0, 0xf, 0xf4, - 0x1b, 0xc0, 0x0, 0x0, 0x3, 0xe4, 0x1f, 0xf0, - 0x2f, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xf8, 0x3f, 0xd0, 0x0, 0x0, 0x2f, 0xf8, - 0x0, 0x0, 0x7, 0xfc, 0x3f, 0xf4, 0x0, 0x1, - 0xff, 0xff, 0x40, 0x0, 0x1f, 0xfc, 0x2f, 0xfe, - 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0xbf, 0xf8, - 0xb, 0xff, 0xc0, 0xf, 0xff, 0xff, 0xf0, 0x3, - 0xff, 0xe0, 0x1, 0xff, 0xd0, 0x1f, 0xff, 0xff, - 0xf8, 0x7, 0xff, 0x40, 0x0, 0x7f, 0xc0, 0x2f, - 0xff, 0xff, 0xfc, 0x3, 0xfd, 0x0, 0x0, 0x3f, - 0xc0, 0x3f, 0xff, 0xff, 0xfc, 0x3, 0xfc, 0x0, - 0x0, 0x3f, 0xc0, 0x3f, 0xff, 0xff, 0xfc, 0x3, - 0xfc, 0x0, 0x0, 0x7f, 0xc0, 0x2f, 0xff, 0xff, - 0xfc, 0x3, 0xfc, 0x0, 0x1, 0xff, 0xd0, 0x1f, - 0xff, 0xff, 0xf8, 0x7, 0xff, 0x40, 0xb, 0xff, - 0xc0, 0xf, 0xff, 0xff, 0xf0, 0x3, 0xff, 0xe0, - 0x2f, 0xfe, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, - 0xbf, 0xf4, 0x3f, 0xf4, 0x0, 0x1, 0xff, 0xff, - 0x40, 0x0, 0x1f, 0xfc, 0x3f, 0xd0, 0x0, 0x0, - 0x2f, 0xf8, 0x0, 0x0, 0x7, 0xfc, 0x2f, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf8, - 0xf, 0xf4, 0x1b, 0xc0, 0x0, 0x0, 0x3, 0xe4, - 0x1f, 0xf0, 0xb, 0xfd, 0xff, 0xf4, 0x0, 0x0, - 0x1f, 0xff, 0x7f, 0xe0, 0x3, 0xff, 0xff, 0xff, - 0x80, 0x2, 0xff, 0xff, 0xff, 0xc0, 0x2, 0xff, - 0xff, 0xff, 0xd0, 0x7, 0xff, 0xff, 0xff, 0x40, - 0x0, 0xff, 0xf9, 0xff, 0xe0, 0xb, 0xff, 0x6f, - 0xfe, 0x0, 0x0, 0x2e, 0x40, 0x2f, 0xe0, 0xb, - 0xf8, 0x1, 0xf4, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xf0, 0xf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xf0, 0xf, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0xff, - 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, - 0xff, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, - - /* U+E8FD "" */ - 0x0, 0x0, 0x0, 0x1, 0xbf, 0xfe, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xff, 0xff, - 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, - 0xff, 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x0, - 0x0, 0x2, 0xff, 0xfe, 0x40, 0x1, 0xbf, 0xff, - 0x80, 0x0, 0x0, 0xb, 0xff, 0xd0, 0x0, 0x0, - 0x7, 0xff, 0xe0, 0x0, 0x0, 0x2f, 0xfd, 0x0, - 0x0, 0x0, 0x0, 0x7f, 0xf8, 0x0, 0x0, 0xbf, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfe, 0x0, - 0x1, 0xff, 0xc0, 0x0, 0x2f, 0xf9, 0x0, 0x3, - 0xff, 0x40, 0x3, 0xff, 0x0, 0x1, 0xff, 0xff, - 0x80, 0x0, 0xff, 0xc0, 0xb, 0xfc, 0x0, 0x7, - 0xff, 0xff, 0xf0, 0x0, 0x3f, 0xe0, 0xf, 0xf4, - 0x0, 0xf, 0xfd, 0x6f, 0xf8, 0x0, 0x1f, 0xf0, - 0x2f, 0xf0, 0x0, 0xf, 0xe0, 0x7, 0xfc, 0x0, - 0xf, 0xf8, 0x3f, 0xd0, 0x0, 0xb, 0x40, 0x3, - 0xfc, 0x0, 0x7, 0xfc, 0x3f, 0xc0, 0x0, 0x0, - 0x0, 0x3, 0xfc, 0x0, 0x3, 0xfc, 0x7f, 0x80, - 0x0, 0x0, 0x0, 0x3, 0xfc, 0x0, 0x2, 0xfd, - 0xbf, 0x40, 0x0, 0x0, 0x0, 0xb, 0xf4, 0x0, - 0x1, 0xfe, 0xff, 0x0, 0x0, 0x0, 0x0, 0x2f, - 0xe0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0xbf, 0xc0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x2, 0xff, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x3, 0xfc, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0xb, 0xf4, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0xf, 0xf0, 0x0, 0x0, 0x0, 0xff, 0xbf, 0x40, - 0x0, 0x0, 0x7, 0xd0, 0x0, 0x0, 0x1, 0xfe, - 0x7f, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x2, 0xfd, 0x3f, 0xc0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3, 0xfc, 0x3f, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7, 0xfc, 0x2f, 0xf0, - 0x0, 0x0, 0xb, 0xd0, 0x0, 0x0, 0xf, 0xf8, - 0xf, 0xf4, 0x0, 0x0, 0x1f, 0xf0, 0x0, 0x0, - 0x1f, 0xf0, 0xb, 0xfc, 0x0, 0x0, 0x2f, 0xf4, - 0x0, 0x0, 0x3f, 0xe0, 0x3, 0xff, 0x0, 0x0, - 0x1f, 0xf0, 0x0, 0x0, 0xff, 0xc0, 0x1, 0xff, - 0xc0, 0x0, 0xb, 0xd0, 0x0, 0x3, 0xff, 0x40, - 0x0, 0xbf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xfe, 0x0, 0x0, 0x2f, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x7f, 0xf8, 0x0, 0x0, 0xb, 0xff, 0xd0, - 0x0, 0x0, 0x7, 0xff, 0xe0, 0x0, 0x0, 0x2, - 0xff, 0xfe, 0x40, 0x1, 0xbf, 0xff, 0x80, 0x0, - 0x0, 0x0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0xff, 0xff, - 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, - 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x1, 0xbf, 0xfe, 0x40, 0x0, 0x0, 0x0, - - /* U+E90F "" */ - 0x0, 0x0, 0x6, 0xff, 0xf9, 0x0, 0x0, 0x0, - 0x0, 0xb, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, - 0x7, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x2, - 0xff, 0xff, 0xff, 0xff, 0xf8, 0x0, 0x0, 0xbf, - 0xfe, 0x40, 0x1b, 0xff, 0xe0, 0x0, 0x2f, 0xfd, - 0x0, 0x0, 0x7, 0xff, 0x80, 0x7, 0xff, 0x0, - 0x0, 0x0, 0xf, 0xfd, 0x0, 0xff, 0xc0, 0x0, - 0x0, 0x0, 0x3f, 0xf0, 0x2f, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0x83, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x7, 0xfc, 0x7f, 0xc0, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0xdb, 0xf8, 0x0, 0x0, 0x0, 0x0, - 0x2, 0xfe, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, - 0x1f, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, - 0xf4, 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xbf, - 0x80, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xe7, 0xfc, - 0x0, 0x0, 0x0, 0x0, 0x3, 0xfd, 0x3f, 0xd0, - 0x0, 0x0, 0x0, 0x0, 0x7f, 0xc1, 0xff, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xf4, 0xf, 0xfc, 0x0, - 0x0, 0x0, 0x3, 0xff, 0x0, 0x7f, 0xf0, 0x0, - 0x0, 0x0, 0xff, 0xd0, 0x2, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xf8, 0x0, 0xb, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff, - 0xff, 0x80, 0x0, 0x0, 0x7f, 0xff, 0xff, 0xff, - 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x1, 0xff, 0xff, 0xff, 0xf4, 0x0, - 0x0, 0x0, 0x3f, 0xff, 0xff, 0xff, 0xc0, 0x0, - 0x0, 0x3, 0xff, 0xff, 0xff, 0xfc, 0x0, 0x0, - 0x0, 0x1f, 0xff, 0xff, 0xff, 0x40, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3, 0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x2f, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, - 0xf8, 0x0, 0x0, 0x0, - - /* U+E92E "" */ - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xff, 0xff, 0xf0, 0x0, 0x0, - 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0xf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf0, - 0xf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf0, - 0xf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf0, - 0xf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf0, - 0xf, 0xf0, 0x7, 0xd0, 0x7, 0xd0, 0xf, 0xf0, - 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, - 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, - 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, - 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, - 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, - 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, - 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, - 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, - 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, - 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, - 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, - 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, - 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, - 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, - 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, - 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, 0xf, 0xf0, - 0xf, 0xf0, 0x7, 0xd0, 0x7, 0xd0, 0xf, 0xf0, - 0xf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf0, - 0xf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf0, - 0xf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf0, - 0xf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf0, - 0xf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, - 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, - 0x3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0x0, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, - - /* U+E9B9 "" */ - 0xb, 0xe0, 0x0, 0xb, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xe0, 0x3f, 0xfc, 0x0, 0x3f, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfc, 0xbf, 0xfe, 0x0, 0xbf, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xbf, 0xfe, 0x0, 0xbf, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xfc, 0x0, 0x3f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xb, 0xe0, - 0x0, 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xb, 0xe0, 0x0, 0xb, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xe0, 0x3f, 0xfc, 0x0, 0x3f, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfc, 0xbf, 0xfe, 0x0, 0xbf, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xbf, 0xfe, 0x0, 0xbf, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xfc, 0x0, 0x3f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xb, 0xe0, - 0x0, 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xb, 0xe0, 0x0, 0xb, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xe0, 0x3f, 0xfc, 0x0, 0x3f, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfc, 0xbf, 0xfe, 0x0, 0xbf, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xbf, 0xfe, 0x0, 0xbf, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xfc, 0x0, 0x3f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xb, 0xe0, - 0x0, 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, - - /* U+E9F4 "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xf4, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xff, 0xc0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xf8, 0x3f, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xf0, 0x1f, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xf0, 0x1f, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xf8, 0x3f, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3, 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xfe, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x1f, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, 0x40, 0x0, - 0x0, 0xb, 0xd0, 0x0, 0x0, 0x1, 0xff, 0x40, - 0xf, 0xff, 0xf0, 0x0, 0x0, 0xb, 0xd0, 0x0, - 0x0, 0xf, 0xff, 0xf0, 0x3f, 0xff, 0xfc, 0x0, - 0x0, 0xb, 0xd0, 0x0, 0x0, 0x3f, 0xff, 0xfc, - 0x7f, 0xff, 0xfd, 0x0, 0x0, 0x6f, 0xf8, 0x0, - 0x0, 0x7f, 0xff, 0xfd, 0xff, 0x82, 0xff, 0x0, - 0x3, 0xff, 0xff, 0x80, 0x0, 0xff, 0x82, 0xff, - 0xff, 0x0, 0xff, 0x0, 0xf, 0xff, 0xff, 0xf0, - 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, 0xff, 0x40, - 0x3f, 0xff, 0xff, 0xfc, 0x1, 0xff, 0x0, 0xff, - 0xff, 0x82, 0xff, 0xf9, 0xbf, 0xe0, 0x1b, 0xfe, - 0x6f, 0xff, 0x82, 0xff, 0x7f, 0xff, 0xff, 0xff, - 0xff, 0x40, 0x2, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0x3f, 0xff, 0xfd, 0xbf, 0xfe, 0x0, 0x0, 0xbf, - 0xfe, 0x7f, 0xff, 0xfc, 0xf, 0xff, 0xf0, 0x7, - 0xfc, 0x0, 0x0, 0x7f, 0xd0, 0xf, 0xff, 0xf0, - 0x1, 0xff, 0x40, 0x3, 0xfc, 0x0, 0x0, 0x3f, - 0xc0, 0x1, 0xff, 0x40, 0x0, 0x0, 0x0, 0x3, - 0xfc, 0x0, 0x0, 0x3f, 0xc0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xfc, 0x0, 0x0, 0x7f, - 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, - 0xfe, 0x0, 0x0, 0xbf, 0x80, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0x40, 0x2, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xe0, 0x1b, 0xfe, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3f, 0xff, 0xff, 0xfc, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3f, 0xff, 0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, - 0xfc, 0x6f, 0xf8, 0x3f, 0x80, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x1f, 0xfb, 0xf4, 0x0, 0x0, 0x1f, - 0xef, 0xf4, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, - 0xd0, 0x0, 0x0, 0xb, 0xff, 0xff, 0x0, 0x0, - 0x0, 0x3, 0xff, 0xff, 0xc0, 0x0, 0x0, 0x3, - 0xff, 0xff, 0xc0, 0x0, 0x0, 0x7, 0xff, 0xff, - 0xd0, 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, - 0x0, 0xf, 0xf8, 0x2f, 0xf0, 0x0, 0x0, 0xf, - 0xf8, 0x2f, 0xf0, 0x0, 0x0, 0xf, 0xf0, 0xf, - 0xf0, 0x0, 0x0, 0xf, 0xf0, 0xf, 0xf0, 0x0, - 0x0, 0xf, 0xf0, 0xf, 0xf0, 0x0, 0x0, 0xf, - 0xf0, 0xf, 0xf0, 0x0, 0x0, 0xf, 0xf8, 0x2f, - 0xf0, 0x0, 0x0, 0xf, 0xf8, 0x2f, 0xf0, 0x0, - 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, 0x7, - 0xff, 0xff, 0xd0, 0x0, 0x0, 0x3, 0xff, 0xff, - 0xc0, 0x0, 0x0, 0x3, 0xff, 0xff, 0xc0, 0x0, - 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xf4, - 0x0, 0x0, 0x0, 0x0, 0x1f, 0xf4, 0x0, 0x0, - - /* U+E9F7 "" */ - 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xe0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfc, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfc, 0xb, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xe0, - - /* U+EA07 "" */ - 0x0, 0x0, 0x0, 0x1, 0xbf, 0xfe, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xff, 0xff, - 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, - 0xff, 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x0, - 0x0, 0x2, 0xff, 0xff, 0xfe, 0xbf, 0xff, 0xff, - 0x80, 0x0, 0x0, 0xb, 0xff, 0xdb, 0xfc, 0x3f, - 0xe7, 0xff, 0xe0, 0x0, 0x0, 0x2f, 0xfd, 0xf, - 0xf4, 0x1f, 0xf0, 0x7f, 0xf8, 0x0, 0x0, 0xbf, - 0xf0, 0x1f, 0xf0, 0xf, 0xf4, 0xf, 0xfe, 0x0, - 0x1, 0xff, 0xc0, 0x3f, 0xd0, 0x7, 0xfc, 0x3, - 0xff, 0x40, 0x3, 0xff, 0x0, 0x3f, 0xc0, 0x3, - 0xfc, 0x0, 0xff, 0xc0, 0xb, 0xfd, 0x0, 0x7f, - 0x80, 0x2, 0xfd, 0x0, 0x7f, 0xe0, 0xf, 0xf8, - 0x0, 0xff, 0x40, 0x1, 0xff, 0x0, 0x2f, 0xf0, - 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0xbf, 0x40, 0x3, 0xfc, 0x0, 0x0, 0x3f, 0xc0, - 0x1, 0xfe, 0xff, 0x0, 0x3, 0xfc, 0x0, 0x0, - 0x3f, 0xc0, 0x0, 0xff, 0xff, 0x0, 0x3, 0xfc, - 0x0, 0x0, 0x3f, 0xc0, 0x0, 0xff, 0xff, 0x0, - 0x3, 0xfc, 0x0, 0x0, 0x3f, 0xc0, 0x0, 0xff, - 0xff, 0x0, 0x3, 0xfc, 0x0, 0x0, 0x3f, 0xc0, - 0x0, 0xff, 0xff, 0x0, 0x3, 0xfc, 0x0, 0x0, - 0x3f, 0xc0, 0x0, 0xff, 0xff, 0x0, 0x3, 0xfc, - 0x0, 0x0, 0x3f, 0xc0, 0x0, 0xff, 0xbf, 0x40, - 0x3, 0xfc, 0x0, 0x0, 0x3f, 0xc0, 0x1, 0xfe, - 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfd, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x2f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, - 0xf, 0xf8, 0x0, 0xff, 0x40, 0x1, 0xfe, 0x0, - 0x2f, 0xf0, 0xb, 0xfd, 0x0, 0x7f, 0x80, 0x2, - 0xfd, 0x0, 0x7f, 0xe0, 0x3, 0xff, 0x0, 0x3f, - 0xc0, 0x3, 0xfc, 0x0, 0xff, 0xc0, 0x1, 0xff, - 0xc0, 0x3f, 0xd0, 0x7, 0xfc, 0x3, 0xff, 0x40, - 0x0, 0xbf, 0xf0, 0x1f, 0xf0, 0xf, 0xf4, 0xf, - 0xfe, 0x0, 0x0, 0x2f, 0xfd, 0xf, 0xf4, 0x1f, - 0xf0, 0x7f, 0xf8, 0x0, 0x0, 0xb, 0xff, 0xdb, - 0xfc, 0x3f, 0xe7, 0xff, 0xe0, 0x0, 0x0, 0x2, - 0xff, 0xff, 0xfe, 0xbf, 0xff, 0xff, 0x80, 0x0, - 0x0, 0x0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0xff, 0xff, - 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, - 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x1, 0xbf, 0xfe, 0x40, 0x0, 0x0, 0x0, - - /* U+EAD6 "" */ - 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xe0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfc, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0xb, 0xff, 0x7, - 0xff, 0x4f, 0x0, 0xb0, 0xff, 0xff, 0xf, 0xff, - 0xcb, 0xff, 0x8f, 0x40, 0xf0, 0xff, 0xff, 0xf, - 0x97, 0xcf, 0xd5, 0xf, 0x81, 0xf0, 0xff, 0xff, - 0xf, 0x43, 0xcf, 0x80, 0xb, 0xc2, 0xe0, 0xff, - 0xff, 0xf, 0x43, 0xcf, 0x80, 0x7, 0xc3, 0xd0, - 0xff, 0xff, 0xf, 0x43, 0xcf, 0xfc, 0x3, 0xd3, - 0xc0, 0xff, 0xff, 0xf, 0x43, 0xcf, 0xfc, 0x3, - 0xe7, 0xc0, 0xff, 0xff, 0xf, 0x43, 0xcf, 0x80, - 0x1, 0xfb, 0x80, 0xff, 0xff, 0xf, 0x43, 0xcf, - 0x80, 0x0, 0xff, 0x40, 0xff, 0xff, 0xf, 0x83, - 0xcf, 0x80, 0x0, 0xff, 0x0, 0xff, 0xff, 0xf, - 0xff, 0xcb, 0xff, 0x80, 0xbf, 0x0, 0xff, 0xff, - 0xb, 0xff, 0x7, 0xff, 0x40, 0x3c, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfc, 0xb, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xe0, - - /* U+EB8E "" */ - 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfc, 0xbf, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x1f, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x3f, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x3f, 0xf8, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0xf, 0xfe, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x3, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x3f, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x3f, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x3, 0xff, 0x40, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0xf, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x3f, 0xf4, - 0x0, 0x7f, 0xff, 0xfd, 0x0, 0xff, 0xff, 0x0, - 0x3f, 0xd0, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, - 0xff, 0x0, 0x1f, 0x40, 0x0, 0xff, 0xff, 0xff, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x7f, - 0xff, 0xfd, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xb, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, - - /* U+EB97 "" */ - 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfc, 0xbf, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0x80, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xc0, 0x0, 0xff, 0xff, 0x0, 0x15, 0x55, - 0x55, 0x54, 0xf, 0xd4, 0x0, 0xff, 0xff, 0x0, - 0xff, 0xff, 0xff, 0xff, 0xf, 0xff, 0x0, 0xff, - 0xff, 0x0, 0xff, 0xff, 0xff, 0xff, 0xf, 0xff, - 0x0, 0xff, 0xff, 0x0, 0x15, 0x55, 0x55, 0x54, - 0xf, 0xd4, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xc0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xb, 0x80, 0x0, 0xff, - 0xff, 0x0, 0x2, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x3, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x17, 0xf0, - 0x15, 0x55, 0x55, 0x54, 0x0, 0xff, 0xff, 0x0, - 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x0, 0xff, - 0xff, 0x0, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, - 0x0, 0xff, 0xff, 0x0, 0x17, 0xf0, 0x15, 0x55, - 0x55, 0x54, 0x0, 0xff, 0xff, 0x0, 0x3, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x2, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xb, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x7f, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x0, - - /* U+EBCC "" */ - 0x0, 0x7, 0xd0, 0x0, 0x0, 0x0, 0x7, 0xd0, - 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, 0xf, - 0xf0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, - 0xf, 0xf0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, - 0x0, 0xf, 0xf0, 0x0, 0xb, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xe0, 0x3f, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xbf, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x7d, 0x0, - 0x7d, 0x0, 0x7d, 0x0, 0xff, 0xff, 0x0, 0xff, - 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, - 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, - 0x0, 0x7d, 0x0, 0x7d, 0x0, 0x7d, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x7d, 0x0, - 0x7d, 0x0, 0x7d, 0x0, 0xff, 0xff, 0x0, 0xff, - 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, - 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, - 0x0, 0x7d, 0x0, 0x7d, 0x0, 0x7d, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xb, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, - - /* U+EC1C "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xc0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0x80, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x2f, 0xfe, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xbf, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2, 0xff, 0xf8, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xff, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3f, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0xc0, 0x0, 0x0, - 0x0, 0x0, 0x3, 0xff, 0xff, 0x40, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0xff, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xef, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x3, 0xff, 0x9f, 0xf4, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xfe, 0x3f, 0xff, 0xa5, 0x0, 0x0, - 0x0, 0x7f, 0xf8, 0x7f, 0xff, 0xff, 0xff, 0xa4, - 0x1, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0x7, 0xff, 0x80, 0x5a, 0xff, 0xff, 0xff, 0xfe, - 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x5a, 0xff, 0xfd, - 0x7f, 0xff, 0xa5, 0x0, 0x0, 0x0, 0x7f, 0xf4, - 0xbf, 0xff, 0xff, 0xff, 0xa5, 0x1, 0xff, 0xd0, - 0x7f, 0xff, 0xff, 0xff, 0xff, 0xb, 0xff, 0x40, - 0x1a, 0xff, 0xff, 0xff, 0xfd, 0x2f, 0xfd, 0x0, - 0x0, 0x0, 0x5a, 0xff, 0xfc, 0xbf, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x1f, 0xf6, 0xff, 0xc0, 0x0, - 0x0, 0x0, 0x0, 0x3f, 0xeb, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7f, 0xff, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x1, 0xff, 0xff, 0xc0, 0x0, 0x0, - 0x0, 0x0, 0x3, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xff, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x2f, 0xff, 0x80, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xbf, 0xf8, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x2, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x1, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, - - /* U+EF40 "" */ - 0xb, 0xe0, 0x0, 0xb, 0xe0, 0x0, 0xb, 0xe0, - 0x0, 0x3f, 0xfc, 0x0, 0x3f, 0xfc, 0x0, 0x3f, - 0xfc, 0x0, 0xbf, 0xfe, 0x0, 0xbf, 0xfe, 0x0, - 0xbf, 0xfe, 0x0, 0xff, 0xff, 0x0, 0xff, 0xff, - 0x0, 0xff, 0xff, 0x0, 0xff, 0xff, 0x0, 0xff, - 0xff, 0x0, 0xff, 0xff, 0x0, 0xbf, 0xfe, 0x0, - 0xbf, 0xfe, 0x0, 0xbf, 0xfe, 0x0, 0x3f, 0xfc, - 0x0, 0x3f, 0xfc, 0x0, 0x3f, 0xfc, 0x0, 0xb, - 0xe0, 0x0, 0xb, 0xe0, 0x0, 0xb, 0xe0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xb, 0xe0, 0x0, 0xb, - 0xe0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfc, 0x0, - 0x3f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xfe, - 0x0, 0xbf, 0xfe, 0x0, 0x0, 0x1f, 0x80, 0xff, - 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xbf, 0xf0, - 0xff, 0xff, 0x0, 0xff, 0xff, 0x0, 0x2, 0xff, - 0xfc, 0xbf, 0xfe, 0x0, 0xbf, 0xfe, 0x0, 0xb, - 0xff, 0xfe, 0x3f, 0xfc, 0x0, 0x3f, 0xfc, 0x0, - 0x2f, 0xff, 0xff, 0xb, 0xe0, 0x0, 0xb, 0xe0, - 0x0, 0xbf, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x2, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xb, 0xf9, 0xff, 0xf8, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xe0, 0x7f, 0xe0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xbf, 0x80, 0xbf, 0x80, - 0xb, 0xe0, 0x0, 0x0, 0x2, 0xfe, 0x2, 0xfe, - 0x0, 0x3f, 0xfc, 0x0, 0x0, 0xb, 0xf8, 0xb, - 0xf8, 0x0, 0xbf, 0xfe, 0x0, 0x0, 0xf, 0xe0, - 0x2f, 0xe0, 0x0, 0xff, 0xff, 0x0, 0x0, 0xf, - 0xc0, 0xbf, 0x80, 0x0, 0xff, 0xff, 0x0, 0x0, - 0xf, 0xc2, 0xfe, 0x0, 0x0, 0xbf, 0xfe, 0x0, - 0x0, 0xf, 0xff, 0xf8, 0x0, 0x0, 0x3f, 0xfc, - 0x0, 0x0, 0xf, 0xff, 0xe0, 0x0, 0x0, 0xb, - 0xe0, 0x0, 0x0, 0x7, 0xff, 0x80, 0x0, 0x0, - - /* U+EF4A "" */ - 0x0, 0x0, 0x0, 0x1, 0xbf, 0xfe, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xff, 0xff, - 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, - 0xff, 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x0, - 0x0, 0x2, 0xff, 0xfe, 0x40, 0x1, 0xbf, 0xff, - 0x80, 0x0, 0x0, 0xb, 0xff, 0xd0, 0x0, 0x0, - 0x7, 0xff, 0xe0, 0x0, 0x0, 0x2f, 0xfd, 0x0, - 0x0, 0x0, 0x0, 0x7f, 0xf8, 0x0, 0x0, 0xbf, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfe, 0x0, - 0x1, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x3, - 0xff, 0x40, 0x3, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xc0, 0xb, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3f, 0xe0, 0xf, 0xf4, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xf0, - 0x2f, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xf8, 0x3f, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xfc, 0x3f, 0xc0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3, 0xfc, 0x7f, 0x80, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xfd, - 0xbf, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xfe, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xbf, 0x40, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xfe, - 0x7f, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x2, 0xfd, 0x3f, 0xc0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3, 0xfc, 0x3f, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7, 0xfc, 0x2f, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf8, - 0xf, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x1f, 0xf0, 0xb, 0xfc, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0xe0, 0x3, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xc0, 0x1, 0xff, - 0xc0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0x40, - 0x0, 0xbf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xfe, 0x0, 0x0, 0x2f, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x7f, 0xf8, 0x0, 0x0, 0xb, 0xff, 0xd0, - 0x0, 0x0, 0x7, 0xff, 0xe0, 0x0, 0x0, 0x2, - 0xff, 0xfe, 0x40, 0x1, 0xbf, 0xff, 0x80, 0x0, - 0x0, 0x0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0xff, 0xff, - 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, - 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x1, 0xbf, 0xfe, 0x40, 0x0, 0x0, 0x0, - - /* U+EF7A "" */ - 0x0, 0x0, 0x2f, 0xff, 0x80, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff, 0x80, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, - 0xf0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xe4, 0x1, - 0xbf, 0xfc, 0x0, 0x0, 0x0, 0xb, 0xff, 0x0, - 0x0, 0xf, 0xfe, 0x0, 0x0, 0x0, 0x1f, 0xf8, - 0x0, 0x0, 0x2, 0xff, 0x40, 0x0, 0x0, 0x3f, - 0xf0, 0x0, 0x0, 0x0, 0xff, 0xc0, 0x0, 0x0, - 0x3f, 0xc0, 0x0, 0x0, 0x0, 0x3f, 0xc0, 0x0, - 0x0, 0xbf, 0x80, 0x0, 0x0, 0x0, 0x2f, 0xe0, - 0x0, 0x0, 0xff, 0x40, 0x0, 0x0, 0x0, 0x1f, - 0xf0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xf0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xf0, 0x0, 0x0, 0xff, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0xff, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0xff, - 0x40, 0x0, 0x0, 0x0, 0x1f, 0xe0, 0x0, 0x0, - 0xbf, 0x80, 0x0, 0x0, 0x0, 0x2f, 0xd0, 0x0, - 0x0, 0x3f, 0xc0, 0x0, 0x0, 0x0, 0x3f, 0xc0, - 0x0, 0x0, 0x3f, 0xf0, 0x0, 0x0, 0x0, 0xff, - 0x80, 0x0, 0x0, 0x1f, 0xf8, 0x0, 0x0, 0x2, - 0xff, 0x0, 0x0, 0x0, 0xb, 0xff, 0x0, 0x0, - 0xf, 0xfe, 0x0, 0x0, 0x0, 0x3, 0xff, 0xe4, - 0x1, 0xbf, 0xff, 0x40, 0x0, 0x0, 0x0, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, 0x0, - 0x2f, 0xff, 0xff, 0xff, 0xbf, 0xf4, 0x0, 0x0, - 0x0, 0x7, 0xff, 0xff, 0xf8, 0x1f, 0xfd, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xfe, 0x40, 0x7, 0xff, - 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x7f, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x1f, 0xfd, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7, 0xff, 0x40, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xf4, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, - 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x7, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x1, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, - - /* U+EFE6 "" */ - 0x0, 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x7, 0xff, - 0xd0, 0x0, 0x2, 0xff, 0xff, 0x80, 0x0, 0xf, - 0xff, 0xf0, 0x0, 0xb, 0xff, 0xff, 0xe0, 0x0, - 0xf, 0xff, 0xf0, 0x0, 0x2f, 0xff, 0xff, 0xf8, - 0x0, 0xf, 0xff, 0xf0, 0x0, 0x3f, 0xf4, 0x1f, - 0xfc, 0x0, 0x2f, 0xff, 0xf8, 0x0, 0xbf, 0xc0, - 0x3, 0xfe, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, - 0x40, 0x1, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, - 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0xff, 0xff, - 0x0, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0xff, - 0xff, 0x0, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, - 0xff, 0xff, 0x0, 0xff, 0x0, 0x0, 0xff, 0x0, - 0xff, 0xff, 0xff, 0x0, 0xff, 0x0, 0x0, 0xff, - 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0x0, 0x0, - 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0x0, - 0x0, 0xff, 0x0, 0x7f, 0xff, 0xfd, 0x0, 0xff, - 0x0, 0x0, 0xff, 0x0, 0x0, 0xff, 0x0, 0x0, - 0xff, 0x0, 0x0, 0xff, 0x0, 0x0, 0xff, 0x0, - 0x0, 0xff, 0x0, 0x0, 0xff, 0x0, 0x0, 0xff, - 0x0, 0x0, 0xff, 0x0, 0x0, 0xff, 0x0, 0x0, - 0xff, 0x0, 0x0, 0xff, 0x0, 0x0, 0xff, 0x0, - 0x0, 0xff, 0x0, 0x0, 0xff, 0x0, 0x0, 0xff, - 0x0, 0x0, 0xff, 0x0, 0x0, 0xff, 0x0, 0x0, - 0xff, 0x0, 0x0, 0xff, 0x0, 0x0, 0xff, 0x0, - 0x0, 0xff, 0x0, 0x0, 0xff, 0x0, 0x7f, 0xff, - 0xfd, 0x0, 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, - 0xff, 0xff, 0x0, 0xff, 0x0, 0x0, 0xff, 0x0, - 0xff, 0xff, 0xff, 0x0, 0xff, 0x0, 0x0, 0xff, - 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0x0, 0x0, - 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0x0, - 0x0, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, - 0x0, 0x0, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, - 0xff, 0x0, 0x0, 0xff, 0x0, 0xff, 0xff, 0xff, - 0x0, 0xff, 0x40, 0x1, 0xff, 0x0, 0xff, 0xff, - 0xff, 0x0, 0xbf, 0xc0, 0x3, 0xfe, 0x0, 0x2f, - 0xff, 0xf8, 0x0, 0x3f, 0xf4, 0x1f, 0xfc, 0x0, - 0xf, 0xff, 0xf0, 0x0, 0x2f, 0xff, 0xff, 0xf8, - 0x0, 0xf, 0xff, 0xf0, 0x0, 0xb, 0xff, 0xff, - 0xe0, 0x0, 0xf, 0xff, 0xf0, 0x0, 0x2, 0xff, - 0xff, 0x80, 0x0, 0x7, 0xff, 0xd0, 0x0, 0x0, - 0x2f, 0xf8, 0x0, 0x0, - - /* U+F028 "" */ - 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xbf, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x7d, 0x0, 0x7d, 0x0, 0x7d, 0x0, - 0x7d, 0x0, 0xff, 0xff, 0x0, 0xff, 0x0, 0xff, - 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, - 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, - 0xff, 0xff, 0x0, 0x7d, 0x0, 0x7d, 0x0, 0x7d, - 0x0, 0x7d, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x7d, - 0x0, 0x7d, 0x0, 0x7d, 0x0, 0x7d, 0x0, 0xff, - 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, - 0xff, 0x0, 0xff, 0xff, 0x0, 0xff, 0x0, 0xff, - 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0x0, - 0x7d, 0x0, 0x7d, 0x0, 0x7d, 0x0, 0x7d, 0x0, - 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x7, 0xff, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, - 0xf, 0xff, 0xff, 0xff, 0xf0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0xf, 0xff, 0xff, 0xff, 0xf0, - 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xff, 0xd0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0xb, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, - - /* U+F090 "" */ - 0x0, 0x0, 0x0, 0x7, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x1, 0xf0, 0xf, 0xf0, 0xf, 0x40, 0x0, - 0x0, 0x3, 0xfc, 0xf, 0xf0, 0x3f, 0xc0, 0x0, - 0x0, 0x3, 0xff, 0xf, 0xf0, 0xff, 0xc0, 0x0, - 0x0, 0x1, 0xff, 0xcf, 0xf3, 0xff, 0x40, 0x0, - 0x0, 0x0, 0xbf, 0xff, 0xff, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x2f, 0xff, 0xff, 0xf4, 0x0, 0x0, - 0x0, 0x0, 0xb, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x2, 0xff, 0xff, 0x40, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xbf, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xf4, 0x0, 0x0, 0x0, - 0x7d, 0x0, 0x0, 0x7, 0xd0, 0x0, 0x0, 0x7d, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, - 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, - - /* U+F15C "" */ - 0x0, 0x0, 0x0, 0x0, 0x1b, 0xff, 0xe4, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, - 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xff, 0xff, 0xff, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0xff, 0xff, - 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, - 0xf9, 0x0, 0x6f, 0xff, 0x40, 0x0, 0x0, 0x0, - 0x0, 0x3, 0xff, 0x80, 0x0, 0x2, 0xff, 0xc0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0x0, 0x0, - 0x0, 0x7f, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x1f, - 0xf4, 0x0, 0x0, 0x0, 0x1f, 0xf4, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0xe0, 0x0, 0x0, 0x0, 0xb, - 0xfc, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xc0, 0x0, - 0x0, 0x0, 0x3, 0xfd, 0x0, 0x0, 0x0, 0x1, - 0xff, 0x80, 0x0, 0x0, 0x0, 0x2, 0xfe, 0x0, - 0x0, 0x0, 0x2f, 0xff, 0x40, 0x0, 0x0, 0x0, - 0x1, 0xff, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x3, - 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0x0, 0x0, 0xf, 0xff, 0x40, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xe4, 0x0, 0x1f, 0xf8, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x3f, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xff, 0xd0, 0x7f, 0xc0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0xf0, 0xbf, 0x40, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, - 0xfc, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xfd, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xfe, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xbf, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0x7f, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0x3f, 0xe0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x2, 0xfe, 0x2f, 0xf8, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, - 0xfd, 0xf, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x2f, 0xfc, 0x3, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xd0, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x1, 0xbf, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe4, 0x0, - - /* U+F720 "" */ - 0x0, 0x0, 0x0, 0x0, 0xbe, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0xe0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, - 0xd7, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x2, 0xff, - 0xfd, 0x0, 0x7f, 0xff, 0x80, 0x0, 0x0, 0x1f, - 0xff, 0xe0, 0x0, 0xb, 0xff, 0xf4, 0x0, 0x1, - 0xff, 0xff, 0x0, 0x0, 0x0, 0xff, 0xff, 0x40, - 0xb, 0xff, 0xf4, 0x0, 0x0, 0x0, 0x1f, 0xff, - 0xe0, 0x3f, 0xff, 0x40, 0x0, 0x0, 0x0, 0x1, - 0xff, 0xfc, 0xbf, 0xf8, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x2f, 0xfe, 0xff, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7f, 0xff, 0xff, 0xff, 0xc0, 0x0, - 0x0, 0x0, 0x3, 0xff, 0xff, 0xff, 0xff, 0xf8, - 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff, 0x7f, - 0xff, 0x40, 0x0, 0x1, 0xff, 0xfd, 0xff, 0xff, - 0xb, 0xff, 0xf4, 0x0, 0x1f, 0xff, 0xe0, 0xff, - 0xff, 0x0, 0xff, 0xfe, 0x0, 0xbf, 0xff, 0x0, - 0xff, 0xff, 0x0, 0x1f, 0xff, 0xeb, 0xff, 0xf4, - 0x0, 0xff, 0xff, 0x0, 0x2, 0xff, 0xff, 0xff, - 0x80, 0x0, 0xff, 0xff, 0x0, 0x0, 0x2f, 0xff, - 0xf8, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x7, - 0xff, 0xd0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, - 0x0, 0xff, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0xff, 0xff, - 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, - 0xff, 0xff, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0xff, 0x0, - 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0xff, - 0x0, 0x0, 0x0, 0xff, 0xff, 0xc0, 0x0, 0x0, - 0xff, 0x0, 0x0, 0x3, 0xff, 0xbf, 0xf8, 0x0, - 0x0, 0xff, 0x0, 0x0, 0x2f, 0xfe, 0x3f, 0xff, - 0x40, 0x0, 0xff, 0x0, 0x1, 0xff, 0xfc, 0xb, - 0xff, 0xf4, 0x0, 0xff, 0x0, 0x1f, 0xff, 0xe0, - 0x1, 0xff, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, - 0x40, 0x0, 0x1f, 0xff, 0xe0, 0xff, 0xb, 0xff, - 0xf4, 0x0, 0x0, 0x2, 0xff, 0xfd, 0xff, 0x7f, - 0xff, 0x80, 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, - 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x7f, 0xff, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xb, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xbe, 0x0, 0x0, 0x0, 0x0, - - /* U+F8C7 "" */ - 0x0, 0x0, 0x0, 0x0, 0x7, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x14, 0x0, 0x0, - 0xf, 0xf0, 0x0, 0x0, 0x14, 0x0, 0x0, 0xbe, - 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0xbe, 0x0, - 0x1, 0xff, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, - 0xff, 0x40, 0x3, 0xff, 0x0, 0x0, 0xf, 0xf0, - 0x0, 0x0, 0xff, 0xc0, 0xb, 0xfc, 0x0, 0x0, - 0xf, 0xf0, 0x0, 0x0, 0x3f, 0xe0, 0xf, 0xf4, - 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x1f, 0xf0, - 0x2f, 0xf0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, - 0xf, 0xf4, 0x3f, 0xd0, 0x0, 0x0, 0xf, 0xf0, - 0x0, 0x0, 0x7, 0xfc, 0x3f, 0xc0, 0x0, 0x0, - 0xf, 0xf0, 0x0, 0x0, 0x3, 0xfc, 0x7f, 0x80, - 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x2, 0xfd, - 0xbf, 0x40, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, - 0x1, 0xfe, 0xff, 0x0, 0x0, 0x0, 0xf, 0xf0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0xf, 0xf0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x7, 0xd0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xbf, 0x40, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xfe, - 0x7f, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x2, 0xfd, 0x3f, 0xc0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3, 0xfc, 0x3f, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7, 0xfc, 0x2f, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf8, - 0xf, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x1f, 0xf0, 0xb, 0xfc, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0xe0, 0x3, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xc0, 0x1, 0xff, - 0xc0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0x40, - 0x0, 0xbf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xfe, 0x0, 0x0, 0x2f, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x7f, 0xf8, 0x0, 0x0, 0xb, 0xff, 0xd0, - 0x0, 0x0, 0x7, 0xff, 0xe0, 0x0, 0x0, 0x2, - 0xff, 0xfe, 0x40, 0x1, 0xbf, 0xff, 0x80, 0x0, - 0x0, 0x0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0xff, 0xff, - 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, - 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x1, 0xbf, 0xfe, 0x40, 0x0, 0x0, 0x0, - - /* U+FFF75 "󿽵" */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x40, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x2, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0xfc, 0x0, - 0x7, 0xc0, 0x0, 0x3e, 0x0, 0xff, 0xff, 0x0, - 0xfc, 0x0, 0xb, 0xc0, 0x0, 0x3f, 0x0, 0xff, - 0xff, 0x0, 0x64, 0x0, 0x2, 0x40, 0x0, 0x18, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x1, - 0xff, 0xff, 0xf8, 0x0, 0x2, 0xff, 0x0, 0x0, - 0x0, 0x6f, 0xff, 0xfe, 0x40, 0x0, 0x0, 0xff, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xe0, 0x7, 0xc0, - 0x0, 0xff, 0x0, 0x1, 0xbf, 0xff, 0xf9, 0x0, - 0xb, 0xc0, 0x0, 0xff, 0x0, 0x1f, 0xff, 0xff, - 0x40, 0x0, 0x7, 0xc0, 0x2, 0xff, 0x2, 0xff, - 0xff, 0xe4, 0x7, 0xc0, 0x0, 0x0, 0x1f, 0xfe, - 0x1f, 0xff, 0xfd, 0x0, 0xb, 0xc0, 0x0, 0x7, - 0xff, 0xfc, 0x3f, 0xff, 0x80, 0x0, 0x7, 0xc0, - 0x1, 0xbf, 0xff, 0xf0, 0xbf, 0xf4, 0xb, 0x40, - 0x0, 0x0, 0x6f, 0xff, 0xff, 0x80, 0xff, 0x40, - 0xf, 0xc0, 0x0, 0xb, 0xff, 0xff, 0xe4, 0x0, - 0xff, 0x0, 0xb, 0x40, 0x1, 0xff, 0xff, 0xfd, - 0x0, 0x0, 0xff, 0x80, 0x0, 0x0, 0x6f, 0xff, - 0xff, 0x80, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0x0, 0xfc, 0x0, 0x7, 0xc0, 0x0, 0x3e, - 0x0, 0xff, 0xff, 0x0, 0xfc, 0x0, 0xb, 0xc0, - 0x0, 0x3f, 0x0, 0xff, 0xff, 0x0, 0x64, 0x0, - 0x2, 0x40, 0x0, 0x18, 0x0, 0xff, 0xff, 0x80, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xf, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; - - -/*--------------------- - * GLYPH DESCRIPTION - *--------------------*/ - -static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { - {.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */, - {.bitmap_index = 0, .adv_w = 768, .box_w = 28, .box_h = 28, .ofs_x = 10, .ofs_y = 10}, - {.bitmap_index = 196, .adv_w = 768, .box_w = 40, .box_h = 32, .ofs_x = 4, .ofs_y = 8}, - {.bitmap_index = 516, .adv_w = 768, .box_w = 25, .box_h = 40, .ofs_x = 10, .ofs_y = 4}, - {.bitmap_index = 766, .adv_w = 768, .box_w = 28, .box_h = 40, .ofs_x = 10, .ofs_y = 4}, - {.bitmap_index = 1046, .adv_w = 768, .box_w = 44, .box_h = 44, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 1530, .adv_w = 768, .box_w = 40, .box_h = 32, .ofs_x = 4, .ofs_y = 8}, - {.bitmap_index = 1850, .adv_w = 768, .box_w = 40, .box_h = 40, .ofs_x = 4, .ofs_y = 4}, - {.bitmap_index = 2250, .adv_w = 768, .box_w = 24, .box_h = 14, .ofs_x = 12, .ofs_y = 18}, - {.bitmap_index = 2334, .adv_w = 768, .box_w = 40, .box_h = 32, .ofs_x = 4, .ofs_y = 8}, - {.bitmap_index = 2654, .adv_w = 768, .box_w = 40, .box_h = 40, .ofs_x = 4, .ofs_y = 4}, - {.bitmap_index = 3054, .adv_w = 768, .box_w = 36, .box_h = 36, .ofs_x = 6, .ofs_y = 6}, - {.bitmap_index = 3378, .adv_w = 768, .box_w = 24, .box_h = 36, .ofs_x = 12, .ofs_y = 6}, - {.bitmap_index = 3594, .adv_w = 768, .box_w = 32, .box_h = 36, .ofs_x = 8, .ofs_y = 6}, - {.bitmap_index = 3882, .adv_w = 768, .box_w = 32, .box_h = 32, .ofs_x = 8, .ofs_y = 8}, - {.bitmap_index = 4138, .adv_w = 768, .box_w = 28, .box_h = 28, .ofs_x = 10, .ofs_y = 10}, - {.bitmap_index = 4334, .adv_w = 768, .box_w = 36, .box_h = 24, .ofs_x = 6, .ofs_y = 12}, - {.bitmap_index = 4550, .adv_w = 768, .box_w = 8, .box_h = 32, .ofs_x = 20, .ofs_y = 8}, - {.bitmap_index = 4614, .adv_w = 768, .box_w = 32, .box_h = 32, .ofs_x = 8, .ofs_y = 8}, - {.bitmap_index = 4870, .adv_w = 768, .box_w = 46, .box_h = 34, .ofs_x = 1, .ofs_y = 6}, - {.bitmap_index = 5261, .adv_w = 768, .box_w = 32, .box_h = 24, .ofs_x = 8, .ofs_y = 12}, - {.bitmap_index = 5453, .adv_w = 768, .box_w = 36, .box_h = 32, .ofs_x = 8, .ofs_y = 8}, - {.bitmap_index = 5741, .adv_w = 768, .box_w = 36, .box_h = 33, .ofs_x = 6, .ofs_y = 8}, - {.bitmap_index = 6038, .adv_w = 768, .box_w = 32, .box_h = 40, .ofs_x = 8, .ofs_y = 4}, - {.bitmap_index = 6358, .adv_w = 768, .box_w = 40, .box_h = 38, .ofs_x = 4, .ofs_y = 6}, - {.bitmap_index = 6738, .adv_w = 768, .box_w = 40, .box_h = 40, .ofs_x = 4, .ofs_y = 4}, - {.bitmap_index = 7138, .adv_w = 768, .box_w = 40, .box_h = 40, .ofs_x = 4, .ofs_y = 4}, - {.bitmap_index = 7538, .adv_w = 768, .box_w = 30, .box_h = 40, .ofs_x = 9, .ofs_y = 4}, - {.bitmap_index = 7838, .adv_w = 768, .box_w = 32, .box_h = 36, .ofs_x = 8, .ofs_y = 6}, - {.bitmap_index = 8126, .adv_w = 768, .box_w = 40, .box_h = 32, .ofs_x = 4, .ofs_y = 8}, - {.bitmap_index = 8446, .adv_w = 768, .box_w = 48, .box_h = 46, .ofs_x = 0, .ofs_y = 2}, - {.bitmap_index = 8998, .adv_w = 768, .box_w = 36, .box_h = 36, .ofs_x = 6, .ofs_y = 6}, - {.bitmap_index = 9322, .adv_w = 768, .box_w = 40, .box_h = 40, .ofs_x = 4, .ofs_y = 4}, - {.bitmap_index = 9722, .adv_w = 768, .box_w = 36, .box_h = 36, .ofs_x = 6, .ofs_y = 6}, - {.bitmap_index = 10046, .adv_w = 768, .box_w = 40, .box_h = 32, .ofs_x = 4, .ofs_y = 8}, - {.bitmap_index = 10366, .adv_w = 768, .box_w = 40, .box_h = 36, .ofs_x = 4, .ofs_y = 6}, - {.bitmap_index = 10726, .adv_w = 768, .box_w = 36, .box_h = 40, .ofs_x = 6, .ofs_y = 4}, - {.bitmap_index = 11086, .adv_w = 768, .box_w = 32, .box_h = 40, .ofs_x = 8, .ofs_y = 4}, - {.bitmap_index = 11406, .adv_w = 768, .box_w = 36, .box_h = 32, .ofs_x = 8, .ofs_y = 8}, - {.bitmap_index = 11694, .adv_w = 768, .box_w = 40, .box_h = 40, .ofs_x = 4, .ofs_y = 4}, - {.bitmap_index = 12094, .adv_w = 768, .box_w = 36, .box_h = 36, .ofs_x = 6, .ofs_y = 6}, - {.bitmap_index = 12418, .adv_w = 768, .box_w = 36, .box_h = 36, .ofs_x = 6, .ofs_y = 6}, - {.bitmap_index = 12742, .adv_w = 768, .box_w = 44, .box_h = 32, .ofs_x = 2, .ofs_y = 8}, - {.bitmap_index = 13094, .adv_w = 768, .box_w = 32, .box_h = 32, .ofs_x = 8, .ofs_y = 8}, - {.bitmap_index = 13350, .adv_w = 768, .box_w = 44, .box_h = 32, .ofs_x = 2, .ofs_y = 8}, - {.bitmap_index = 13702, .adv_w = 768, .box_w = 36, .box_h = 40, .ofs_x = 6, .ofs_y = 4}, - {.bitmap_index = 14062, .adv_w = 768, .box_w = 40, .box_h = 40, .ofs_x = 4, .ofs_y = 4}, - {.bitmap_index = 14462, .adv_w = 768, .box_w = 40, .box_h = 40, .ofs_x = 4, .ofs_y = 4} -}; - -/*--------------------- - * CHARACTER MAPPING - *--------------------*/ - -static const uint16_t unicode_list_0[] = { - 0x0, 0x14, 0x62, 0x9b, 0x148, 0x182, 0x1ca, 0x1d1, - 0x1e1, 0x26a, 0x2af, 0x2c0, 0x418, 0x47e, 0x488, 0x48d, - 0x48f, 0x490, 0x4f9, 0x523, 0x600, 0x62b, 0x757, 0x76a, - 0x773, 0x7b8, 0x7ca, 0x7e9, 0x874, 0x8af, 0x8b2, 0x8c2, - 0x991, 0xa49, 0xa52, 0xa87, 0xad7, 0xdfb, 0xe05, 0xe35, - 0xea1, 0xee3, 0xf4b, 0x1017, 0x15db, 0x1782 -}; - -/*Collect the unicode lists and glyph_id offsets*/ -static const lv_font_fmt_txt_cmap_t cmaps[] = -{ - { - .range_start = 57669, .range_length = 6019, .glyph_id_start = 1, - .unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 46, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY - }, - { - .range_start = 1048437, .range_length = 1, .glyph_id_start = 47, - .unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY - } -}; - - - -/*-------------------- - * ALL CUSTOM DATA - *--------------------*/ - -#if LVGL_VERSION_MAJOR == 8 -/*Store all the custom data of the font*/ -static lv_font_fmt_txt_glyph_cache_t cache; -#endif - -#if LVGL_VERSION_MAJOR >= 8 -static const lv_font_fmt_txt_dsc_t font_dsc = { -#else -static lv_font_fmt_txt_dsc_t font_dsc = { -#endif - .glyph_bitmap = glyph_bitmap, - .glyph_dsc = glyph_dsc, - .cmaps = cmaps, - .kern_dsc = NULL, - .kern_scale = 0, - .cmap_num = 2, - .bpp = 2, - .kern_classes = 0, - .bitmap_format = 0, -#if LVGL_VERSION_MAJOR == 8 - .cache = &cache -#endif -}; - - - -/*----------------- - * PUBLIC FONT - *----------------*/ - -/*Initialize a public general font descriptor*/ -#if LVGL_VERSION_MAJOR >= 8 -const lv_font_t material_symbols_shared_48 = { -#else -lv_font_t material_symbols_shared_48 = { -#endif - .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ - .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ - .line_height = 46, /*The maximum line height required by the font*/ - .base_line = -2, /*Baseline measured from the bottom of the line*/ -#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) - .subpx = LV_FONT_SUBPX_NONE, -#endif -#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 - .underline_position = 0, - .underline_thickness = 0, -#endif - .dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ -#if LV_VERSION_CHECK(8, 2, 0) || LVGL_VERSION_MAJOR >= 9 - .fallback = NULL, -#endif - .user_data = NULL, -}; - - - -#endif /*#if MATERIAL_SYMBOLS_SHARED_48*/ - diff --git a/Modules/lvgl-module/source-fonts/material_symbols_shared_64.c b/Modules/lvgl-module/source-fonts/material_symbols_shared_64.c deleted file mode 100644 index 7c45bef5e..000000000 --- a/Modules/lvgl-module/source-fonts/material_symbols_shared_64.c +++ /dev/null @@ -1,3653 +0,0 @@ -/******************************************************************************* - * Size: 64 px - * Bpp: 2 - * Opts: --no-compress --no-prefilter --bpp 2 --size 64 --font MaterialSymbolsRounded.ttf -r 0xE145,0xE5C3,0xE770,0xEF40,0xEBCC,0xEFE6,0xEF4A,0xE5CD,0xF15C,0xE668,0xE92E,0xE326,0xEB97,0xE745,0xEC1C,0xE2C7,0xF720,0xF090,0xE8AF,0xE30F,0xE8FD,0xE9F4,0xE3F4,0xE316,0xE90F,0xEA07,0xE9B9,0xE159,0xE5D2,0xE28D,0xE5D4,0xE405,0xE89C,0xF8C7,0xE5D5,0xEF7A,0xE8B8,0xE9F7,0xE55D,0xF028,0xE1E0,0xE63E,0xE1A7,0xEB8E,0xEAD6,0xE3AF,0xFFF75 --format lvgl -o source-fonts/material_symbols_shared_64.c --force-fast-kern-format - ******************************************************************************/ - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -#ifndef MATERIAL_SYMBOLS_SHARED_64 -#define MATERIAL_SYMBOLS_SHARED_64 1 -#endif - -#if MATERIAL_SYMBOLS_SHARED_64 - -/*----------------- - * BITMAPS - *----------------*/ - -/*Store the image of the glyphs*/ -static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { - /* U+E145 "" */ - 0x0, 0x0, 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xfc, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, - 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xfe, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xe0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfe, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xe0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xfe, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xe0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xfe, 0x0, 0x0, 0x0, 0x0, - 0x5, 0x55, 0x55, 0x55, 0xff, 0xf5, 0x55, 0x55, - 0x55, 0x3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfc, 0xbf, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xdb, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc1, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xf4, 0x0, 0x0, 0x0, 0x0, 0xff, 0xe0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfe, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xe0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xfe, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xe0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xfe, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xe0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfe, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xb, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7f, 0xc0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x1, 0xf4, 0x0, 0x0, 0x0, - 0x0, - - /* U+E159 "" */ - 0x0, 0x15, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x40, 0x0, 0x7f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x80, 0x2f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xbf, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfd, 0xff, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0xdf, 0xff, - 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x1, 0xff, 0xfd, 0xff, 0xff, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0xdf, 0xff, 0xff, 0xc0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xbf, 0xff, 0xfd, 0xff, - 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x7f, 0xff, 0xff, 0xdf, 0xfe, 0xff, 0xff, - 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, - 0xef, 0xfd, 0xff, 0xd2, 0xff, 0xfe, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x1f, 0xff, 0xf4, 0xff, 0xdf, - 0xfd, 0x3, 0xff, 0xfd, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xff, 0xf8, 0xf, 0xfd, 0xff, 0xd0, 0x7, - 0xff, 0xfc, 0x0, 0x0, 0x0, 0xb, 0xff, 0xfc, - 0x0, 0xff, 0xdf, 0xfd, 0x0, 0xb, 0xff, 0xf8, - 0x0, 0x0, 0x7, 0xff, 0xfd, 0x0, 0xf, 0xfd, - 0xff, 0xd0, 0x0, 0x1f, 0xff, 0xf4, 0x0, 0x2, - 0xff, 0xfe, 0x0, 0x0, 0xff, 0xdf, 0xfd, 0x0, - 0x0, 0x2f, 0xff, 0xe0, 0x1, 0xff, 0xff, 0x40, - 0x0, 0xf, 0xfd, 0xff, 0xd0, 0x0, 0x0, 0x7f, - 0xff, 0xd0, 0xff, 0xff, 0x80, 0x0, 0x0, 0xff, - 0xdf, 0xfd, 0x0, 0x0, 0x0, 0xbf, 0xff, 0xff, - 0xff, 0xc0, 0x0, 0x0, 0xf, 0xfd, 0xff, 0xd0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xd0, 0x0, - 0x0, 0x0, 0xff, 0xdf, 0xfd, 0x0, 0x0, 0x0, - 0x1, 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, 0xf, - 0xfd, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x2, 0xff, - 0xf4, 0x0, 0x0, 0x0, 0x0, 0xff, 0xdf, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0x7, 0xf8, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xfd, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xdf, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0xff, - 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xdf, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xfd, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xdf, - 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xfd, 0xff, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xdf, 0xfd, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xdf, 0xfd, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xfd, 0xff, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xdf, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0xff, 0xd0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xdf, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdb, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xc2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x7, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf8, 0x0, 0x1, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x54, 0x0, - - /* U+E1A7 "" */ - 0x0, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xfe, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2, 0xff, 0x80, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xff, 0xe0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xff, 0xf8, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xff, 0xfe, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xff, 0xff, 0x80, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xff, 0xff, 0xe0, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xff, 0xff, 0xf8, 0x0, - 0x3f, 0x80, 0x0, 0x3, 0xff, 0xff, 0xfe, 0x0, - 0xbf, 0xf0, 0x0, 0x3, 0xff, 0xbf, 0xff, 0x80, - 0xbf, 0xfc, 0x0, 0x3, 0xff, 0x4f, 0xff, 0xe0, - 0x7f, 0xff, 0x0, 0x3, 0xff, 0x43, 0xff, 0xf8, - 0x2f, 0xff, 0xc0, 0x3, 0xff, 0x40, 0xbf, 0xfd, - 0xb, 0xff, 0xf0, 0x3, 0xff, 0x40, 0x3f, 0xff, - 0x2, 0xff, 0xfc, 0x3, 0xff, 0x40, 0x7f, 0xfe, - 0x0, 0xbf, 0xff, 0x3, 0xff, 0x41, 0xff, 0xfc, - 0x0, 0x2f, 0xff, 0xc3, 0xff, 0x47, 0xff, 0xf4, - 0x0, 0xb, 0xff, 0xf3, 0xff, 0x5f, 0xff, 0xd0, - 0x0, 0x2, 0xff, 0xff, 0xff, 0xbf, 0xff, 0x40, - 0x0, 0x0, 0xbf, 0xff, 0xff, 0xff, 0xfd, 0x0, - 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xf4, 0x0, - 0x0, 0x0, 0xb, 0xff, 0xff, 0xff, 0xd0, 0x0, - 0x0, 0x0, 0x2, 0xff, 0xff, 0xff, 0x40, 0x0, - 0x0, 0x0, 0x0, 0xbf, 0xff, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xff, 0xf4, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x1f, 0xff, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7f, 0xff, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0x1, 0xff, 0xff, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xff, 0xc0, 0x0, - 0x0, 0x0, 0x1f, 0xff, 0xff, 0xff, 0xf0, 0x0, - 0x0, 0x0, 0x7f, 0xff, 0xff, 0xff, 0xfc, 0x0, - 0x0, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, - 0x0, 0x7, 0xff, 0xf7, 0xff, 0x6f, 0xff, 0xc0, - 0x0, 0x1f, 0xff, 0xd3, 0xff, 0x4b, 0xff, 0xf0, - 0x0, 0x7f, 0xff, 0x43, 0xff, 0x42, 0xff, 0xfc, - 0x1, 0xff, 0xfd, 0x3, 0xff, 0x40, 0xbf, 0xfe, - 0x7, 0xff, 0xf4, 0x3, 0xff, 0x40, 0x3f, 0xff, - 0x1f, 0xff, 0xd0, 0x3, 0xff, 0x40, 0x7f, 0xfe, - 0x3f, 0xff, 0x40, 0x3, 0xff, 0x41, 0xff, 0xfc, - 0xbf, 0xfd, 0x0, 0x3, 0xff, 0x47, 0xff, 0xf0, - 0xbf, 0xf4, 0x0, 0x3, 0xff, 0x5f, 0xff, 0xc0, - 0x7f, 0xd0, 0x0, 0x3, 0xff, 0xff, 0xff, 0x0, - 0x1a, 0x0, 0x0, 0x3, 0xff, 0xff, 0xfc, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xff, 0xff, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xff, 0xff, 0xc0, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xff, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xff, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xff, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xff, 0xc0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x1, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x78, 0x0, 0x0, 0x0, - - /* U+E1E0 "" */ - 0x0, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xfc, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, - 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3, 0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xbf, 0xff, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, 0xff, 0x80, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xff, - 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, - 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xbf, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xbf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xa, - 0x90, 0x0, 0xb, 0xff, 0x0, 0x1a, 0xaa, 0xa8, - 0xb, 0xff, 0xc0, 0x0, 0xbf, 0xf0, 0x3, 0xff, - 0xff, 0xe2, 0xff, 0xff, 0x0, 0xb, 0xff, 0x0, - 0x3f, 0xff, 0xfe, 0x3f, 0xff, 0xf8, 0x0, 0xbf, - 0xf0, 0x3, 0xff, 0xff, 0xeb, 0xff, 0xff, 0xc0, - 0xb, 0xff, 0x0, 0x3f, 0xff, 0xfe, 0xbf, 0xff, - 0xfc, 0x0, 0xbf, 0xf0, 0x3, 0xff, 0xff, 0xeb, - 0xff, 0xff, 0xc0, 0xb, 0xff, 0x0, 0x3f, 0xff, - 0xfe, 0x7f, 0xff, 0xf8, 0x0, 0xbf, 0xf0, 0x3, - 0xff, 0xff, 0xe3, 0xff, 0xff, 0x0, 0xb, 0xff, - 0x0, 0x3f, 0xff, 0xfe, 0xf, 0xff, 0xc0, 0x0, - 0xbf, 0xf0, 0x3, 0xff, 0xff, 0xe0, 0x3f, 0xf4, - 0x0, 0xb, 0xff, 0x0, 0x2f, 0xff, 0xfd, 0x3, - 0xff, 0x40, 0x0, 0xbf, 0xf0, 0x0, 0x1f, 0xfc, - 0x0, 0x3f, 0xf4, 0x0, 0xb, 0xff, 0x0, 0x1, - 0xff, 0xc0, 0x3, 0xff, 0x40, 0x0, 0xbf, 0xf0, - 0x0, 0x1f, 0xfc, 0x0, 0x3f, 0xf4, 0x0, 0xb, - 0xff, 0x0, 0x1, 0xff, 0xc0, 0x3, 0xff, 0x40, - 0x0, 0xbf, 0xf0, 0x0, 0x1f, 0xfc, 0x0, 0x3f, - 0xfe, 0xaa, 0xaf, 0xff, 0xaa, 0xab, 0xff, 0xc0, - 0x3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfc, 0x0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x40, 0x0, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf0, 0x0, 0x3, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0x0, 0x0, 0x6, - 0xaa, 0xaa, 0xff, 0xfa, 0xaa, 0xa9, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xb, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xbf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xb, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xbf, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, 0x80, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, 0xfe, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xff, 0xf4, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xff, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, - 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x1a, 0x40, 0x0, 0x0, 0x0, 0x0, - - /* U+E28D "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x50, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0xf8, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0xff, 0xff, 0xc0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xff, - 0xff, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x2f, 0xfd, 0x7, 0xff, - 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3, 0xff, 0x80, 0x2f, 0xfc, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0xf4, 0x1, 0xff, 0xc0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, - 0xff, 0x40, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xf4, - 0x1, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0x40, 0x1f, - 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3f, 0xf4, 0x1, 0xff, 0xc0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3, 0xff, 0x40, 0x1f, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3f, 0xf4, 0x1, 0xff, 0xc0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, - 0x40, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xf4, 0x1, - 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xff, 0x40, 0x1f, 0xfc, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0xf4, 0x1, 0xff, 0xc0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3, 0xff, 0x40, 0x1f, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, - 0xf4, 0x1, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0x40, - 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3f, 0xf4, 0x1, 0xff, - 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3, 0xff, 0x40, 0x1f, 0xfc, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0xf4, 0x1, 0xff, 0xc0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, - 0xff, 0x40, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xf4, - 0x1, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x6, 0xaa, 0xaa, 0xab, 0xff, 0xea, 0xbf, - 0xfe, 0xaa, 0xaa, 0xa9, 0x0, 0x0, 0x0, 0x3, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfc, 0x0, 0x0, 0x0, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xf0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x80, 0x0, 0x3, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x0, - 0x0, 0x3f, 0xfe, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xab, 0xff, 0xc0, 0x0, 0x3, - 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x3f, 0xf4, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xff, 0xc0, 0x0, 0x3, 0xff, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, - 0xfc, 0x0, 0x0, 0x3f, 0xf4, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xc0, - 0x0, 0x3, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, - 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0, 0x7, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfd, 0x0, 0x0, 0xbf, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xe0, 0x0, 0xf, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0, - 0x1f, 0xfd, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x57, 0xff, 0x40, 0x2, 0xff, - 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0xf8, 0x0, 0x3f, 0xf8, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x2, 0xff, 0xc0, 0x3, 0xff, 0x40, 0xb, 0xd0, - 0x0, 0x2, 0xf8, 0x0, 0x0, 0x7e, 0x0, 0x1f, - 0xfc, 0x0, 0x7f, 0xf0, 0x2, 0xff, 0x0, 0x0, - 0x7f, 0xd0, 0x0, 0xf, 0xf8, 0x0, 0xff, 0xd0, - 0xb, 0xff, 0x0, 0x3f, 0xf4, 0x0, 0xb, 0xfe, - 0x0, 0x1, 0xff, 0xc0, 0xf, 0xfe, 0x0, 0xff, - 0xe0, 0x3, 0xff, 0x40, 0x0, 0xbf, 0xe0, 0x0, - 0x1f, 0xfc, 0x0, 0xbf, 0xf0, 0xf, 0xfd, 0x0, - 0x3f, 0xf4, 0x0, 0xb, 0xfe, 0x0, 0x1, 0xff, - 0xc0, 0x7, 0xff, 0x1, 0xff, 0xc0, 0x3, 0xff, - 0x40, 0x0, 0xbf, 0xe0, 0x0, 0x1f, 0xfc, 0x0, - 0x3f, 0xf4, 0x2f, 0xfc, 0x0, 0x3f, 0xf4, 0x0, - 0xb, 0xfe, 0x0, 0x1, 0xff, 0xc0, 0x3, 0xff, - 0x83, 0xff, 0x80, 0x3, 0xff, 0x40, 0x0, 0xbf, - 0xe0, 0x0, 0x1f, 0xfc, 0x0, 0x2f, 0xfc, 0x3f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xc2, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfc, 0xf, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x40, 0x7f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xe0, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x0, - 0x0, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x50, 0x0, - - /* U+E2C7 "" */ - 0x0, 0x15, 0x55, 0x55, 0x55, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, - 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, - 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xd0, 0x0, 0x0, 0x1, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, 0xf, 0xfd, - 0x0, 0x0, 0x0, 0x7, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xe0, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x8f, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x7f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, - 0xd0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xdf, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x1, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x5f, 0xfd, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xdf, - 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xfd, 0xff, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xdf, 0xfd, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xdf, 0xfd, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xfd, 0xff, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xdf, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0xff, 0xd0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xdf, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xfd, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xdf, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xfd, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xdf, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0xff, - 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xdf, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xfd, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xdf, - 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xfd, 0xff, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xdf, 0xfd, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xdf, 0xfd, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xfd, 0xff, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xdf, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0xff, 0xd0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xdf, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdb, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xc2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x7, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf8, 0x0, 0x1, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x54, 0x0, - - /* U+E30F "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x15, 0x55, 0x55, - 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, - 0xff, 0xff, 0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xff, 0xff, - 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3, 0xff, 0xff, 0xff, 0xfc, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3f, 0xff, 0xff, 0xff, 0xc0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0x0, - 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3f, 0xf0, 0x1, 0xff, 0xc0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3, 0xff, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xf0, - 0x1, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xff, 0x0, 0x1f, 0xfc, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0xf0, 0x1, 0xff, 0xc0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, - 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3f, 0xf8, 0x3, 0xff, - 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3, 0xff, 0xf0, 0xff, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, - 0xff, 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xff, 0xff, - 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x2, 0xff, 0xff, 0xf4, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xb, 0xff, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x2, 0xff, 0xff, 0xff, 0xd0, 0x0, 0x2f, 0xff, - 0x40, 0x0, 0x7f, 0xff, 0xff, 0xf4, 0xbf, 0xff, - 0xff, 0xff, 0x40, 0x0, 0xbf, 0xd0, 0x0, 0x2f, - 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xfd, - 0x0, 0x1, 0xf4, 0x0, 0xb, 0xff, 0xff, 0xff, - 0xfd, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x0, 0x0, - 0x0, 0x2, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, - 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, 0x0, 0xbf, - 0xff, 0xff, 0xff, 0xfd, 0xff, 0xe5, 0x55, 0x7f, - 0xff, 0x40, 0x0, 0x0, 0x2f, 0xff, 0xd5, 0x55, - 0xff, 0xdf, 0xfd, 0x0, 0x1, 0xff, 0xfc, 0x0, - 0x0, 0x7, 0xff, 0xf0, 0x0, 0xf, 0xfd, 0xff, - 0xd0, 0x0, 0x7, 0xff, 0xe0, 0x0, 0x0, 0xff, - 0xfc, 0x0, 0x0, 0xff, 0xdf, 0xfd, 0x0, 0x0, - 0x7f, 0xfe, 0x0, 0x0, 0xf, 0xff, 0xc0, 0x0, - 0xf, 0xfd, 0xff, 0xd0, 0x0, 0x1f, 0xff, 0xc0, - 0x0, 0x0, 0x7f, 0xff, 0x0, 0x0, 0xff, 0xdf, - 0xfe, 0x55, 0x57, 0xff, 0xf4, 0x0, 0x0, 0x2, - 0xff, 0xfd, 0x55, 0x5f, 0xfd, 0xff, 0xff, 0xff, - 0xff, 0xfd, 0x0, 0x0, 0x0, 0xb, 0xff, 0xff, - 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0x40, - 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xfd, - 0xff, 0xff, 0xff, 0xff, 0xd0, 0x0, 0x1e, 0x40, - 0x0, 0xbf, 0xff, 0xff, 0xff, 0xdb, 0xff, 0xff, - 0xff, 0xf4, 0x0, 0xb, 0xfd, 0x0, 0x2, 0xff, - 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xfc, 0x0, - 0x2, 0xff, 0xf4, 0x0, 0x7, 0xff, 0xff, 0xff, - 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xff, - 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xb, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0xff, - 0xff, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3f, 0xff, 0x1f, 0xff, 0xc0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3, 0xff, 0xc0, 0x7f, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xf0, - 0x1, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xff, 0x0, 0x1f, 0xfc, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0xf0, 0x1, 0xff, 0xc0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, - 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3f, 0xf0, 0x1, 0xff, - 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3, 0xff, 0x0, 0x1f, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, - 0xf0, 0x1, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0x95, 0x6f, - 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0xff, 0xff, 0xff, 0xc0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, - 0xff, 0xff, 0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xff, 0xff, - 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3, 0xff, 0xff, 0xff, 0xf8, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xb, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, - 0x0, - - /* U+E316 "" */ - 0x0, 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3, 0xfc, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x3, - 0xff, 0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x3f, 0xff, - 0x5f, 0xff, 0xc0, 0x0, 0x0, 0xf, 0xff, 0xd0, - 0x7f, 0xff, 0x0, 0x0, 0x3, 0xff, 0xf4, 0x1, - 0xff, 0xfc, 0x0, 0x0, 0xff, 0xfd, 0x0, 0x7, - 0xff, 0xf0, 0x0, 0x3f, 0xff, 0x40, 0x0, 0x1f, - 0xff, 0xc0, 0xf, 0xff, 0xd0, 0x0, 0x0, 0x7f, - 0xff, 0x3, 0xff, 0xf4, 0x0, 0x0, 0x1, 0xff, - 0xfc, 0xbf, 0xfd, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xef, 0xff, 0x40, 0x0, 0x0, 0x0, 0x1f, 0xff, - 0xbf, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xe2, - 0xf4, 0x0, 0x0, 0x0, 0x0, 0x1, 0xf8, - - /* U+E326 "" */ - 0x0, 0x0, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x40, 0x0, 0x1, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x0, 0x0, 0xbf, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, - 0x0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x3, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xf4, 0x0, 0x3f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0x0, 0x3, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, - 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0xf4, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, - 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xf4, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x15, 0x55, 0x55, - 0x55, 0x40, 0x3, 0xff, 0x40, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0x0, - 0x3f, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0x3, 0xff, 0x40, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xff, 0xff, - 0xff, 0xff, 0xd0, 0x3f, 0xf4, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0x3, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xd0, 0x3f, 0xf4, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0x0, - 0x0, 0xf, 0xfd, 0x3, 0xff, 0x40, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, 0xff, - 0xd0, 0x3f, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xfd, 0x0, 0x50, 0xf, 0xfd, 0x3, 0xff, - 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xd0, - 0x3f, 0x40, 0xff, 0xd0, 0x3f, 0xf4, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xfd, 0x3, 0xf8, 0xf, - 0xfd, 0x3, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xd0, 0x3f, 0x40, 0xff, 0xd0, 0x3f, - 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, - 0x0, 0x40, 0xf, 0xfd, 0x3, 0xff, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, - 0xff, 0xd0, 0x3f, 0xf4, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xfd, 0x0, 0x0, 0xf, 0xfd, 0x3, - 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xd0, 0x0, 0x0, 0xff, 0xd0, 0x3f, 0xf4, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0x0, 0x0, - 0xf, 0xfd, 0x3, 0xff, 0x40, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, 0xff, 0xd0, - 0x3f, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xfd, 0x0, 0x0, 0xf, 0xfd, 0x3, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xe0, 0x0, 0xff, 0xd0, 0x0, - 0x0, 0xff, 0xd0, 0x3f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x80, 0xf, 0xfd, 0x0, 0x0, 0xf, 0xfd, - 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x0, - 0xff, 0xd0, 0x0, 0x0, 0xff, 0xd0, 0xb, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xc0, 0xf, 0xfd, 0x0, - 0x0, 0xf, 0xfd, 0x0, 0x1f, 0xff, 0xff, 0xff, - 0xff, 0xf4, 0x0, 0xff, 0xd0, 0x0, 0x0, 0xff, - 0xd0, 0x0, 0x5, 0x55, 0x55, 0x55, 0x54, 0x0, - 0xf, 0xfd, 0x0, 0x0, 0xf, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xd0, - 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xfd, 0x0, 0x0, 0xf, - 0xfd, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, - 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd7, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0xf, 0xff, - 0xff, 0xff, 0xff, 0xfd, 0xbf, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfc, 0x0, 0xbf, 0xff, 0xff, 0xff, - 0xff, 0xd7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xc0, 0x7, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x3f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x0, 0x1f, - 0xff, 0xff, 0xff, 0xfe, 0x0, 0x15, 0x55, 0x55, - 0x55, 0x55, 0x54, 0x0, 0x0, 0x15, 0x55, 0x55, - 0x55, 0x0, - - /* U+E3AF "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x55, 0x50, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x1b, 0xff, 0xff, 0xfe, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6f, - 0xff, 0xff, 0xff, 0xff, 0x90, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x40, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xe4, 0x0, - 0x1f, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, - 0x3, 0xff, 0xff, 0x80, 0x0, 0x3, 0xf0, 0x6f, - 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, - 0x80, 0x0, 0x0, 0xbe, 0x0, 0x2f, 0xff, 0xf0, - 0x0, 0x0, 0x0, 0x3f, 0xff, 0xc0, 0x0, 0x0, - 0xf, 0xc0, 0x0, 0x7f, 0xff, 0x80, 0x0, 0x0, - 0xf, 0xff, 0xe0, 0x0, 0x0, 0x2, 0xf4, 0x0, - 0x0, 0xbf, 0xfe, 0x0, 0x0, 0x2, 0xff, 0xf4, - 0x0, 0x0, 0x0, 0x7f, 0x0, 0x0, 0x2, 0xff, - 0xf4, 0x0, 0x0, 0x7f, 0xff, 0x40, 0x0, 0x0, - 0xf, 0xc0, 0x0, 0x0, 0xb, 0xff, 0xc0, 0x0, - 0xf, 0xff, 0xfc, 0x0, 0x0, 0x1, 0xf8, 0x0, - 0x0, 0x0, 0x2f, 0xfe, 0x0, 0x2, 0xff, 0xfb, - 0xd0, 0x0, 0x0, 0x3f, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xf4, 0x0, 0x3f, 0xfc, 0x3f, 0x0, 0x0, - 0xb, 0xd0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xc0, - 0xb, 0xff, 0x41, 0xf8, 0x0, 0x1, 0xfc, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xfd, 0x0, 0xff, 0xf0, - 0xf, 0xc0, 0x0, 0x3f, 0x40, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xe0, 0x1f, 0xfd, 0x0, 0x7f, 0x0, - 0x7, 0xf8, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, - 0x2, 0xff, 0xc0, 0x2, 0xf4, 0x0, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x3f, 0xf8, - 0x0, 0xf, 0xc0, 0x2f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x83, 0xff, 0x40, 0x0, 0xbe, - 0x3, 0xff, 0xff, 0xff, 0xea, 0xaa, 0xaa, 0xbf, - 0xfc, 0x7f, 0xf0, 0x0, 0x3, 0xf4, 0xff, 0xff, - 0xff, 0xf0, 0x0, 0x0, 0x1, 0xff, 0xc7, 0xff, - 0x0, 0x0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0x0, - 0x0, 0x0, 0xf, 0xfd, 0xbf, 0xe0, 0x0, 0x0, - 0xff, 0xff, 0xff, 0xff, 0xf8, 0x0, 0x0, 0x0, - 0xff, 0xdb, 0xfe, 0x0, 0x0, 0x3, 0xff, 0xff, - 0xff, 0xff, 0xc0, 0x0, 0x0, 0xf, 0xfd, 0xbf, - 0xe0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, - 0x0, 0x0, 0x0, 0xff, 0xef, 0xfe, 0x0, 0x0, - 0x0, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x0, 0x0, - 0xf, 0xfe, 0xbf, 0xe0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xff, 0xff, 0xc0, 0x0, 0x0, 0xff, 0xeb, - 0xfe, 0x0, 0x0, 0x0, 0x3f, 0xff, 0xff, 0xff, - 0xfe, 0x0, 0x0, 0xf, 0xfd, 0xbf, 0xf0, 0x0, - 0x0, 0x1, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0, - 0x0, 0xff, 0xd7, 0xff, 0x0, 0x0, 0x0, 0x1f, - 0xff, 0xff, 0xfe, 0x1f, 0x80, 0x0, 0x1f, 0xfc, - 0x3f, 0xfa, 0xaa, 0xaa, 0xab, 0xff, 0xff, 0xff, - 0xc0, 0xfd, 0x0, 0x1, 0xff, 0xc3, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x3, 0xf0, - 0x0, 0x3f, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x0, 0x2f, 0x40, 0x3, 0xff, - 0x81, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x3f, - 0xd0, 0x0, 0xfc, 0x0, 0xbf, 0xf0, 0xf, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x2, 0xf8, 0x0, 0x7, - 0xe0, 0xf, 0xff, 0x0, 0xbf, 0xf4, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0x0, 0x0, 0x3f, 0x2, 0xff, - 0xd0, 0x3, 0xff, 0xc0, 0x0, 0x0, 0x0, 0xb, - 0xe0, 0x0, 0x1, 0xfc, 0x7f, 0xfc, 0x0, 0x2f, - 0xfe, 0x0, 0x0, 0x0, 0x0, 0xfc, 0x0, 0x0, - 0xf, 0xdf, 0xff, 0x80, 0x0, 0xff, 0xf4, 0x0, - 0x0, 0x0, 0x3f, 0x40, 0x0, 0x0, 0x3f, 0xff, - 0xf0, 0x0, 0xb, 0xff, 0xd0, 0x0, 0x0, 0x7, - 0xf0, 0x0, 0x0, 0x2, 0xff, 0xfd, 0x0, 0x0, - 0x3f, 0xff, 0x40, 0x0, 0x0, 0xfd, 0x0, 0x0, - 0x0, 0x1f, 0xff, 0x80, 0x0, 0x0, 0xff, 0xfd, - 0x0, 0x0, 0x2f, 0x80, 0x0, 0x0, 0xb, 0xff, - 0xf0, 0x0, 0x0, 0x7, 0xff, 0xf8, 0x0, 0x3, - 0xf0, 0x0, 0x0, 0x2, 0xff, 0xfc, 0x0, 0x0, - 0x0, 0x1f, 0xff, 0xf4, 0x0, 0xbe, 0x0, 0x0, - 0x1, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x7f, - 0xff, 0xf4, 0xf, 0xc0, 0x0, 0x1, 0xff, 0xff, - 0xd0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xff, 0xfb, - 0xf4, 0x0, 0x6, 0xff, 0xff, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x3, 0xff, 0xff, 0xff, 0xaa, 0xaf, - 0xff, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xff, 0xfd, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x6b, 0xfe, 0x94, 0x0, 0x0, 0x0, 0x0, - 0x0, - - /* U+E3F4 "" */ - 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x80, 0x1f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, - 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfc, 0xbf, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xe5, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x5b, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3c, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x1, - 0x40, 0x0, 0x2, 0xff, 0x80, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x7, 0xd0, 0x0, 0x7, 0xff, - 0xd0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0xf, - 0xf0, 0x0, 0xf, 0xff, 0xf0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x3f, 0xfc, 0x0, 0x3f, 0xff, - 0xfc, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0xbf, - 0xfe, 0x0, 0xbf, 0xff, 0xfe, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x1, 0xff, 0xff, 0x41, 0xff, 0xff, - 0xff, 0x40, 0x7, 0xff, 0xff, 0xd0, 0x3, 0xff, - 0xff, 0xc3, 0xff, 0xff, 0xff, 0xc0, 0x7, 0xff, - 0xff, 0xd0, 0xf, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xf0, 0x7, 0xff, 0xff, 0xd0, 0x2f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x7, 0xff, - 0xff, 0xd0, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xf4, 0x7, 0xff, 0xff, 0xd0, 0x5, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x50, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xe5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x5b, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, - 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf4, 0x2, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, - - /* U+E405 "" */ - 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xf8, - 0x0, 0x0, 0x0, 0x0, 0xbf, 0xff, 0xff, 0xfe, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xfe, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xfa, 0xaa, 0xa4, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x5, 0x0, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x7, 0xff, 0xf8, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x7f, 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x1, 0xff, 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x7, 0xff, 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0xf, 0xff, 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x3f, 0xff, 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x7f, 0xff, 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0xbf, 0xff, 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0, 0x0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0, 0x0, - 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0, 0x0, - 0x3f, 0xff, 0xff, 0xff, 0xff, 0x40, 0x0, 0x0, - 0x2f, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, - 0xf, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x0, - 0x3, 0xff, 0xff, 0xff, 0xf4, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x2f, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x1, 0xff, 0xe4, 0x0, 0x0, 0x0, 0x0, - - /* U+E55D "" */ - 0x0, 0x0, 0x0, 0x0, 0x1, 0xa4, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, - 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, - 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3, 0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xbf, 0xff, 0xe0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, - 0xff, 0xff, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0xff, 0xff, 0xc0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, 0xaf, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xf0, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xfe, 0xb, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2, 0xff, 0xc0, 0x3f, 0xf8, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xf8, - 0x2, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xb, 0xff, 0x40, 0x1f, 0xfe, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xf0, 0x0, 0xff, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfd, 0x0, - 0x7, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, 0x3, - 0xff, 0xc0, 0x0, 0x3f, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7f, 0xf8, 0x0, 0x2, 0xff, 0xd0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0x0, 0x0, - 0xf, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xe0, 0x0, 0x0, 0xbf, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x2f, 0xfc, 0x0, 0x0, 0x3, 0xff, 0x80, - 0x0, 0x0, 0x0, 0x3, 0xff, 0x80, 0x0, 0x0, - 0x2f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xf4, - 0x0, 0x0, 0x1, 0xff, 0xe0, 0x0, 0x0, 0x0, - 0xf, 0xff, 0x0, 0x0, 0x0, 0xf, 0xff, 0x0, - 0x0, 0x0, 0x1, 0xff, 0xd0, 0x0, 0x0, 0x0, - 0x7f, 0xf4, 0x0, 0x0, 0x0, 0x3f, 0xfc, 0x0, - 0x0, 0x0, 0x3, 0xff, 0xc0, 0x0, 0x0, 0x7, - 0xff, 0x40, 0x0, 0x0, 0x0, 0x1f, 0xfd, 0x0, - 0x0, 0x0, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xf0, 0x0, 0x0, 0xf, 0xfe, 0x0, 0x0, - 0x0, 0x0, 0xb, 0xff, 0x0, 0x0, 0x2, 0xff, - 0xc0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xf8, 0x0, - 0x0, 0x3f, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x2, - 0xff, 0xc0, 0x0, 0xb, 0xff, 0x40, 0x0, 0xa, - 0x0, 0x0, 0x1f, 0xfe, 0x0, 0x0, 0xff, 0xf0, - 0x0, 0x1f, 0xff, 0x40, 0x0, 0xff, 0xf0, 0x0, - 0x1f, 0xfd, 0x0, 0x2f, 0xff, 0xff, 0x80, 0x7, - 0xff, 0x40, 0x3, 0xff, 0xc0, 0x2f, 0xff, 0xff, - 0xff, 0x80, 0x3f, 0xfc, 0x0, 0x7f, 0xf4, 0x7f, - 0xff, 0xff, 0xff, 0xff, 0xd1, 0xff, 0xd0, 0xf, - 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, - 0xff, 0x0, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xbf, - 0xff, 0xff, 0xff, 0xf0, 0x2f, 0xff, 0xff, 0xff, - 0xd0, 0x0, 0x7f, 0xff, 0xff, 0xff, 0x83, 0xff, - 0xff, 0xff, 0xd0, 0x0, 0x0, 0x7f, 0xff, 0xff, - 0xfc, 0xbf, 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, - 0x2f, 0xff, 0xff, 0xef, 0xff, 0xff, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x1f, 0xff, 0xff, 0xff, 0xff, - 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, - 0xf7, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xb, 0xfd, 0x9, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x6, 0x0, - - /* U+E5C3 "" */ - 0x0, 0x55, 0x0, 0x0, 0x0, 0x55, 0x0, 0x0, - 0x0, 0x55, 0x0, 0x3, 0xff, 0xd0, 0x0, 0x3, - 0xff, 0xd0, 0x0, 0x3, 0xff, 0xd0, 0xf, 0xff, - 0xf4, 0x0, 0xf, 0xff, 0xf4, 0x0, 0xf, 0xff, - 0xf4, 0x2f, 0xff, 0xfc, 0x0, 0x2f, 0xff, 0xfc, - 0x0, 0x2f, 0xff, 0xfc, 0x3f, 0xff, 0xfc, 0x0, - 0x3f, 0xff, 0xfc, 0x0, 0x3f, 0xff, 0xfc, 0x3f, - 0xff, 0xfd, 0x0, 0x3f, 0xff, 0xfd, 0x0, 0x3f, - 0xff, 0xfd, 0x3f, 0xff, 0xfd, 0x0, 0x3f, 0xff, - 0xfd, 0x0, 0x3f, 0xff, 0xfd, 0x3f, 0xff, 0xfc, - 0x0, 0x3f, 0xff, 0xfc, 0x0, 0x3f, 0xff, 0xfc, - 0x1f, 0xff, 0xf8, 0x0, 0x1f, 0xff, 0xf8, 0x0, - 0x1f, 0xff, 0xf8, 0xb, 0xff, 0xf0, 0x0, 0xb, - 0xff, 0xf0, 0x0, 0xb, 0xff, 0xf0, 0x1, 0xff, - 0x80, 0x0, 0x1, 0xff, 0x80, 0x0, 0x1, 0xff, - 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x55, 0x0, 0x0, 0x0, 0x55, 0x0, 0x0, - 0x0, 0x55, 0x0, 0x3, 0xff, 0xd0, 0x0, 0x3, - 0xff, 0xd0, 0x0, 0x3, 0xff, 0xd0, 0xf, 0xff, - 0xf4, 0x0, 0xf, 0xff, 0xf4, 0x0, 0xf, 0xff, - 0xf4, 0x2f, 0xff, 0xfc, 0x0, 0x2f, 0xff, 0xfc, - 0x0, 0x2f, 0xff, 0xfc, 0x3f, 0xff, 0xfc, 0x0, - 0x3f, 0xff, 0xfc, 0x0, 0x3f, 0xff, 0xfc, 0x3f, - 0xff, 0xfd, 0x0, 0x3f, 0xff, 0xfd, 0x0, 0x3f, - 0xff, 0xfd, 0x3f, 0xff, 0xfd, 0x0, 0x3f, 0xff, - 0xfd, 0x0, 0x3f, 0xff, 0xfd, 0x3f, 0xff, 0xfc, - 0x0, 0x3f, 0xff, 0xfc, 0x0, 0x3f, 0xff, 0xfc, - 0x1f, 0xff, 0xf8, 0x0, 0x1f, 0xff, 0xf8, 0x0, - 0x1f, 0xff, 0xf8, 0xb, 0xff, 0xf0, 0x0, 0xb, - 0xff, 0xf0, 0x0, 0xb, 0xff, 0xf0, 0x1, 0xff, - 0x80, 0x0, 0x1, 0xff, 0x80, 0x0, 0x1, 0xff, - 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x55, 0x0, 0x0, 0x0, 0x55, 0x0, 0x0, - 0x0, 0x55, 0x0, 0x3, 0xff, 0xd0, 0x0, 0x3, - 0xff, 0xd0, 0x0, 0x3, 0xff, 0xd0, 0xf, 0xff, - 0xf4, 0x0, 0xf, 0xff, 0xf4, 0x0, 0xf, 0xff, - 0xf4, 0x2f, 0xff, 0xfc, 0x0, 0x2f, 0xff, 0xfc, - 0x0, 0x2f, 0xff, 0xfc, 0x3f, 0xff, 0xfc, 0x0, - 0x3f, 0xff, 0xfc, 0x0, 0x3f, 0xff, 0xfc, 0x3f, - 0xff, 0xfd, 0x0, 0x3f, 0xff, 0xfd, 0x0, 0x3f, - 0xff, 0xfd, 0x3f, 0xff, 0xfd, 0x0, 0x3f, 0xff, - 0xfd, 0x0, 0x3f, 0xff, 0xfd, 0x3f, 0xff, 0xfc, - 0x0, 0x3f, 0xff, 0xfc, 0x0, 0x3f, 0xff, 0xfc, - 0x1f, 0xff, 0xf8, 0x0, 0x1f, 0xff, 0xf8, 0x0, - 0x1f, 0xff, 0xf8, 0xb, 0xff, 0xf0, 0x0, 0xb, - 0xff, 0xf0, 0x0, 0xb, 0xff, 0xf0, 0x1, 0xff, - 0x80, 0x0, 0x1, 0xff, 0x80, 0x0, 0x1, 0xff, - 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, - - /* U+E5CD "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x40, 0x3f, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x7, 0xf8, 0xbf, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x1f, 0xfc, 0xbf, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7f, 0xfd, 0x7f, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x1, 0xff, 0xfc, 0x2f, 0xff, 0xc0, - 0x0, 0x0, 0x0, 0x7, 0xff, 0xf4, 0xb, 0xff, - 0xf0, 0x0, 0x0, 0x0, 0x1f, 0xff, 0xd0, 0x2, - 0xff, 0xfc, 0x0, 0x0, 0x0, 0x7f, 0xff, 0x40, - 0x0, 0xbf, 0xff, 0x0, 0x0, 0x1, 0xff, 0xfd, - 0x0, 0x0, 0x2f, 0xff, 0xc0, 0x0, 0x7, 0xff, - 0xf4, 0x0, 0x0, 0xb, 0xff, 0xf0, 0x0, 0x1f, - 0xff, 0xd0, 0x0, 0x0, 0x2, 0xff, 0xfc, 0x0, - 0x7f, 0xff, 0x40, 0x0, 0x0, 0x0, 0xbf, 0xff, - 0x1, 0xff, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x2f, - 0xff, 0xc7, 0xff, 0xf4, 0x0, 0x0, 0x0, 0x0, - 0xb, 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x2, 0xff, 0xff, 0xff, 0x40, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xbf, 0xff, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, 0xf4, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, - 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, - 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, - 0xff, 0xff, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, - 0x1f, 0xff, 0xdb, 0xff, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x7f, 0xff, 0x42, 0xff, 0xfc, 0x0, 0x0, - 0x0, 0x1, 0xff, 0xfd, 0x0, 0xbf, 0xff, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xf4, 0x0, 0x2f, 0xff, - 0xc0, 0x0, 0x0, 0x1f, 0xff, 0xd0, 0x0, 0xb, - 0xff, 0xf0, 0x0, 0x0, 0x7f, 0xff, 0x40, 0x0, - 0x2, 0xff, 0xfc, 0x0, 0x1, 0xff, 0xfd, 0x0, - 0x0, 0x0, 0xbf, 0xff, 0x0, 0x7, 0xff, 0xf4, - 0x0, 0x0, 0x0, 0x2f, 0xff, 0xc0, 0x1f, 0xff, - 0xd0, 0x0, 0x0, 0x0, 0xb, 0xff, 0xf0, 0x3f, - 0xff, 0x40, 0x0, 0x0, 0x0, 0x2, 0xff, 0xf8, - 0xbf, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, - 0xfc, 0xbf, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x2f, 0xfc, 0x7f, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xb, 0xfc, 0x1a, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x1, 0xa0, - - /* U+E5D2 "" */ - 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf8, 0xbf, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfd, 0x5, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x50, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x5, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x50, - 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x50, 0x7f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0x2f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, - - /* U+E5D4 "" */ - 0x0, 0x55, 0x0, 0x3, 0xff, 0xd0, 0xf, 0xff, - 0xf4, 0x2f, 0xff, 0xfc, 0x3f, 0xff, 0xfc, 0x3f, - 0xff, 0xfd, 0x3f, 0xff, 0xfd, 0x3f, 0xff, 0xfc, - 0x1f, 0xff, 0xf8, 0xb, 0xff, 0xf0, 0x1, 0xff, - 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x55, 0x0, 0x3, 0xff, 0xd0, 0xf, 0xff, - 0xf4, 0x2f, 0xff, 0xfc, 0x3f, 0xff, 0xfc, 0x3f, - 0xff, 0xfd, 0x3f, 0xff, 0xfd, 0x3f, 0xff, 0xfc, - 0x1f, 0xff, 0xf8, 0xb, 0xff, 0xf0, 0x1, 0xff, - 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x55, 0x0, 0x3, 0xff, 0xd0, 0xf, 0xff, - 0xf4, 0x2f, 0xff, 0xfc, 0x3f, 0xff, 0xfc, 0x3f, - 0xff, 0xfd, 0x3f, 0xff, 0xfd, 0x3f, 0xff, 0xfc, - 0x1f, 0xff, 0xf8, 0xb, 0xff, 0xf0, 0x1, 0xff, - 0x80, 0x0, 0x0, 0x0, - - /* U+E5D5 "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x54, 0x0, 0x0, - 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x1, 0xbf, - 0xff, 0xfe, 0x40, 0x0, 0x7, 0xf8, 0x0, 0x0, - 0x0, 0x2f, 0xff, 0xff, 0xff, 0xf8, 0x0, 0xf, - 0xfc, 0x0, 0x0, 0x2, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x80, 0xf, 0xfd, 0x0, 0x0, 0x1f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xf4, 0xf, 0xfd, 0x0, - 0x0, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0xf, 0xfd, 0x0, 0x2, 0xff, 0xff, 0xe4, 0x0, - 0x1b, 0xff, 0xff, 0x8f, 0xfd, 0x0, 0xb, 0xff, - 0xfd, 0x0, 0x0, 0x0, 0x7f, 0xff, 0xef, 0xfd, - 0x0, 0x2f, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x7, - 0xff, 0xff, 0xfd, 0x0, 0x7f, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0xfd, 0x0, 0xff, - 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xff, - 0xfd, 0x2, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xff, 0xfd, 0x3, 0xff, 0xc0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xfd, 0xb, - 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, - 0xff, 0xfd, 0xf, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x1f, 0xff, 0xff, 0xff, 0xfd, 0x1f, 0xfd, 0x0, - 0x0, 0x0, 0x0, 0x3f, 0xff, 0xff, 0xff, 0xfd, - 0x2f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, - 0xff, 0xff, 0xfd, 0x3f, 0xf8, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0xff, 0xff, 0xff, 0xfc, 0x3f, 0xf4, - 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff, - 0xf8, 0x3f, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x1, - 0x55, 0x55, 0x55, 0x40, 0x7f, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7f, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3f, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3f, 0xf4, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xf8, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x2f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0x0, 0xf, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xc0, 0xb, 0xff, 0x40, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x1, 0xff, 0xd0, 0x3, 0xff, 0xc0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xc0, - 0x2, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xff, 0x80, 0x0, 0xff, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3f, 0xff, 0x0, 0x0, 0x7f, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xfd, - 0x0, 0x0, 0x2f, 0xff, 0xd0, 0x0, 0x0, 0x0, - 0x7, 0xff, 0xf4, 0x0, 0x0, 0xb, 0xff, 0xfd, - 0x0, 0x0, 0x0, 0x7f, 0xff, 0xe0, 0x0, 0x0, - 0x2, 0xff, 0xff, 0xe4, 0x0, 0x1b, 0xff, 0xff, - 0x80, 0x0, 0x0, 0x0, 0xbf, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x1f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x0, 0x0, - 0x0, 0x0, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, - 0xff, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x1, 0xbf, 0xff, 0xfe, 0x40, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x54, 0x0, - 0x0, 0x0, 0x0, 0x0, - - /* U+E63E "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x6b, 0xff, 0xff, - 0xfe, 0x90, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x6, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xf9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x90, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x2f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x2f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x80, 0x0, 0x0, 0xf, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x40, 0x0, 0x7, 0xff, 0xff, 0xff, - 0xff, 0xe5, 0x0, 0x0, 0x5, 0xbf, 0xff, 0xff, - 0xff, 0xfe, 0x0, 0x2, 0xff, 0xff, 0xff, 0xfe, - 0x40, 0x0, 0x0, 0x0, 0x0, 0x1b, 0xff, 0xff, - 0xff, 0xfc, 0x0, 0xff, 0xff, 0xff, 0xfd, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, 0xff, - 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0xff, - 0xff, 0xc3, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0xff, - 0xfd, 0x3f, 0xff, 0xfd, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, 0xff, - 0xd3, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0xfc, - 0x1f, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, 0x80, - 0x7f, 0xd0, 0x0, 0x0, 0x0, 0x6, 0xff, 0xff, - 0xf9, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xe0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff, - 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, - 0xff, 0xfe, 0x40, 0x0, 0x1b, 0xff, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xff, - 0xf9, 0x0, 0x0, 0x0, 0x2, 0xff, 0xff, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, 0xf8, - 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0xfe, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0x80, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x14, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x1, 0x40, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, - 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, 0xfe, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xff, 0xf8, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3f, 0xff, 0xff, 0xc0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7, 0xff, 0xff, 0xfd, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xbf, 0xff, 0xff, 0xe0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xb, 0xff, 0xff, 0xfe, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7f, 0xff, 0xff, 0xe0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0xff, 0xff, 0xc0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0xf4, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3, 0xff, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x7, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, - - /* U+E668 "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x2f, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xb, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0xe0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xbf, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x2f, 0xff, 0xc0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, - 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xbf, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xff, 0xc0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, - 0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xbf, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, 0xc0, 0x0, - 0x1, 0xf4, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, - 0xf0, 0x0, 0x0, 0x3f, 0xe0, 0x0, 0x0, 0x0, - 0x2, 0xff, 0xfc, 0x0, 0x0, 0xb, 0xff, 0x80, - 0x0, 0x0, 0x0, 0xbf, 0xff, 0x0, 0x0, 0x0, - 0xbf, 0xfe, 0x0, 0x0, 0x0, 0x2f, 0xff, 0xc0, - 0x0, 0x0, 0x3, 0xff, 0xf8, 0x0, 0x0, 0xb, - 0xff, 0xf0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xe0, - 0x0, 0x2, 0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, - 0x3f, 0xff, 0x80, 0x0, 0xbf, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xfe, 0x0, 0x2f, 0xff, - 0xc0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xf8, - 0xb, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xff, 0xe2, 0xff, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3f, 0xff, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, - 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xff, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2, 0xe0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, - - /* U+E745 "" */ - 0x1, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf4, 0x0, 0x0, 0x0, 0x0, - 0x3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x54, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x64, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, - 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x1, 0xff, 0xfc, 0x0, 0xff, 0xff, - 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, 0x1, 0xff, - 0xff, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0, - 0x0, 0x0, 0x1, 0xff, 0xff, 0xfc, 0x3f, 0xff, - 0xff, 0xff, 0xfd, 0x0, 0x0, 0x0, 0x1, 0xff, - 0xff, 0xff, 0x4f, 0xff, 0xff, 0xff, 0xff, 0x0, - 0x0, 0x0, 0x1, 0xff, 0xff, 0xff, 0xe1, 0xff, - 0xff, 0xff, 0xff, 0x80, 0x0, 0x0, 0x1, 0xff, - 0xff, 0xff, 0xf8, 0x5, 0x55, 0x55, 0x55, 0x0, - 0x0, 0x0, 0x1, 0xff, 0xff, 0xff, 0xfd, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, - 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x2, 0xff, 0xc3, 0xff, 0xfe, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, - 0xc0, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x2, 0xff, 0xc0, 0xf, 0xfe, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, - 0xc0, 0xf, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x2, 0xff, 0xc0, 0xf, 0xfe, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, - 0xc0, 0xf, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xc0, 0xf, 0xfe, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, - 0xc0, 0xf, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xf0, 0xf, 0xfe, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, - 0xfc, 0xf, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xfe, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3f, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xfe, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, - - /* U+E770 "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xa4, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x1f, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xff, 0xe0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x7, 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0x4f, 0xff, - 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3f, 0xff, 0x2, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7f, 0xfc, 0x0, 0x7f, - 0xff, 0xd5, 0x54, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xf4, 0x0, 0xf, 0xff, 0xff, 0xff, 0xd0, - 0x0, 0x0, 0x0, 0x3, 0xff, 0xe0, 0x0, 0x3, - 0xff, 0xff, 0xff, 0xf8, 0x1a, 0x0, 0x0, 0xb, - 0xff, 0xc0, 0x0, 0x0, 0xbf, 0xff, 0xff, 0xfd, - 0xbf, 0xc0, 0x0, 0x1f, 0xff, 0x0, 0x0, 0x0, - 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x0, 0x3f, - 0xfd, 0x0, 0x0, 0x0, 0x3, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0x0, 0xff, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xff, 0xc2, 0xff, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xff, 0xfb, 0xff, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xef, 0xff, 0xfc, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd3, 0xff, 0xf4, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0xbf, 0xf0, - 0x0, 0x2, 0xc0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x1f, 0xc0, 0x0, 0x7, 0xf4, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x3, 0x40, - 0x0, 0xf, 0xfe, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x3f, 0xff, 0xc0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0xbf, 0xff, 0xf4, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x1, 0xff, 0xff, 0xfd, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x3, 0xff, 0xff, 0xff, 0x80, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0xb, 0xff, 0xff, 0xff, - 0xf0, 0x0, 0x7, 0xff, 0xff, 0xf0, 0x0, 0x0, - 0x1f, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x7, 0xff, - 0xff, 0xfd, 0x0, 0x0, 0x3f, 0xff, 0xff, 0xff, - 0xff, 0x80, 0x7, 0xff, 0xff, 0xff, 0x80, 0x0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x7, 0xff, - 0xff, 0xff, 0xe0, 0x2, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfd, 0x7, 0xff, 0xff, 0xff, 0xfc, 0x7, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x47, 0xff, - 0xff, 0xff, 0xff, 0x4f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - - /* U+E89C "" */ - 0x0, 0x15, 0x55, 0x55, 0x55, 0x55, 0x50, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xf4, 0x0, 0x0, 0x0, 0x3f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x0, 0x7f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x40, - 0x0, 0x0, 0x7f, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0x7f, 0xff, 0xd0, 0x0, 0x0, 0x7f, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x7f, 0xff, 0xf4, 0x0, 0x0, - 0x7f, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, - 0xfd, 0x0, 0x0, 0x7f, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x7f, 0xff, 0xff, 0x40, 0x0, 0x7f, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0xff, 0xd0, - 0x0, 0x7f, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x7f, - 0xff, 0xff, 0xf4, 0x0, 0x7f, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x7f, 0xff, 0xff, 0xfd, 0x0, 0x7f, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0xff, - 0xff, 0x40, 0x7f, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0x7f, 0xff, 0xff, 0xff, 0xd0, 0x7f, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x7f, 0xff, 0xff, 0xff, 0xf0, - 0x7f, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, - 0xff, 0xff, 0xfc, 0x7f, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, 0xff, 0xff, - 0xfd, 0x7f, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xfd, 0x7f, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0x7f, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xfd, 0x7f, 0xf0, 0x0, 0x0, 0x0, 0xbe, - 0x0, 0x0, 0x0, 0xf, 0xfd, 0x7f, 0xf0, 0x0, - 0x0, 0x1, 0xff, 0x40, 0x0, 0x0, 0xf, 0xfd, - 0x7f, 0xf0, 0x0, 0x0, 0x2, 0xff, 0x80, 0x0, - 0x0, 0xf, 0xfd, 0x7f, 0xf0, 0x0, 0x0, 0x2, - 0xff, 0x80, 0x0, 0x0, 0xf, 0xfd, 0x7f, 0xf0, - 0x0, 0x0, 0x2, 0xff, 0x80, 0x0, 0x0, 0xf, - 0xfd, 0x7f, 0xf0, 0x0, 0x0, 0x2, 0xff, 0x80, - 0x0, 0x0, 0xf, 0xfd, 0x7f, 0xf0, 0x0, 0x0, - 0x2, 0xff, 0x80, 0x0, 0x0, 0xf, 0xfd, 0x7f, - 0xf0, 0x0, 0x0, 0x2, 0xff, 0x80, 0x0, 0x0, - 0xf, 0xfd, 0x7f, 0xf0, 0x0, 0xbf, 0xff, 0xff, - 0xff, 0xfe, 0x0, 0xf, 0xfd, 0x7f, 0xf0, 0x1, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x40, 0xf, 0xfd, - 0x7f, 0xf0, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x80, 0xf, 0xfd, 0x7f, 0xf0, 0x1, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x40, 0xf, 0xfd, 0x7f, 0xf0, - 0x0, 0xbf, 0xff, 0xff, 0xff, 0xfe, 0x0, 0xf, - 0xfd, 0x7f, 0xf0, 0x0, 0x0, 0x2, 0xff, 0x80, - 0x0, 0x0, 0xf, 0xfd, 0x7f, 0xf0, 0x0, 0x0, - 0x2, 0xff, 0x80, 0x0, 0x0, 0xf, 0xfd, 0x7f, - 0xf0, 0x0, 0x0, 0x2, 0xff, 0x80, 0x0, 0x0, - 0xf, 0xfd, 0x7f, 0xf0, 0x0, 0x0, 0x2, 0xff, - 0x80, 0x0, 0x0, 0xf, 0xfd, 0x7f, 0xf0, 0x0, - 0x0, 0x2, 0xff, 0x80, 0x0, 0x0, 0xf, 0xfd, - 0x7f, 0xf0, 0x0, 0x0, 0x2, 0xff, 0x80, 0x0, - 0x0, 0xf, 0xfd, 0x7f, 0xf0, 0x0, 0x0, 0x1, - 0xff, 0x40, 0x0, 0x0, 0xf, 0xfd, 0x7f, 0xf0, - 0x0, 0x0, 0x0, 0xbe, 0x0, 0x0, 0x0, 0xf, - 0xfd, 0x7f, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xfd, 0x7f, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0x7f, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xfd, 0x7f, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xfd, 0x7f, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, - 0x7f, 0xf5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x5f, 0xfd, 0x3f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x3f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfc, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf4, 0xb, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x1, - 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfe, 0x40, - - /* U+E8AF "" */ - 0x0, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0x0, 0x0, 0x0, - 0x7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, 0xbf, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0, 0x0, - 0x0, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3, 0xff, 0x0, 0x0, 0x0, 0xf, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, - 0xf0, 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0x0, 0x0, - 0x0, 0xf, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0xf0, 0x0, 0x0, 0x0, 0xff, - 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, - 0xff, 0x0, 0x0, 0x0, 0xf, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xf0, 0x2, - 0xfa, 0x0, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3, 0xff, 0x0, 0x3f, 0xfd, 0xf, - 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3f, 0xf0, 0x3, 0xff, 0xf4, 0xff, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0x0, - 0x3f, 0xff, 0xcf, 0xfd, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3f, 0xf0, 0x3, 0xff, 0xfc, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3, 0xff, 0x0, 0x3f, 0xff, 0xcf, 0xfd, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xf0, - 0x3, 0xff, 0xfc, 0xff, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xff, 0x0, 0x3f, 0xff, - 0xcf, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0xf0, 0x3, 0xff, 0xfc, 0xff, 0xd0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, - 0x0, 0x3f, 0xff, 0xcf, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3f, 0xf0, 0x3, 0xff, - 0xfc, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3, 0xff, 0x0, 0x3f, 0xff, 0xcf, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, - 0xf0, 0x3, 0xff, 0xfc, 0xff, 0xd0, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x5b, 0xff, 0x0, 0x3f, - 0xff, 0xcf, 0xfd, 0x1f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf0, 0x3, 0xff, 0xfc, 0xff, - 0xd7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfe, 0x0, 0x3f, 0xff, 0xcf, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x3, - 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf4, 0x0, 0x3f, 0xff, 0xcf, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xf8, 0x0, 0x3, 0xff, 0xfc, 0xff, 0xff, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3f, 0xff, 0xcf, 0xff, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xfc, - 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xbf, 0xff, 0xcf, 0xff, 0xc0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x1f, 0xff, 0xfc, 0xff, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0xff, - 0xc7, 0xfc, 0x0, 0x3f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x9, 0x0, - 0x3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xc0, 0x0, 0x0, 0x3f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfc, 0x0, 0x0, 0x3, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0, - 0x0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfc, 0x0, 0x0, 0x1, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xc0, 0x0, 0x0, 0xb, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x0, - 0x0, 0x0, 0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, - 0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xc0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3, 0xff, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfc, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xc0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x2, 0xe0, - - /* U+E8B8 "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0x55, 0x50, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, - 0xff, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7, 0xff, 0xff, 0xff, 0xd0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xb, 0xff, 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, - 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xfd, 0x0, 0x7f, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xfc, 0x0, 0x3f, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x3f, - 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xfd, - 0x0, 0x7f, 0xfc, 0x0, 0x3f, 0xfd, 0x0, 0x7f, - 0xe0, 0x0, 0x0, 0x3f, 0xff, 0xe3, 0xff, 0xfc, - 0x0, 0x3f, 0xff, 0xcb, 0xff, 0xfc, 0x0, 0x0, - 0xff, 0xff, 0xff, 0xff, 0xf8, 0x0, 0x2f, 0xff, - 0xff, 0xff, 0xff, 0x0, 0x1, 0xff, 0xff, 0xff, - 0xff, 0xf8, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, - 0x40, 0x3, 0xff, 0xff, 0xff, 0xff, 0x90, 0x0, - 0x6, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xb, 0xff, - 0xaf, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x2f, 0xff, - 0xfa, 0xff, 0xe0, 0xf, 0xff, 0x1, 0xff, 0xd0, - 0x0, 0x0, 0x0, 0x7, 0xff, 0x40, 0xff, 0xf0, - 0x2f, 0xfe, 0x0, 0x1b, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xe4, 0x0, 0xbf, 0xf8, 0x3f, 0xfc, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3f, 0xfc, 0x7f, 0xf4, 0x0, 0x0, 0x0, 0x6, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x1f, 0xfd, 0x7f, - 0xfc, 0x0, 0x0, 0x0, 0x3f, 0xff, 0xfd, 0x0, - 0x0, 0x0, 0x3f, 0xfd, 0x3f, 0xff, 0x40, 0x0, - 0x1, 0xff, 0xff, 0xff, 0x80, 0x0, 0x1, 0xff, - 0xfc, 0x2f, 0xff, 0xe0, 0x0, 0x3, 0xff, 0xff, - 0xff, 0xd0, 0x0, 0xb, 0xff, 0xf8, 0xb, 0xff, - 0xfc, 0x0, 0xf, 0xff, 0xff, 0xff, 0xf0, 0x0, - 0x3f, 0xff, 0xe0, 0x1, 0xff, 0xff, 0x0, 0x1f, - 0xff, 0xff, 0xff, 0xf8, 0x0, 0xff, 0xff, 0x40, - 0x0, 0x7f, 0xfe, 0x0, 0x3f, 0xff, 0xff, 0xff, - 0xfc, 0x0, 0xbf, 0xfd, 0x0, 0x0, 0xf, 0xfd, - 0x0, 0x3f, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x7f, - 0xf0, 0x0, 0x0, 0xf, 0xfd, 0x0, 0x3f, 0xff, - 0xff, 0xff, 0xfd, 0x0, 0x7f, 0xf0, 0x0, 0x0, - 0xf, 0xfd, 0x0, 0x3f, 0xff, 0xff, 0xff, 0xfd, - 0x0, 0x7f, 0xf0, 0x0, 0x0, 0xf, 0xfd, 0x0, - 0x3f, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x7f, 0xf0, - 0x0, 0x0, 0x2f, 0xfe, 0x0, 0x3f, 0xff, 0xff, - 0xff, 0xfc, 0x0, 0xbf, 0xf8, 0x0, 0x0, 0xff, - 0xfe, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xfc, 0x0, - 0xbf, 0xfe, 0x0, 0x7, 0xff, 0xfe, 0x0, 0xf, - 0xff, 0xff, 0xff, 0xf4, 0x0, 0xbf, 0xff, 0xc0, - 0xf, 0xff, 0xf4, 0x0, 0xb, 0xff, 0xff, 0xff, - 0xf0, 0x0, 0x1f, 0xff, 0xf0, 0x3f, 0xff, 0xc0, - 0x0, 0x2, 0xff, 0xff, 0xff, 0xc0, 0x0, 0x3, - 0xff, 0xfc, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0xbf, - 0xff, 0xff, 0x0, 0x0, 0x0, 0xbf, 0xfc, 0x7f, - 0xf4, 0x0, 0x0, 0x0, 0x1f, 0xff, 0xf4, 0x0, - 0x0, 0x0, 0x1f, 0xfd, 0x7f, 0xf8, 0x0, 0x0, - 0x0, 0x0, 0x59, 0x0, 0x0, 0x0, 0x0, 0x2f, - 0xfc, 0x3f, 0xfd, 0x0, 0x5, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x40, 0x0, 0x7f, 0xfc, 0x1f, 0xff, - 0x0, 0x7f, 0x80, 0x0, 0x0, 0x0, 0x2, 0xfd, - 0x0, 0xff, 0xf4, 0xf, 0xff, 0x4b, 0xff, 0xf0, - 0x0, 0x0, 0x0, 0xf, 0xff, 0xe1, 0xff, 0xe0, - 0x3, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, - 0xbf, 0xff, 0xff, 0xff, 0xc0, 0x2, 0xff, 0xff, - 0xff, 0xff, 0xf4, 0x0, 0x1f, 0xff, 0xff, 0xff, - 0xff, 0x80, 0x0, 0xff, 0xff, 0xff, 0xff, 0xf8, - 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, - 0x7f, 0xff, 0xfb, 0xff, 0xf8, 0x0, 0x2f, 0xff, - 0xef, 0xff, 0xfd, 0x0, 0x0, 0x1f, 0xff, 0x40, - 0xff, 0xfc, 0x0, 0x3f, 0xff, 0x1, 0xff, 0xf4, - 0x0, 0x0, 0x2, 0xa0, 0x0, 0x2f, 0xfc, 0x0, - 0x3f, 0xf8, 0x0, 0x1a, 0x80, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x3f, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xfc, 0x0, 0x7f, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xfe, 0x55, 0xbf, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xff, 0xff, 0xff, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, - 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xff, 0xff, 0xff, 0xc0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xff, 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, - 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, - - /* U+E8FD "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x55, 0x50, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x1b, 0xff, 0xff, 0xfe, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6f, - 0xff, 0xff, 0xff, 0xff, 0x90, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x40, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xe4, 0x0, - 0x1, 0xbf, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, - 0x3, 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, 0x2f, - 0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, - 0x40, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, 0xf0, - 0x0, 0x0, 0x0, 0x3f, 0xff, 0x80, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3f, 0xff, 0xc0, 0x0, 0x0, - 0xf, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xbf, 0xfe, 0x0, 0x0, 0x2, 0xff, 0xf4, - 0x0, 0x0, 0x6, 0xfa, 0x40, 0x0, 0x2, 0xff, - 0xf4, 0x0, 0x0, 0x7f, 0xfd, 0x0, 0x0, 0x1f, - 0xff, 0xff, 0x40, 0x0, 0xb, 0xff, 0xc0, 0x0, - 0xf, 0xff, 0x40, 0x0, 0xb, 0xff, 0xff, 0xfe, - 0x0, 0x0, 0x2f, 0xff, 0x0, 0x2, 0xff, 0xe0, - 0x0, 0x1, 0xff, 0xff, 0xff, 0xfc, 0x0, 0x0, - 0xff, 0xf4, 0x0, 0x3f, 0xfc, 0x0, 0x0, 0x3f, - 0xff, 0xef, 0xff, 0xd0, 0x0, 0x3, 0xff, 0xc0, - 0xb, 0xff, 0x40, 0x0, 0x7, 0xff, 0x40, 0x1f, - 0xff, 0x0, 0x0, 0x2f, 0xfd, 0x0, 0xff, 0xf0, - 0x0, 0x0, 0x7f, 0xd0, 0x0, 0x7f, 0xf0, 0x0, - 0x0, 0xff, 0xe0, 0x1f, 0xfd, 0x0, 0x0, 0x2, - 0xf4, 0x0, 0x3, 0xff, 0x40, 0x0, 0xb, 0xff, - 0x2, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x2f, 0xf4, 0x0, 0x0, 0x3f, 0xf4, 0x3f, 0xf8, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0x0, - 0x0, 0x3, 0xff, 0x83, 0xff, 0x40, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7f, 0xf0, 0x0, 0x0, 0x1f, - 0xfc, 0x7f, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xfd, 0x0, 0x0, 0x1, 0xff, 0xc7, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0x80, - 0x0, 0x0, 0xf, 0xfd, 0xbf, 0xe0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xf0, 0x0, 0x0, 0x0, - 0xff, 0xdb, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3f, 0xfc, 0x0, 0x0, 0x0, 0xf, 0xfd, 0xbf, - 0xe0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xef, 0xfe, 0x0, 0x0, - 0x0, 0x0, 0x2, 0xff, 0xc0, 0x0, 0x0, 0x0, - 0xf, 0xfe, 0xbf, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0x3f, 0xf4, 0x0, 0x0, 0x0, 0x0, 0xff, 0xeb, - 0xfe, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xfd, 0xbf, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x7f, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xd7, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x7, 0xfc, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfc, - 0x3f, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x1e, 0x0, - 0x0, 0x0, 0x0, 0x1, 0xff, 0xc3, 0xff, 0x40, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x2f, 0xfc, 0x2f, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, - 0x81, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7f, 0xf0, 0xf, 0xfe, - 0x0, 0x0, 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xff, 0x0, 0xbf, 0xf0, 0x0, 0x0, - 0x0, 0xb, 0xfc, 0x0, 0x0, 0x0, 0x1, 0xff, - 0xd0, 0x3, 0xff, 0x80, 0x0, 0x0, 0x1, 0xff, - 0xf0, 0x0, 0x0, 0x0, 0x3f, 0xfc, 0x0, 0x2f, - 0xfd, 0x0, 0x0, 0x0, 0x1f, 0xff, 0x0, 0x0, - 0x0, 0xb, 0xff, 0x80, 0x0, 0xff, 0xf0, 0x0, - 0x0, 0x1, 0xff, 0xf0, 0x0, 0x0, 0x1, 0xff, - 0xf0, 0x0, 0xb, 0xff, 0xc0, 0x0, 0x0, 0xf, - 0xfe, 0x0, 0x0, 0x0, 0x3f, 0xfd, 0x0, 0x0, - 0x3f, 0xff, 0x0, 0x0, 0x0, 0x7f, 0x80, 0x0, - 0x0, 0xf, 0xff, 0x80, 0x0, 0x0, 0xff, 0xfc, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xf0, 0x0, 0x0, 0x7, 0xff, 0xf4, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2, 0xff, 0xfc, 0x0, 0x0, - 0x0, 0x1f, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, 0x7f, - 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xff, - 0xd0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xff, 0xe4, - 0x0, 0x0, 0x1, 0xff, 0xff, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x3, 0xff, 0xff, 0xfe, 0xaa, 0xaf, - 0xff, 0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xb, 0xff, 0xff, 0xff, 0xfd, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x6b, 0xfe, 0x94, 0x0, 0x0, 0x0, 0x0, - 0x0, - - /* U+E90F "" */ - 0x0, 0x0, 0x0, 0x0, 0x15, 0x54, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, 0xff, - 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, - 0xff, 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, - 0x2f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x7, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xd0, 0x0, 0x0, 0x1f, 0xff, 0xfe, - 0x40, 0x1, 0xbf, 0xff, 0xf4, 0x0, 0x0, 0x3f, - 0xff, 0xd0, 0x0, 0x0, 0x7, 0xff, 0xfc, 0x0, - 0x0, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xbf, - 0xff, 0x0, 0x2, 0xff, 0xf4, 0x0, 0x0, 0x0, - 0x0, 0x1f, 0xff, 0x80, 0x7, 0xff, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0x7, 0xff, 0xd0, 0xf, 0xff, - 0x40, 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xf0, - 0x1f, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xbf, 0xf4, 0x3f, 0xfc, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0xfc, 0x3f, 0xf8, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x2f, 0xfc, 0x7f, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, - 0xbf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xfe, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xb, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, 0xff, 0xe0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, - 0xbf, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xfe, 0x7f, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xfd, 0x3f, 0xf8, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x2f, 0xfc, 0x2f, 0xfc, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xf8, - 0x1f, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xbf, 0xf4, 0xf, 0xff, 0x40, 0x0, 0x0, 0x0, - 0x0, 0x1, 0xff, 0xf0, 0x7, 0xff, 0xc0, 0x0, - 0x0, 0x0, 0x0, 0x7, 0xff, 0xd0, 0x2, 0xff, - 0xf4, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, 0x80, - 0x0, 0xff, 0xfe, 0x55, 0x55, 0x55, 0x55, 0xbf, - 0xff, 0x0, 0x0, 0x3f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfc, 0x0, 0x0, 0x1f, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xf4, 0x0, 0x0, 0x7, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0, - 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff, - 0xff, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x1, 0x55, 0x55, 0x55, 0x55, 0x40, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xff, - 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, - 0xff, 0xff, 0xff, 0xf4, 0x0, 0x0, 0x0, 0x0, - 0x2f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x0, 0x0, - 0x0, 0x0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, 0xff, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x1, 0x55, 0x55, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, 0xff, - 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, - 0xff, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x2, 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xbf, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b, 0xe0, - 0x0, 0x0, 0x0, 0x0, - - /* U+E92E "" */ - 0x0, 0x0, 0x0, 0x2, 0xff, 0xff, 0xff, 0x80, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, - 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x1, 0x55, - 0x55, 0x5f, 0xff, 0xff, 0xff, 0xf5, 0x55, 0x55, - 0x40, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x3f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfd, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfc, 0xf, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, - 0x2, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x2, 0xff, 0x80, 0x2, 0xff, 0x80, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2, 0xff, 0x80, 0x2, 0xff, - 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, - 0x80, 0x2, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x2, 0xff, 0x80, 0x2, 0xff, 0x80, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0x80, 0x2, - 0xff, 0x80, 0x1, 0x90, 0x0, 0x6, 0x40, 0x2, - 0xff, 0x80, 0x2, 0xff, 0x80, 0xb, 0xfc, 0x0, - 0x3f, 0xe0, 0x2, 0xff, 0x80, 0x2, 0xff, 0x80, - 0xf, 0xfc, 0x0, 0x3f, 0xf0, 0x2, 0xff, 0x80, - 0x2, 0xff, 0x80, 0xf, 0xfd, 0x0, 0x7f, 0xf0, - 0x2, 0xff, 0x80, 0x2, 0xff, 0x80, 0xf, 0xfd, - 0x0, 0x7f, 0xf0, 0x2, 0xff, 0x80, 0x2, 0xff, - 0x80, 0xf, 0xfd, 0x0, 0x7f, 0xf0, 0x2, 0xff, - 0x80, 0x2, 0xff, 0x80, 0xf, 0xfd, 0x0, 0x7f, - 0xf0, 0x2, 0xff, 0x80, 0x2, 0xff, 0x80, 0xf, - 0xfd, 0x0, 0x7f, 0xf0, 0x2, 0xff, 0x80, 0x2, - 0xff, 0x80, 0xf, 0xfd, 0x0, 0x7f, 0xf0, 0x2, - 0xff, 0x80, 0x2, 0xff, 0x80, 0xf, 0xfd, 0x0, - 0x7f, 0xf0, 0x2, 0xff, 0x80, 0x2, 0xff, 0x80, - 0xf, 0xfd, 0x0, 0x7f, 0xf0, 0x2, 0xff, 0x80, - 0x2, 0xff, 0x80, 0xf, 0xfd, 0x0, 0x7f, 0xf0, - 0x2, 0xff, 0x80, 0x2, 0xff, 0x80, 0xf, 0xfd, - 0x0, 0x7f, 0xf0, 0x2, 0xff, 0x80, 0x2, 0xff, - 0x80, 0xf, 0xfd, 0x0, 0x7f, 0xf0, 0x2, 0xff, - 0x80, 0x2, 0xff, 0x80, 0xf, 0xfd, 0x0, 0x7f, - 0xf0, 0x2, 0xff, 0x80, 0x2, 0xff, 0x80, 0xf, - 0xfd, 0x0, 0x7f, 0xf0, 0x2, 0xff, 0x80, 0x2, - 0xff, 0x80, 0xf, 0xfd, 0x0, 0x7f, 0xf0, 0x2, - 0xff, 0x80, 0x2, 0xff, 0x80, 0xf, 0xfd, 0x0, - 0x7f, 0xf0, 0x2, 0xff, 0x80, 0x2, 0xff, 0x80, - 0xf, 0xfd, 0x0, 0x7f, 0xf0, 0x2, 0xff, 0x80, - 0x2, 0xff, 0x80, 0xf, 0xfd, 0x0, 0x7f, 0xf0, - 0x2, 0xff, 0x80, 0x2, 0xff, 0x80, 0xf, 0xfd, - 0x0, 0x7f, 0xf0, 0x2, 0xff, 0x80, 0x2, 0xff, - 0x80, 0xf, 0xfd, 0x0, 0x7f, 0xf0, 0x2, 0xff, - 0x80, 0x2, 0xff, 0x80, 0xf, 0xfc, 0x0, 0x3f, - 0xf0, 0x2, 0xff, 0x80, 0x2, 0xff, 0x80, 0x7, - 0xf8, 0x0, 0x2f, 0xd0, 0x2, 0xff, 0x80, 0x2, - 0xff, 0x80, 0x0, 0x40, 0x0, 0x1, 0x0, 0x2, - 0xff, 0x80, 0x2, 0xff, 0x80, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x2, 0xff, 0x80, 0x2, 0xff, 0x80, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0x80, - 0x2, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x2, 0xff, 0x80, 0x2, 0xff, 0x80, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2, 0xff, 0x80, 0x2, 0xff, - 0xd5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x56, 0xff, - 0x80, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x80, 0x1, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x40, 0x0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x0, 0x0, 0x3f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfc, 0x0, 0x0, 0xb, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x0, - - /* U+E9B9 "" */ - 0x0, 0x54, 0x0, 0x0, 0x0, 0x5a, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0x50, 0x0, 0x7f, 0xf8, - 0x0, 0x0, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xd0, 0x1f, 0xff, 0xf0, 0x0, 0x2f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x43, 0xff, 0xff, 0x40, 0x3, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xff, - 0xfc, 0x0, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xdb, 0xff, 0xff, 0xc0, 0xb, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfe, 0xbf, 0xff, 0xfc, 0x0, 0xbf, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xff, - 0xff, 0x80, 0x7, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfd, 0x3f, 0xff, 0xf0, 0x0, - 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xc0, 0xff, 0xfd, 0x0, 0x1, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x2, - 0xff, 0x40, 0x0, 0x2, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x54, 0x0, 0x0, 0x0, 0x5a, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0x50, 0x0, 0x7f, 0xf8, - 0x0, 0x0, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xd0, 0x1f, 0xff, 0xf0, 0x0, 0x2f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x43, 0xff, 0xff, 0x40, 0x3, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xff, - 0xfc, 0x0, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xdb, 0xff, 0xff, 0xc0, 0xb, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfe, 0xbf, 0xff, 0xfc, 0x0, 0xbf, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xff, - 0xff, 0x80, 0x7, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfd, 0x3f, 0xff, 0xf0, 0x0, - 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xc0, 0xff, 0xfd, 0x0, 0x1, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x2, - 0xff, 0x40, 0x0, 0x2, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x54, 0x0, 0x0, 0x0, 0x5a, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0x50, 0x0, 0x7f, 0xf8, - 0x0, 0x0, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xd0, 0x1f, 0xff, 0xf0, 0x0, 0x2f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x43, 0xff, 0xff, 0x40, 0x3, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xff, - 0xfc, 0x0, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xdb, 0xff, 0xff, 0xc0, 0xb, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfe, 0xbf, 0xff, 0xfc, 0x0, 0xbf, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xff, - 0xff, 0x80, 0x7, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfd, 0x3f, 0xff, 0xf0, 0x0, - 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xc0, 0xff, 0xfd, 0x0, 0x1, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x2, - 0xff, 0x40, 0x0, 0x2, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, - - /* U+E9F4 "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, - 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, - 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, - 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, - 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xff, - 0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xfd, - 0x7f, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xf0, - 0xf, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xd0, - 0x7, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xd0, - 0x7, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xe0, - 0xb, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xf8, - 0x2f, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xff, - 0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, - 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, - 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, - 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, - 0xf9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x5, 0x50, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x5, 0x50, 0x0, - 0x0, 0xbf, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xfe, 0x0, - 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, 0x0, 0xf, - 0xf0, 0x0, 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, - 0xf, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, 0xf, - 0xf0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xf0, - 0x3f, 0xff, 0xff, 0xfc, 0x0, 0x0, 0x0, 0xf, - 0xf0, 0x0, 0x0, 0x0, 0x3f, 0xff, 0xff, 0xfc, - 0x7f, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x2, 0xff, - 0xff, 0x80, 0x0, 0x0, 0x7f, 0xff, 0xff, 0xfd, - 0xff, 0xf4, 0x1f, 0xfe, 0x0, 0x0, 0x2f, 0xff, - 0xff, 0xf8, 0x0, 0x0, 0xbf, 0xf4, 0x1f, 0xfe, - 0xff, 0xe0, 0xb, 0xff, 0x0, 0x0, 0xbf, 0xff, - 0xff, 0xfe, 0x0, 0x0, 0xff, 0xe0, 0xb, 0xff, - 0xff, 0xd0, 0x7, 0xff, 0x0, 0x3, 0xff, 0xff, - 0xff, 0xff, 0xc0, 0x0, 0xff, 0xd0, 0x7, 0xff, - 0xff, 0xe0, 0xb, 0xff, 0xd0, 0xb, 0xff, 0xff, - 0xff, 0xff, 0xe0, 0x7, 0xff, 0xe0, 0xb, 0xff, - 0xbf, 0xf4, 0x1f, 0xff, 0xff, 0xaf, 0xff, 0xd0, - 0x7, 0xff, 0xfa, 0xff, 0xff, 0xf4, 0x1f, 0xfe, - 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, - 0x0, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x0, - 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, - 0xf, 0xff, 0xff, 0xf0, 0x6f, 0xff, 0xf0, 0x0, - 0x0, 0xf, 0xff, 0xf9, 0xf, 0xff, 0xff, 0xf0, - 0x3, 0xff, 0xff, 0xc0, 0x1, 0xff, 0xe0, 0x0, - 0x0, 0xb, 0xff, 0x40, 0x3, 0xff, 0xff, 0xc0, - 0x0, 0xbf, 0xfd, 0x0, 0x0, 0xff, 0xd0, 0x0, - 0x0, 0x7, 0xff, 0x0, 0x0, 0x7f, 0xfe, 0x0, - 0x0, 0x1, 0x40, 0x0, 0x0, 0xff, 0xd0, 0x0, - 0x0, 0x7, 0xff, 0x0, 0x0, 0x1, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, - 0x0, 0x7, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xe0, 0x0, - 0x0, 0xb, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xf0, 0x0, - 0x0, 0xf, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xf8, 0x0, - 0x0, 0x2f, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfe, 0x0, - 0x0, 0xbf, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, 0xd0, - 0x7, 0xff, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0xff, - 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xff, - 0xff, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0xff, - 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, - 0xff, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xe2, 0xff, - 0xff, 0x8b, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x5, 0x50, 0xff, 0xc0, 0x5, - 0x50, 0x3, 0xff, 0x5, 0x50, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xbf, 0xff, 0xff, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x7f, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x1f, 0xff, 0xff, 0xf8, 0x0, 0x0, - 0x0, 0x0, 0x2f, 0xff, 0xff, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0xff, 0xff, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0xff, 0xff, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0x7f, 0xff, 0xff, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x7f, 0xff, 0xff, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xf4, 0x1f, 0xfe, 0x0, 0x0, - 0x0, 0x0, 0xbf, 0xf4, 0x1f, 0xfe, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xe0, 0xb, 0xff, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xe0, 0xb, 0xff, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xd0, 0x7, 0xff, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xd0, 0x7, 0xff, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xe0, 0xb, 0xff, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xe0, 0xb, 0xff, 0x0, 0x0, - 0x0, 0x0, 0xbf, 0xf4, 0x1f, 0xfe, 0x0, 0x0, - 0x0, 0x0, 0xbf, 0xf4, 0x1f, 0xfe, 0x0, 0x0, - 0x0, 0x0, 0x7f, 0xff, 0xff, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x7f, 0xff, 0xff, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0xff, 0xff, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0xff, 0xff, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xff, 0xff, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xff, 0xff, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x3, 0xff, 0xff, 0xc0, 0x0, 0x0, - 0x0, 0x0, 0x3, 0xff, 0xff, 0xc0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xbf, 0xfe, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xbf, 0xfe, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x1, 0x40, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x1, 0x40, 0x0, 0x0, 0x0, - - /* U+E9F7 "" */ - 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x80, 0x1f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, - 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfc, 0xbf, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xe5, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x5b, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xe5, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x5b, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xe5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x5b, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, - 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf4, 0x2, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, - - /* U+EA07 "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x55, 0x50, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x1b, 0xff, 0xff, 0xfe, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6f, - 0xff, 0xff, 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x40, 0x0, - 0x0, 0x0, 0x0, 0xb, 0xff, 0xff, 0xff, 0xfb, - 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, - 0x3, 0xff, 0xff, 0x9f, 0xff, 0xf, 0xff, 0x6f, - 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, - 0x82, 0xff, 0xd0, 0x7f, 0xf8, 0x2f, 0xff, 0xf0, - 0x0, 0x0, 0x0, 0x3f, 0xff, 0xc0, 0x3f, 0xf8, - 0x3, 0xff, 0xc0, 0x7f, 0xff, 0x80, 0x0, 0x0, - 0xf, 0xff, 0xe0, 0xb, 0xff, 0x0, 0x1f, 0xfd, - 0x0, 0xff, 0xfe, 0x0, 0x0, 0x2, 0xff, 0xf8, - 0x0, 0xff, 0xe0, 0x0, 0xff, 0xf0, 0x3, 0xff, - 0xf4, 0x0, 0x0, 0x7f, 0xfe, 0x0, 0x1f, 0xfd, - 0x0, 0x7, 0xff, 0x0, 0xf, 0xff, 0xc0, 0x0, - 0xf, 0xff, 0x80, 0x3, 0xff, 0xc0, 0x0, 0x3f, - 0xf8, 0x0, 0x3f, 0xfe, 0x0, 0x2, 0xff, 0xf0, - 0x0, 0x3f, 0xf4, 0x0, 0x2, 0xff, 0xc0, 0x0, - 0xff, 0xf4, 0x0, 0x3f, 0xfd, 0x0, 0x7, 0xff, - 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x7, 0xff, 0xc0, - 0x7, 0xff, 0xd5, 0x55, 0xff, 0xf5, 0x55, 0x56, - 0xff, 0xe5, 0x55, 0x7f, 0xfd, 0x0, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xe0, 0x1f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x3f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfc, 0x7f, 0xf0, 0x0, 0x3, 0xff, 0x80, 0x0, - 0x0, 0x3f, 0xf8, 0x0, 0x1, 0xff, 0xc7, 0xff, - 0x0, 0x0, 0x3f, 0xf4, 0x0, 0x0, 0x2, 0xff, - 0x80, 0x0, 0xf, 0xfd, 0xbf, 0xf0, 0x0, 0x3, - 0xff, 0x40, 0x0, 0x0, 0x2f, 0xfc, 0x0, 0x0, - 0xff, 0xdb, 0xfe, 0x0, 0x0, 0x3f, 0xf4, 0x0, - 0x0, 0x1, 0xff, 0xc0, 0x0, 0xf, 0xfd, 0xbf, - 0xe0, 0x0, 0x3, 0xff, 0x40, 0x0, 0x0, 0x1f, - 0xfc, 0x0, 0x0, 0xff, 0xef, 0xfe, 0x0, 0x0, - 0x3f, 0xf0, 0x0, 0x0, 0x1, 0xff, 0xc0, 0x0, - 0xf, 0xfe, 0xbf, 0xe0, 0x0, 0x3, 0xff, 0x40, - 0x0, 0x0, 0x1f, 0xfc, 0x0, 0x0, 0xff, 0xeb, - 0xfe, 0x0, 0x0, 0x3f, 0xf4, 0x0, 0x0, 0x2, - 0xff, 0xc0, 0x0, 0xf, 0xfd, 0xbf, 0xf0, 0x0, - 0x3, 0xff, 0x40, 0x0, 0x0, 0x2f, 0xf8, 0x0, - 0x0, 0xff, 0xd7, 0xff, 0x0, 0x0, 0x3f, 0xf8, - 0x0, 0x0, 0x2, 0xff, 0x80, 0x0, 0xf, 0xfc, - 0x3f, 0xf9, 0x55, 0x57, 0xff, 0xd5, 0x55, 0x55, - 0x7f, 0xf9, 0x55, 0x56, 0xff, 0xc3, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x0, 0xbf, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xd0, 0x3, 0xff, 0xc0, 0x0, 0x7f, 0xf0, 0x0, - 0x0, 0xff, 0xd0, 0x0, 0x3f, 0xfc, 0x0, 0x2f, - 0xfe, 0x0, 0x3, 0xff, 0x40, 0x0, 0x2f, 0xfc, - 0x0, 0xf, 0xff, 0x80, 0x0, 0xff, 0xf4, 0x0, - 0x3f, 0xf8, 0x0, 0x3, 0xff, 0x80, 0x2, 0xff, - 0xf0, 0x0, 0xb, 0xff, 0xc0, 0x2, 0xff, 0xc0, - 0x0, 0x7f, 0xf4, 0x0, 0x7f, 0xfd, 0x0, 0x0, - 0x3f, 0xff, 0x0, 0xf, 0xfd, 0x0, 0xb, 0xff, - 0x0, 0x1f, 0xff, 0x80, 0x0, 0x0, 0xff, 0xfc, - 0x0, 0xff, 0xf0, 0x0, 0xff, 0xe0, 0x7, 0xff, - 0xf0, 0x0, 0x0, 0x7, 0xff, 0xf4, 0x7, 0xff, - 0x40, 0x2f, 0xfc, 0x2, 0xff, 0xfc, 0x0, 0x0, - 0x0, 0x1f, 0xff, 0xe0, 0x3f, 0xfc, 0x3, 0xff, - 0xc1, 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, 0x7f, - 0xff, 0xe1, 0xff, 0xe0, 0xff, 0xf5, 0xbf, 0xff, - 0xd0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xff, 0xff, - 0xff, 0x5f, 0xff, 0xff, 0xff, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x3, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xb, 0xff, 0xff, 0xff, 0xfd, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xaf, 0xff, 0x94, 0x0, 0x0, 0x0, 0x0, - 0x0, - - /* U+EAD6 "" */ - 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x80, 0x1f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, - 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfc, 0xbf, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xe5, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x5b, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x7f, 0xfe, 0x1, 0xff, 0xfc, 0x1e, - 0x0, 0x1e, 0x7, 0xff, 0xff, 0xd0, 0xff, 0xff, - 0xc3, 0xff, 0xfd, 0x3f, 0x0, 0x3f, 0x47, 0xff, - 0xff, 0xd0, 0xff, 0xff, 0xd3, 0xff, 0xfc, 0x2f, - 0x40, 0x3f, 0x7, 0xff, 0xff, 0xd0, 0xfc, 0xb, - 0xd3, 0xf0, 0x0, 0x1f, 0xc0, 0x7f, 0x7, 0xff, - 0xff, 0xd0, 0xfc, 0xb, 0xd3, 0xf0, 0x0, 0xf, - 0xc0, 0xbe, 0x7, 0xff, 0xff, 0xd0, 0xfc, 0xb, - 0xd3, 0xf0, 0x0, 0xf, 0xd0, 0xfd, 0x7, 0xff, - 0xff, 0xd0, 0xfc, 0xb, 0xd3, 0xfa, 0x40, 0xb, - 0xe0, 0xfc, 0x7, 0xff, 0xff, 0xd0, 0xfc, 0xb, - 0xd3, 0xff, 0xd0, 0x7, 0xf1, 0xfc, 0x7, 0xff, - 0xff, 0xd0, 0xfc, 0xb, 0xd3, 0xff, 0xd0, 0x3, - 0xf2, 0xf8, 0x7, 0xff, 0xff, 0xd0, 0xfc, 0xb, - 0xd3, 0xf9, 0x40, 0x3, 0xf7, 0xf0, 0x7, 0xff, - 0xff, 0xd0, 0xfc, 0xb, 0xd3, 0xf0, 0x0, 0x2, - 0xff, 0xf0, 0x7, 0xff, 0xff, 0xd0, 0xfc, 0xb, - 0xd3, 0xf0, 0x0, 0x0, 0xff, 0xe0, 0x7, 0xff, - 0xff, 0xd0, 0xfc, 0xb, 0xd3, 0xf0, 0x0, 0x0, - 0xff, 0xd0, 0x7, 0xff, 0xff, 0xd0, 0xff, 0xff, - 0xd3, 0xff, 0xfc, 0x0, 0xbf, 0xc0, 0x7, 0xff, - 0xff, 0xd0, 0xff, 0xff, 0xc3, 0xff, 0xfd, 0x0, - 0x7f, 0xc0, 0x7, 0xff, 0xff, 0xd0, 0x7f, 0xfe, - 0x1, 0xff, 0xfc, 0x0, 0x2f, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xe5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x5b, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, - 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf4, 0x2, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, - - /* U+EB8E "" */ - 0x0, 0x6a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0x90, 0x0, 0xbf, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xd0, 0x2f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x47, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xbf, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xdf, 0xfe, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xfd, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xdf, - 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xfd, 0xff, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xdf, 0xfd, 0x0, 0x2, 0xf4, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, - 0xff, 0xd0, 0x0, 0xbf, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xdf, 0xfd, 0x0, - 0xf, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xfd, 0xff, 0xd0, 0x0, 0xbf, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xdf, 0xfd, 0x0, 0x3, 0xff, 0xf4, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0xff, 0xd0, - 0x0, 0xf, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xdf, 0xfd, 0x0, 0x0, 0x3f, - 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xfd, 0xff, 0xd0, 0x0, 0x0, 0xff, 0xfd, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xdf, 0xfd, - 0x0, 0x0, 0x3, 0xff, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xfd, 0xff, 0xd0, 0x0, 0x0, - 0x1f, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xdf, 0xfd, 0x0, 0x0, 0x3, 0xff, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0xff, - 0xd0, 0x0, 0x0, 0xff, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xdf, 0xfd, 0x0, 0x0, - 0x3f, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xfd, 0xff, 0xd0, 0x0, 0xf, 0xff, 0xe0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xdf, - 0xfd, 0x0, 0x3, 0xff, 0xf8, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xfd, 0xff, 0xd0, 0x0, - 0xbf, 0xfe, 0x0, 0x0, 0xff, 0xff, 0xff, 0xe0, - 0x0, 0xff, 0xdf, 0xfd, 0x0, 0xf, 0xff, 0x80, - 0x0, 0x3f, 0xff, 0xff, 0xff, 0x40, 0xf, 0xfd, - 0xff, 0xd0, 0x0, 0xbf, 0xe0, 0x0, 0x3, 0xff, - 0xff, 0xff, 0xf8, 0x0, 0xff, 0xdf, 0xfd, 0x0, - 0x3, 0xf8, 0x0, 0x0, 0x3f, 0xff, 0xff, 0xff, - 0x80, 0xf, 0xfd, 0xff, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x1, 0xff, 0xff, 0xff, 0xf0, 0x0, 0xff, - 0xdf, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, - 0x55, 0x55, 0x54, 0x0, 0xf, 0xfd, 0xff, 0xd0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xdf, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdb, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xc2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x7, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf8, 0x0, 0x1, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x54, 0x0, - - /* U+EB97 "" */ - 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xf4, 0x1, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x8b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xdf, 0xfe, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x5f, - 0xfd, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xdf, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xfd, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xdf, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0xff, - 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x40, 0x0, 0x0, 0xff, 0xdf, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0x40, 0x0, - 0xf, 0xfd, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3, 0xf8, 0x0, 0x0, 0xff, 0xdf, - 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3f, 0x80, 0x0, 0xf, 0xfd, 0xff, 0xd0, 0x1, - 0xff, 0xff, 0xff, 0xff, 0xfd, 0x3, 0xff, 0xf0, - 0x0, 0xff, 0xdf, 0xfd, 0x0, 0x3f, 0xff, 0xff, - 0xff, 0xff, 0xf0, 0x3f, 0xff, 0x80, 0xf, 0xfd, - 0xff, 0xd0, 0x3, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x3, 0xff, 0xf8, 0x0, 0xff, 0xdf, 0xfd, 0x0, - 0x2f, 0xff, 0xff, 0xff, 0xff, 0xd0, 0x3f, 0xff, - 0x0, 0xf, 0xfd, 0xff, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xfc, 0x0, 0x0, 0xff, - 0xdf, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0x80, 0x0, 0xf, 0xfd, 0xff, 0xd0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xf4, - 0x0, 0x0, 0xff, 0xdf, 0xfd, 0x0, 0x0, 0x5, - 0x0, 0x0, 0x0, 0x0, 0x5, 0x0, 0x0, 0xf, - 0xfd, 0xff, 0xd0, 0x0, 0x3, 0xf4, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xdf, 0xfd, - 0x0, 0x0, 0x3f, 0xc0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xfd, 0xff, 0xd0, 0x0, 0x7, - 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xdf, 0xfd, 0x0, 0x2f, 0xff, 0xc0, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x0, 0xf, 0xfd, 0xff, - 0xd0, 0x3, 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xff, - 0xff, 0xf8, 0x0, 0xff, 0xdf, 0xfd, 0x0, 0x3f, - 0xff, 0xc1, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, - 0xf, 0xfd, 0xff, 0xd0, 0x1, 0xff, 0xfc, 0xb, - 0xff, 0xff, 0xff, 0xff, 0xe0, 0x0, 0xff, 0xdf, - 0xfd, 0x0, 0x0, 0x3f, 0xc0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xfd, 0xff, 0xd0, 0x0, - 0x3, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xdf, 0xfd, 0x0, 0x0, 0x2f, 0x40, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xdf, 0xfd, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xfd, 0xff, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xdf, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0xff, 0xd0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xdf, 0xfe, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x5f, - 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdb, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x40, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x2, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xe4, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xff, 0xff, - 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, - 0xff, 0xff, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - - /* U+EBCC "" */ - 0x0, 0x0, 0x19, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x64, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xc0, - 0x0, 0x0, 0x0, 0x0, 0x3, 0xfe, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, - 0x3, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, 0xd0, - 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0x7, 0xff, 0x0, 0x0, 0x0, 0x15, 0xff, 0xe5, - 0x55, 0x55, 0x55, 0x55, 0x5b, 0xff, 0x54, 0x0, - 0x7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xd0, 0x2f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, - 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xe5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x5b, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x1, 0xf8, - 0x0, 0xb, 0xd0, 0x0, 0x2f, 0x40, 0x7, 0xff, - 0xff, 0xd0, 0x3, 0xfe, 0x0, 0x1f, 0xf4, 0x0, - 0xbf, 0xc0, 0x7, 0xff, 0xff, 0xd0, 0x7, 0xff, - 0x0, 0x2f, 0xf8, 0x0, 0xff, 0xd0, 0x7, 0xff, - 0xff, 0xd0, 0x3, 0xff, 0x0, 0x2f, 0xf4, 0x0, - 0xff, 0xc0, 0x7, 0xff, 0xff, 0xd0, 0x2, 0xfc, - 0x0, 0xf, 0xe0, 0x0, 0x7f, 0x80, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, - 0x4, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x10, - 0x0, 0x1, 0x0, 0x0, 0x4, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x2, 0xfc, 0x0, 0xf, 0xe0, 0x0, - 0x7f, 0x80, 0x7, 0xff, 0xff, 0xd0, 0x3, 0xff, - 0x0, 0x2f, 0xf4, 0x0, 0xff, 0xc0, 0x7, 0xff, - 0xff, 0xd0, 0x7, 0xff, 0x0, 0x2f, 0xf8, 0x0, - 0xff, 0xd0, 0x7, 0xff, 0xff, 0xd0, 0x3, 0xfe, - 0x0, 0x1f, 0xf4, 0x0, 0xbf, 0xc0, 0x7, 0xff, - 0xff, 0xd0, 0x1, 0xf8, 0x0, 0xb, 0xd0, 0x0, - 0x2f, 0x40, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xe5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x5b, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, - 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf0, 0x2, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, - - /* U+EC1C "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, - 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, - 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x1f, 0xff, 0xc0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0x80, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, - 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, 0xfc, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xbf, 0xff, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x2, 0xff, 0xff, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0xff, - 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x2f, 0xff, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xbf, 0xff, 0xff, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xb, 0xff, 0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3f, 0xff, 0xff, 0xf8, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, - 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3, 0xff, 0xf9, 0xff, 0xe0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xff, 0xe3, 0xff, 0xc0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xff, - 0x87, 0xff, 0xe5, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xfe, 0xf, 0xff, 0xff, 0xff, 0xa5, - 0x0, 0x0, 0x0, 0x3, 0xff, 0xf8, 0x2f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x90, 0x0, 0xf, 0xff, - 0xe0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, - 0x0, 0x3f, 0xff, 0x80, 0x7f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xf8, 0x1, 0xff, 0xfe, 0x0, 0x0, - 0x16, 0xbf, 0xff, 0xff, 0xff, 0xf8, 0x7, 0xff, - 0xf4, 0x0, 0x0, 0x0, 0x0, 0x16, 0xbf, 0xff, - 0xf0, 0xf, 0xff, 0xfe, 0x94, 0x0, 0x0, 0x0, - 0x0, 0x1f, 0xff, 0xd0, 0x2f, 0xff, 0xff, 0xff, - 0xfe, 0x94, 0x0, 0x0, 0x7f, 0xff, 0x40, 0x2f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x1, 0xff, - 0xfc, 0x0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfc, 0xb, 0xff, 0xf0, 0x0, 0x6, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf8, 0x2f, 0xff, 0xc0, 0x0, - 0x0, 0x0, 0x5a, 0xff, 0xff, 0xff, 0xf0, 0xbf, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5b, - 0xff, 0xd2, 0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3, 0xff, 0xcb, 0xff, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0x6f, - 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xfc, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xff, - 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x1, 0xff, 0xff, 0xfe, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, - 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x7, 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0x80, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, - 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0xff, 0xf4, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xff, 0xd0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x2, 0xff, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xf4, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xb, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xff, 0x40, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xfc, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x1, 0xa0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, - - /* U+EF40 "" */ - 0x0, 0x55, 0x0, 0x0, 0x0, 0x55, 0x0, 0x0, - 0x0, 0x55, 0x0, 0x0, 0x0, 0xff, 0xf4, 0x0, - 0x0, 0xff, 0xf4, 0x0, 0x0, 0xff, 0xf4, 0x0, - 0x0, 0xff, 0xff, 0x40, 0x0, 0xff, 0xff, 0x40, - 0x0, 0xff, 0xff, 0x40, 0x0, 0xbf, 0xff, 0xf0, - 0x0, 0xbf, 0xff, 0xf0, 0x0, 0xbf, 0xff, 0xf0, - 0x0, 0x3f, 0xff, 0xfc, 0x0, 0x3f, 0xff, 0xfc, - 0x0, 0x3f, 0xff, 0xfc, 0x0, 0xf, 0xff, 0xff, - 0x40, 0xf, 0xff, 0xff, 0x40, 0xf, 0xff, 0xff, - 0x40, 0x3, 0xff, 0xff, 0xd0, 0x3, 0xff, 0xff, - 0xd0, 0x3, 0xff, 0xff, 0xd0, 0x0, 0xff, 0xff, - 0xf0, 0x0, 0xff, 0xff, 0xf0, 0x0, 0xff, 0xff, - 0xf0, 0x0, 0x1f, 0xff, 0xf8, 0x0, 0x1f, 0xff, - 0xf8, 0x0, 0x1f, 0xff, 0xf8, 0x0, 0x2, 0xff, - 0xfc, 0x0, 0x2, 0xff, 0xfc, 0x0, 0x2, 0xff, - 0xfc, 0x0, 0x0, 0x1f, 0xf8, 0x0, 0x0, 0x1f, - 0xf8, 0x0, 0x0, 0x1f, 0xf8, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x55, 0x0, 0x0, - 0x0, 0x55, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xf4, 0x0, 0x0, 0xff, 0xf4, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x40, - 0x0, 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xbf, 0xff, 0xf0, 0x0, 0xbf, 0xff, 0xf0, - 0x0, 0x0, 0x1, 0xf8, 0x0, 0x3f, 0xff, 0xfc, - 0x0, 0x3f, 0xff, 0xfc, 0x0, 0x0, 0x2, 0xff, - 0xd0, 0xf, 0xff, 0xff, 0x40, 0xf, 0xff, 0xff, - 0x40, 0x0, 0x2, 0xff, 0xfd, 0x3, 0xff, 0xff, - 0xd0, 0x3, 0xff, 0xff, 0xd0, 0x0, 0x2, 0xff, - 0xff, 0xd0, 0xff, 0xff, 0xf0, 0x0, 0xff, 0xff, - 0xf0, 0x0, 0x2, 0xff, 0xff, 0xfc, 0x1f, 0xff, - 0xf8, 0x0, 0x1f, 0xff, 0xf8, 0x0, 0x2, 0xff, - 0xff, 0xff, 0x82, 0xff, 0xfc, 0x0, 0x2, 0xff, - 0xfc, 0x0, 0x2, 0xff, 0xff, 0xff, 0xe0, 0x1f, - 0xf8, 0x0, 0x0, 0x1f, 0xf8, 0x0, 0x2, 0xff, - 0xff, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x2, 0xff, 0xff, 0xff, 0xfd, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, - 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x2, 0xff, 0xc3, 0xff, 0xfe, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, - 0xc0, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x2, 0xff, 0xc0, 0xf, 0xfe, 0x0, - 0x0, 0x55, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, - 0xc0, 0xf, 0xfe, 0x0, 0x0, 0xff, 0xf4, 0x0, - 0x0, 0x0, 0x3, 0xff, 0xc0, 0xf, 0xfe, 0x0, - 0x0, 0xff, 0xff, 0x40, 0x0, 0x0, 0x2, 0xff, - 0xc0, 0xf, 0xfe, 0x0, 0x0, 0xbf, 0xff, 0xf0, - 0x0, 0x0, 0x0, 0xff, 0xc0, 0xf, 0xfe, 0x0, - 0x0, 0x3f, 0xff, 0xfc, 0x0, 0x0, 0x0, 0x3f, - 0xc0, 0xf, 0xfe, 0x0, 0x0, 0xf, 0xff, 0xff, - 0x40, 0x0, 0x0, 0xf, 0xf0, 0xf, 0xfe, 0x0, - 0x0, 0x3, 0xff, 0xff, 0xd0, 0x0, 0x0, 0x3, - 0xfc, 0xf, 0xfe, 0x0, 0x0, 0x0, 0xff, 0xff, - 0xf0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xfe, 0x0, - 0x0, 0x0, 0x1f, 0xff, 0xf8, 0x0, 0x0, 0x0, - 0x3f, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x2, 0xff, - 0xfc, 0x0, 0x0, 0x0, 0xf, 0xff, 0xfe, 0x0, - 0x0, 0x0, 0x0, 0x1f, 0xf8, 0x0, 0x0, 0x0, - 0x1, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, - - /* U+EF4A "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x55, 0x50, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x1b, 0xff, 0xff, 0xfe, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6f, - 0xff, 0xff, 0xff, 0xff, 0x90, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x40, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xe4, 0x0, - 0x1, 0xbf, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, - 0x3, 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, 0x2f, - 0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, - 0x40, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, 0xf0, - 0x0, 0x0, 0x0, 0x3f, 0xff, 0x80, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3f, 0xff, 0xc0, 0x0, 0x0, - 0xf, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xbf, 0xfe, 0x0, 0x0, 0x2, 0xff, 0xf4, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, - 0xf4, 0x0, 0x0, 0x7f, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0xc0, 0x0, - 0xf, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x2f, 0xff, 0x0, 0x2, 0xff, 0xe0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xf4, 0x0, 0x3f, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xc0, - 0xb, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xfd, 0x0, 0xff, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xe0, 0x1f, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, - 0x2, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3f, 0xf4, 0x3f, 0xf8, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3, 0xff, 0x83, 0xff, 0x40, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, - 0xfc, 0x7f, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xc7, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xfd, 0xbf, 0xe0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xdb, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0xbf, - 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xef, 0xfe, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xfe, 0xbf, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xeb, - 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xfd, 0xbf, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xd7, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfc, - 0x3f, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x1, 0xff, 0xc3, 0xff, 0x40, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x2f, 0xfc, 0x2f, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, - 0x81, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7f, 0xf0, 0xf, 0xfe, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xff, 0x0, 0xbf, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, - 0xd0, 0x3, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfc, 0x0, 0x2f, - 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xb, 0xff, 0x80, 0x0, 0xff, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, - 0xf0, 0x0, 0xb, 0xff, 0xc0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfd, 0x0, 0x0, - 0x3f, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xff, 0x80, 0x0, 0x0, 0xff, 0xfc, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0xf0, 0x0, 0x0, 0x7, 0xff, 0xf4, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2, 0xff, 0xfc, 0x0, 0x0, - 0x0, 0x1f, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, 0x7f, - 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xff, - 0xd0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xff, 0xe4, - 0x0, 0x0, 0x1, 0xff, 0xff, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x3, 0xff, 0xff, 0xfe, 0xaa, 0xaf, - 0xff, 0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xb, 0xff, 0xff, 0xff, 0xfd, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x6b, 0xfe, 0x94, 0x0, 0x0, 0x0, 0x0, - 0x0, - - /* U+EF7A "" */ - 0x0, 0x0, 0x0, 0x6f, 0xff, 0xa0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, - 0xff, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xb, 0xff, 0xff, 0xff, 0xff, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0, - 0x0, 0x0, 0x0, 0x1, 0xff, 0xff, 0xe5, 0x5b, - 0xff, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x1f, - 0xff, 0xf4, 0x0, 0x0, 0xbf, 0xff, 0xc0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xfd, 0x0, 0x0, 0x0, - 0x3f, 0xff, 0x80, 0x0, 0x0, 0x0, 0xb, 0xff, - 0xd0, 0x0, 0x0, 0x0, 0x2f, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0xfd, 0x0, 0x0, 0x0, 0x0, - 0x2f, 0xff, 0x0, 0x0, 0x0, 0x2, 0xff, 0xd0, - 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfc, 0x0, 0x0, - 0x0, 0xf, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x7f, 0xf8, 0x0, 0x0, 0x0, 0x7f, 0xf4, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xf0, 0x0, 0x0, - 0x2, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x1, - 0xff, 0xc0, 0x0, 0x0, 0xf, 0xfe, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xff, 0x40, 0x0, 0x0, - 0x3f, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xfd, 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3f, 0xf8, 0x0, 0x0, 0x3, - 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xe0, 0x0, 0x0, 0xf, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3, 0xff, 0x40, 0x0, 0x0, 0x3f, - 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, - 0x0, 0x0, 0x0, 0xbf, 0xe0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0xf4, 0x0, 0x0, 0x2, 0xff, - 0xc0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xc0, - 0x0, 0x0, 0x7, 0xff, 0x40, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xff, 0x0, 0x0, 0x0, 0xf, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xf4, 0x0, - 0x0, 0x0, 0x2f, 0xfe, 0x0, 0x0, 0x0, 0x0, - 0x3, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x3f, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0xbf, 0xfd, 0x0, 0x0, 0x0, 0x3, - 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xfe, - 0x0, 0x0, 0x0, 0x3f, 0xff, 0x40, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xff, 0x40, 0x0, 0x1b, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xff, - 0xfa, 0xab, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xbf, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xbf, 0xff, 0xff, 0xff, 0xe0, 0xbf, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, - 0xff, 0xf8, 0x0, 0xbf, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x1, 0xbf, 0xe9, 0x0, 0x0, 0xbf, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xbf, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xbf, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xbf, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xbf, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, - 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xbf, 0xfe, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, - 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xbf, 0xe0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7e, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, - - /* U+EFE6 "" */ - 0x0, 0x0, 0x0, 0x6f, 0xf9, 0x0, 0x0, 0x0, - 0x1, 0xff, 0xff, 0x40, 0x0, 0x0, 0x7, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x3, 0xff, 0xff, 0xc0, - 0x0, 0x0, 0x2f, 0xff, 0xff, 0xf8, 0x0, 0x0, - 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, 0xff, 0xff, - 0xff, 0xfe, 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, - 0x0, 0x2, 0xff, 0xff, 0xff, 0xff, 0x40, 0x0, - 0x7, 0xff, 0xff, 0xd0, 0x0, 0x7, 0xff, 0xf9, - 0x6f, 0xff, 0xc0, 0x0, 0xb, 0xff, 0xff, 0xe0, - 0x0, 0xf, 0xff, 0x80, 0x3, 0xff, 0xe0, 0x0, - 0x3f, 0xff, 0xff, 0xfc, 0x0, 0xf, 0xfe, 0x0, - 0x0, 0xff, 0xf0, 0x0, 0xff, 0xff, 0xff, 0xff, - 0x0, 0x1f, 0xfc, 0x0, 0x0, 0x7f, 0xf0, 0x0, - 0xff, 0xff, 0xff, 0xff, 0x0, 0x2f, 0xfc, 0x0, - 0x0, 0x3f, 0xf4, 0x0, 0xff, 0xff, 0xff, 0xff, - 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x3f, 0xf4, 0x0, - 0xff, 0xff, 0xff, 0xff, 0x0, 0x2f, 0xf8, 0x0, - 0x0, 0x3f, 0xf4, 0x0, 0xff, 0xff, 0xff, 0xff, - 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x3f, 0xf4, 0x0, - 0xff, 0xff, 0xff, 0xff, 0x0, 0x2f, 0xf8, 0x0, - 0x0, 0x3f, 0xf4, 0x0, 0xff, 0xff, 0xff, 0xff, - 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x3f, 0xf4, 0x0, - 0xff, 0xff, 0xff, 0xff, 0x0, 0x2f, 0xf8, 0x0, - 0x0, 0x3f, 0xf4, 0x0, 0xff, 0xff, 0xff, 0xff, - 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x3f, 0xf4, 0x0, - 0xff, 0xff, 0xff, 0xff, 0x0, 0x2f, 0xf8, 0x0, - 0x0, 0x3f, 0xf4, 0x0, 0xbf, 0xff, 0xff, 0xfe, - 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x3f, 0xf4, 0x0, - 0x1a, 0xbf, 0xfe, 0xa4, 0x0, 0x2f, 0xf8, 0x0, - 0x0, 0x3f, 0xf4, 0x0, 0x0, 0x2f, 0xf8, 0x0, - 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x3f, 0xf4, 0x0, - 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x2f, 0xf8, 0x0, - 0x0, 0x3f, 0xf4, 0x0, 0x0, 0x2f, 0xf8, 0x0, - 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x3f, 0xf4, 0x0, - 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x2f, 0xf8, 0x0, - 0x0, 0x3f, 0xf4, 0x0, 0x0, 0x2f, 0xf8, 0x0, - 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x3f, 0xf4, 0x0, - 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x2f, 0xf8, 0x0, - 0x0, 0x3f, 0xf4, 0x0, 0x0, 0x2f, 0xf8, 0x0, - 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x3f, 0xf4, 0x0, - 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x2f, 0xf8, 0x0, - 0x0, 0x3f, 0xf4, 0x0, 0x0, 0x2f, 0xf8, 0x0, - 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x3f, 0xf4, 0x0, - 0x0, 0x2f, 0xf8, 0x0, 0x1a, 0xbf, 0xfe, 0xa4, - 0x0, 0x3f, 0xf4, 0x0, 0x0, 0x2f, 0xf8, 0x0, - 0xbf, 0xff, 0xff, 0xfe, 0x0, 0x3f, 0xf4, 0x0, - 0x0, 0x2f, 0xf8, 0x0, 0xff, 0xff, 0xff, 0xff, - 0x0, 0x3f, 0xf4, 0x0, 0x0, 0x2f, 0xf8, 0x0, - 0xff, 0xff, 0xff, 0xff, 0x0, 0x3f, 0xf4, 0x0, - 0x0, 0x2f, 0xf8, 0x0, 0xff, 0xff, 0xff, 0xff, - 0x0, 0x3f, 0xf4, 0x0, 0x0, 0x2f, 0xf8, 0x0, - 0xff, 0xff, 0xff, 0xff, 0x0, 0x3f, 0xf4, 0x0, - 0x0, 0x2f, 0xf8, 0x0, 0xff, 0xff, 0xff, 0xff, - 0x0, 0x3f, 0xf4, 0x0, 0x0, 0x2f, 0xf8, 0x0, - 0xff, 0xff, 0xff, 0xff, 0x0, 0x3f, 0xf4, 0x0, - 0x0, 0x2f, 0xf8, 0x0, 0xff, 0xff, 0xff, 0xff, - 0x0, 0x3f, 0xf4, 0x0, 0x0, 0x2f, 0xf8, 0x0, - 0xff, 0xff, 0xff, 0xff, 0x0, 0x3f, 0xf8, 0x0, - 0x0, 0x3f, 0xf8, 0x0, 0xff, 0xff, 0xff, 0xff, - 0x0, 0x2f, 0xfc, 0x0, 0x0, 0x3f, 0xf4, 0x0, - 0xff, 0xff, 0xff, 0xff, 0x0, 0x1f, 0xfe, 0x0, - 0x0, 0xbf, 0xf0, 0x0, 0x3f, 0xff, 0xff, 0xfc, - 0x0, 0xf, 0xff, 0x80, 0x2, 0xff, 0xf0, 0x0, - 0xb, 0xff, 0xff, 0xe0, 0x0, 0xb, 0xff, 0xf9, - 0x6f, 0xff, 0xd0, 0x0, 0x7, 0xff, 0xff, 0xd0, - 0x0, 0x3, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0, - 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, 0xff, 0xff, - 0xff, 0xff, 0x0, 0x0, 0x7, 0xff, 0xff, 0xd0, - 0x0, 0x0, 0x3f, 0xff, 0xff, 0xf8, 0x0, 0x0, - 0x3, 0xff, 0xff, 0xc0, 0x0, 0x0, 0xb, 0xff, - 0xff, 0xd0, 0x0, 0x0, 0x1, 0xff, 0xff, 0x40, - 0x0, 0x0, 0x0, 0x6f, 0xf9, 0x0, 0x0, 0x0, - - /* U+F028 "" */ - 0x0, 0x15, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x54, 0x0, 0x2, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0xf, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x2f, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfd, 0x7f, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xfd, 0x7f, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, - 0x7f, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0x7f, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0x7f, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xfd, 0x7f, 0xf0, 0x0, - 0x28, 0x0, 0x1, 0x90, 0x0, 0xa, 0x40, 0x0, - 0x28, 0x0, 0xf, 0xfd, 0x7f, 0xf0, 0x0, 0xff, - 0x0, 0x7, 0xf8, 0x0, 0x3f, 0xd0, 0x0, 0xff, - 0x0, 0xf, 0xfd, 0x7f, 0xf0, 0x2, 0xff, 0x80, - 0xf, 0xfc, 0x0, 0x7f, 0xf0, 0x2, 0xff, 0x80, - 0xf, 0xfd, 0x7f, 0xf0, 0x2, 0xff, 0x80, 0xf, - 0xfc, 0x0, 0x7f, 0xf0, 0x2, 0xff, 0x80, 0xf, - 0xfd, 0x7f, 0xf0, 0x1, 0xff, 0x40, 0xb, 0xfc, - 0x0, 0x3f, 0xe0, 0x1, 0xff, 0x40, 0xf, 0xfd, - 0x7f, 0xf0, 0x0, 0x7d, 0x0, 0x2, 0xe0, 0x0, - 0xb, 0x80, 0x0, 0x7d, 0x0, 0xf, 0xfd, 0x7f, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0x7f, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xfd, 0x7f, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xfd, 0x7f, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xfd, 0x7f, 0xf0, 0x0, 0xbe, 0x0, - 0x3, 0xf4, 0x0, 0x1f, 0xc0, 0x0, 0xbe, 0x0, - 0xf, 0xfd, 0x7f, 0xf0, 0x1, 0xff, 0x40, 0xf, - 0xfc, 0x0, 0x3f, 0xf0, 0x1, 0xff, 0x40, 0xf, - 0xfd, 0x7f, 0xf0, 0x2, 0xff, 0x80, 0xf, 0xfc, - 0x0, 0x7f, 0xf0, 0x2, 0xff, 0x80, 0xf, 0xfd, - 0x7f, 0xf0, 0x1, 0xff, 0x40, 0xb, 0xfc, 0x0, - 0x3f, 0xe0, 0x1, 0xff, 0x40, 0xf, 0xfd, 0x7f, - 0xf0, 0x0, 0xbe, 0x0, 0x2, 0xf0, 0x0, 0x1f, - 0x80, 0x0, 0xbe, 0x0, 0xf, 0xfd, 0x7f, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xfd, 0x7f, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xfd, 0x7f, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xfd, 0x7f, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xfd, 0x7f, 0xf0, 0x0, 0x0, 0x0, 0xbf, - 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0xf, - 0xfd, 0x7f, 0xf0, 0x0, 0x0, 0x1, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x40, 0x0, 0x0, 0xf, 0xfd, - 0x7f, 0xf0, 0x0, 0x0, 0x2, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x80, 0x0, 0x0, 0xf, 0xfd, 0x7f, - 0xf0, 0x0, 0x0, 0x1, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x40, 0x0, 0x0, 0xf, 0xfd, 0x7f, 0xf0, - 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x0, 0x0, 0x0, 0xf, 0xfd, 0x7f, 0xf0, 0x0, - 0x0, 0x0, 0x5, 0x55, 0x55, 0x55, 0x50, 0x0, - 0x0, 0x0, 0xf, 0xfd, 0x7f, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xfd, 0x7f, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xfd, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfd, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, - 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xf, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x2, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x80, 0x0, 0x15, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x54, 0x0, - - /* U+F090 "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x2, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0x40, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xff, 0x40, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, - 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, - 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3, 0xff, 0x40, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0x40, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xff, 0x40, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, - 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xf0, 0x3, - 0xff, 0x40, 0x2f, 0xc0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xfc, 0x3, 0xff, 0x40, 0xbf, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x1f, 0xff, 0x3, 0xff, 0x42, - 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, - 0xc3, 0xff, 0x4b, 0xff, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x7, 0xff, 0xf3, 0xff, 0x6f, 0xff, 0xc0, - 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xbf, 0xff, 0xff, 0xff, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, - 0xff, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x2, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xff, 0xfc, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x2f, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xb, 0xff, 0xc0, 0x0, 0x0, - 0x0, 0x0, 0x1f, 0x80, 0x0, 0x0, 0x2, 0xff, - 0x0, 0x0, 0x0, 0x2, 0xf4, 0x3f, 0xe0, 0x0, - 0x0, 0x0, 0x68, 0x0, 0x0, 0x0, 0xb, 0xfc, - 0x7f, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xfd, 0x7f, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0x7f, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xfd, 0x7f, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xfd, 0x7f, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0x7f, - 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xfd, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfd, 0x3f, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, - 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xf8, 0xf, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x2, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x80, 0x0, 0x15, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x54, 0x0, - - /* U+F15C "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x14, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xff, 0xfe, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x1f, 0xff, 0xff, 0xff, 0xe4, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xff, - 0xf4, 0x0, 0x6f, 0xff, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xfe, 0x0, - 0x0, 0x1, 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7, 0xff, 0xf4, 0x0, 0x0, - 0x0, 0x1f, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xff, 0xc0, 0x0, 0x0, 0x0, - 0x7, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x1f, 0xff, 0x0, 0x0, 0x0, 0x0, 0x1, - 0xff, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, - 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, - 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xfc, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xf0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfe, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7f, 0xff, 0xc0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7, 0xff, 0x0, 0x0, 0x0, - 0x0, 0x3, 0xff, 0xff, 0xc0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x1f, 0xff, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3, 0xff, 0x40, 0x0, 0x0, 0x0, 0x3f, - 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3, 0xff, 0x40, 0x0, 0x0, 0x0, 0xff, 0xff, - 0xe5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, - 0xff, 0xd4, 0x0, 0x0, 0x3, 0xff, 0xf8, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, - 0xff, 0x80, 0x0, 0x7, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xff, - 0xf4, 0x0, 0xf, 0xff, 0x40, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xff, 0xfd, - 0x0, 0x1f, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xff, 0xff, 0xff, 0x40, - 0x2f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x2, 0xaa, 0xff, 0xff, 0xc0, 0x3f, - 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xb, 0xff, 0xf0, 0x3f, 0xf4, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xf4, 0x3f, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0xf8, 0x7f, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x2f, 0xfc, 0x7f, 0xf0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x1f, 0xfc, 0x3f, 0xf0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xfd, 0x3f, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, - 0x3f, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfc, 0x2f, - 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, 0xf, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x3f, 0xfc, 0xf, 0xff, 0xc0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7f, 0xf8, 0x3, 0xff, 0xf4, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xff, 0xf0, 0x1, 0xff, 0xff, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, - 0xff, 0xe0, 0x0, 0xbf, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xc0, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, - 0x0, 0x7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x0, 0x0, - 0x0, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, - 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x0, 0x0, 0x0, - - /* U+F720 "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0x40, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x7f, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xff, 0x80, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x2f, 0xff, 0xff, 0xf4, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x1, 0xff, 0xff, 0xff, 0xff, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, - 0xff, 0xff, 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xbf, 0xff, 0xf8, 0x7f, 0xff, - 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, - 0xff, 0xc0, 0x7, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x7f, 0xff, 0xfd, 0x0, 0x0, 0xbf, - 0xff, 0xf8, 0x0, 0x0, 0x0, 0x7, 0xff, 0xff, - 0xe0, 0x0, 0x0, 0xf, 0xff, 0xff, 0x80, 0x0, - 0x0, 0x2f, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x1, - 0xff, 0xff, 0xf4, 0x0, 0x2, 0xff, 0xff, 0xf4, - 0x0, 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0x40, - 0xf, 0xff, 0xff, 0x40, 0x0, 0x0, 0x0, 0x0, - 0x2, 0xff, 0xff, 0xe0, 0x3f, 0xff, 0xf8, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0xf8, - 0xbf, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x7, 0xff, 0xfc, 0xff, 0xff, 0xc0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, 0xfd, - 0xff, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x7f, 0xff, 0xfe, 0xff, 0xff, 0xff, 0x40, - 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xf4, 0x0, 0x0, 0x0, 0x0, - 0x2f, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, - 0x0, 0x0, 0x0, 0x1, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xd2, 0xff, 0xff, 0xe0, 0x0, 0x0, 0xf, - 0xff, 0xff, 0x4f, 0xfe, 0xff, 0xd0, 0x7f, 0xff, - 0xfd, 0x0, 0x0, 0xbf, 0xff, 0xf8, 0xf, 0xfe, - 0xff, 0xd0, 0x7, 0xff, 0xff, 0xc0, 0x7, 0xff, - 0xff, 0xc0, 0xf, 0xfe, 0xff, 0xd0, 0x0, 0xbf, - 0xff, 0xf8, 0x7f, 0xff, 0xfd, 0x0, 0xf, 0xfe, - 0xff, 0xd0, 0x0, 0x1f, 0xff, 0xff, 0xff, 0xff, - 0xe0, 0x0, 0xf, 0xfe, 0xff, 0xd0, 0x0, 0x1, - 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0xf, 0xfe, - 0xff, 0xd0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xf4, - 0x0, 0x0, 0xf, 0xfe, 0xff, 0xd0, 0x0, 0x0, - 0x3, 0xff, 0xff, 0x80, 0x0, 0x0, 0xf, 0xfe, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x7f, 0xfc, 0x0, - 0x0, 0x0, 0xf, 0xfe, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x3f, 0xf4, 0x0, 0x0, 0x0, 0xf, 0xfe, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x3f, 0xf4, 0x0, - 0x0, 0x0, 0xf, 0xfe, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x3f, 0xf4, 0x0, 0x0, 0x0, 0xf, 0xfe, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x3f, 0xf4, 0x0, - 0x0, 0x0, 0xf, 0xfe, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x3f, 0xf4, 0x0, 0x0, 0x0, 0xf, 0xfe, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x3f, 0xf4, 0x0, - 0x0, 0x0, 0xf, 0xfe, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x3f, 0xf4, 0x0, 0x0, 0x0, 0xf, 0xfe, - 0xff, 0xd0, 0x0, 0x0, 0x0, 0x3f, 0xf4, 0x0, - 0x0, 0x0, 0xf, 0xfe, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x3f, 0xf4, 0x0, 0x0, 0x0, 0xf, 0xfe, - 0xff, 0xf8, 0x0, 0x0, 0x0, 0x3f, 0xf4, 0x0, - 0x0, 0x0, 0x7f, 0xfd, 0xbf, 0xff, 0x40, 0x0, - 0x0, 0x3f, 0xf4, 0x0, 0x0, 0x2, 0xff, 0xfc, - 0x3f, 0xff, 0xf0, 0x0, 0x0, 0x3f, 0xf4, 0x0, - 0x0, 0x2f, 0xff, 0xfc, 0x1f, 0xff, 0xfe, 0x0, - 0x0, 0x3f, 0xf4, 0x0, 0x1, 0xff, 0xff, 0xf0, - 0x7, 0xff, 0xff, 0xd0, 0x0, 0x3f, 0xf4, 0x0, - 0xb, 0xff, 0xff, 0x80, 0x0, 0x7f, 0xff, 0xfd, - 0x0, 0x3f, 0xf4, 0x0, 0xbf, 0xff, 0xfc, 0x0, - 0x0, 0xb, 0xff, 0xff, 0x80, 0x3f, 0xf4, 0x7, - 0xff, 0xff, 0xd0, 0x0, 0x0, 0x0, 0xff, 0xff, - 0xf8, 0x3f, 0xf4, 0x3f, 0xff, 0xfe, 0x0, 0x0, - 0x0, 0x0, 0x1f, 0xff, 0xff, 0x7f, 0xfa, 0xff, - 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x40, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, - 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, - 0xff, 0xff, 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7f, 0xff, 0xff, 0xfc, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xb, 0xff, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xfe, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x1b, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, - - /* U+F8C7 "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x7, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x29, 0x0, 0x0, 0x0, 0xf, - 0xfd, 0x0, 0x0, 0x0, 0xa, 0x40, 0x0, 0x0, - 0xf, 0xf4, 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, - 0x0, 0x3, 0xfd, 0x0, 0x0, 0x2, 0xff, 0xc0, - 0x0, 0x0, 0xf, 0xfd, 0x0, 0x0, 0x0, 0x7f, - 0xf0, 0x0, 0x0, 0x7f, 0xfc, 0x0, 0x0, 0x0, - 0xff, 0xd0, 0x0, 0x0, 0x7, 0xff, 0xc0, 0x0, - 0xf, 0xff, 0x40, 0x0, 0x0, 0xf, 0xfd, 0x0, - 0x0, 0x0, 0x3f, 0xfd, 0x0, 0x2, 0xff, 0xf0, - 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, 0x1, - 0xff, 0xf0, 0x0, 0x3f, 0xfc, 0x0, 0x0, 0x0, - 0xf, 0xfd, 0x0, 0x0, 0x0, 0xb, 0xff, 0x80, - 0xb, 0xff, 0x40, 0x0, 0x0, 0x0, 0xff, 0xd0, - 0x0, 0x0, 0x0, 0x3f, 0xfc, 0x0, 0xff, 0xf0, - 0x0, 0x0, 0x0, 0xf, 0xfd, 0x0, 0x0, 0x0, - 0x1, 0xff, 0xd0, 0x1f, 0xfe, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xd0, 0x0, 0x0, 0x0, 0xf, 0xff, - 0x2, 0xff, 0xc0, 0x0, 0x0, 0x0, 0xf, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0xbf, 0xf0, 0x3f, 0xf8, - 0x0, 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, - 0x0, 0x3, 0xff, 0x43, 0xff, 0x40, 0x0, 0x0, - 0x0, 0xf, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x3f, - 0xf8, 0x7f, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xff, - 0xd0, 0x0, 0x0, 0x0, 0x2, 0xff, 0xc7, 0xff, - 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x1f, 0xfc, 0xbf, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x1, - 0xff, 0xcb, 0xfe, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xfd, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfc, 0xbf, - 0xe0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xcf, 0xfe, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xfd, 0x0, 0x0, 0x0, 0x0, - 0xf, 0xfc, 0xbf, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0xbf, 0xc0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xcb, - 0xfe, 0x0, 0x0, 0x0, 0x0, 0x2, 0xe0, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xfc, 0xbf, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xff, 0xc7, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xfc, - 0x3f, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2, 0xff, 0x83, 0xff, 0x40, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0xf4, 0x3f, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xff, - 0x1, 0xff, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0xbf, 0xf0, 0xf, 0xfe, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xfe, 0x0, 0xbf, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, - 0xc0, 0x7, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3f, 0xf8, 0x0, 0x3f, - 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xff, 0x0, 0x0, 0xff, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, - 0xe0, 0x0, 0xb, 0xff, 0xc0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x7f, 0xfc, 0x0, 0x0, - 0x3f, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x1f, 0xff, 0x40, 0x0, 0x0, 0xff, 0xfc, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, - 0xe0, 0x0, 0x0, 0x7, 0xff, 0xf4, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x2, 0xff, 0xfc, 0x0, 0x0, - 0x0, 0x2f, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0xbf, - 0xff, 0xe0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xff, - 0xc0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xff, 0xe4, - 0x0, 0x0, 0x2, 0xff, 0xff, 0xf0, 0x0, 0x0, - 0x0, 0x0, 0x7, 0xff, 0xff, 0xfe, 0xa6, 0xaf, - 0xff, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xb, 0xff, 0xff, 0xff, 0xf9, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xaf, 0xfe, 0x90, 0x0, 0x0, 0x0, 0x0, - 0x0, - - /* U+FFF75 "󿽵" */ - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x54, 0x0, 0xf, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfd, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, - 0xf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x4f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfc, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x3, 0xff, 0xcf, 0xfd, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf, 0xfd, 0xff, 0xd0, 0x2, 0xf0, - 0x0, 0x0, 0x2f, 0x0, 0x0, 0x3, 0xf0, 0x0, - 0xff, 0xdf, 0xfd, 0x0, 0x3f, 0x80, 0x0, 0x3, - 0xf8, 0x0, 0x0, 0x7f, 0x80, 0xf, 0xfd, 0xff, - 0xd0, 0x3, 0xf8, 0x0, 0x0, 0x3f, 0x80, 0x0, - 0x7, 0xf4, 0x0, 0xff, 0xdf, 0xfd, 0x0, 0x1e, - 0x0, 0x0, 0x1, 0xe0, 0x0, 0x0, 0x2e, 0x0, - 0xf, 0xfd, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xdf, - 0xfe, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0xf, 0xfd, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xd0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xff, - 0xff, 0xe4, 0x0, 0x0, 0x7f, 0xfd, 0x0, 0x0, - 0x0, 0x0, 0x6, 0xff, 0xff, 0xff, 0xe0, 0x0, - 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x7, - 0xff, 0xff, 0xff, 0x90, 0x0, 0x0, 0x0, 0xf, - 0xfd, 0x0, 0x0, 0x0, 0x1b, 0xff, 0xff, 0xff, - 0x40, 0x0, 0xf8, 0x0, 0x0, 0xff, 0xd0, 0x0, - 0x0, 0x2f, 0xff, 0xff, 0xfe, 0x40, 0x0, 0x2f, - 0xc0, 0x0, 0xf, 0xfd, 0x0, 0x0, 0x6f, 0xff, - 0xff, 0xfd, 0x0, 0x0, 0x2, 0xfc, 0x0, 0x1, - 0xff, 0xd0, 0x0, 0xbf, 0xff, 0xff, 0xf8, 0x0, - 0x0, 0x0, 0xb, 0x40, 0x0, 0x7f, 0xfc, 0x0, - 0xbf, 0xff, 0xff, 0xf4, 0x0, 0x2f, 0x0, 0x0, - 0x0, 0x0, 0xbf, 0xff, 0x80, 0x7f, 0xff, 0xff, - 0xe0, 0x0, 0x3, 0xf8, 0x0, 0x0, 0x1, 0xff, - 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xd0, 0x0, 0x0, - 0x3f, 0x80, 0x0, 0x6, 0xff, 0xff, 0xfd, 0x3, - 0xff, 0xff, 0x80, 0x0, 0x0, 0x1, 0xe0, 0x0, - 0x1b, 0xff, 0xff, 0xff, 0x40, 0xbf, 0xfe, 0x40, - 0xf, 0xc0, 0x0, 0x0, 0x0, 0x2f, 0xff, 0xff, - 0xff, 0x80, 0xf, 0xff, 0x0, 0x1, 0xfd, 0x0, - 0x0, 0x0, 0x7f, 0xff, 0xff, 0xff, 0x40, 0x0, - 0xff, 0xe0, 0x0, 0x1f, 0xd0, 0x0, 0x1, 0xbf, - 0xff, 0xff, 0xfd, 0x0, 0x0, 0xf, 0xfe, 0x0, - 0x0, 0xb8, 0x0, 0x6, 0xff, 0xff, 0xff, 0xf8, - 0x0, 0x0, 0x0, 0xff, 0xf8, 0x0, 0x0, 0x0, - 0xb, 0xff, 0xff, 0xff, 0xe0, 0x0, 0x0, 0x0, - 0xf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfd, 0xff, 0xd1, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0xff, 0xdf, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0xff, - 0xd0, 0x1, 0xe0, 0x0, 0x0, 0x1e, 0x0, 0x0, - 0x2, 0xe0, 0x0, 0xff, 0xdf, 0xfd, 0x0, 0x3f, - 0x80, 0x0, 0x3, 0xf8, 0x0, 0x0, 0x7f, 0x40, - 0xf, 0xfd, 0xff, 0xd0, 0x3, 0xf8, 0x0, 0x0, - 0x3f, 0x80, 0x0, 0x7, 0xf8, 0x0, 0xff, 0xdf, - 0xfd, 0x0, 0x2f, 0x0, 0x0, 0x2, 0xf0, 0x0, - 0x0, 0x3f, 0x0, 0xf, 0xfd, 0xff, 0xe0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xdb, 0xff, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, - 0x7f, 0xfe, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x55, 0xff, 0xd3, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfd, 0x1f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xd0, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x1, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xd0, 0x1, 0xbf, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfd -}; - - -/*--------------------- - * GLYPH DESCRIPTION - *--------------------*/ - -static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { - {.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */, - {.bitmap_index = 0, .adv_w = 1024, .box_w = 38, .box_h = 38, .ofs_x = 13, .ofs_y = 13}, - {.bitmap_index = 361, .adv_w = 1024, .box_w = 54, .box_h = 44, .ofs_x = 5, .ofs_y = 10}, - {.bitmap_index = 955, .adv_w = 1024, .box_w = 32, .box_h = 52, .ofs_x = 14, .ofs_y = 6}, - {.bitmap_index = 1371, .adv_w = 1024, .box_w = 38, .box_h = 53, .ofs_x = 13, .ofs_y = 5}, - {.bitmap_index = 1875, .adv_w = 1024, .box_w = 58, .box_h = 60, .ofs_x = 3, .ofs_y = 2}, - {.bitmap_index = 2745, .adv_w = 1024, .box_w = 54, .box_h = 44, .ofs_x = 5, .ofs_y = 10}, - {.bitmap_index = 3339, .adv_w = 1024, .box_w = 54, .box_h = 54, .ofs_x = 5, .ofs_y = 5}, - {.bitmap_index = 4068, .adv_w = 1024, .box_w = 30, .box_h = 18, .ofs_x = 17, .ofs_y = 24}, - {.bitmap_index = 4203, .adv_w = 1024, .box_w = 54, .box_h = 44, .ofs_x = 5, .ofs_y = 10}, - {.bitmap_index = 4797, .adv_w = 1024, .box_w = 54, .box_h = 54, .ofs_x = 5, .ofs_y = 5}, - {.bitmap_index = 5526, .adv_w = 1024, .box_w = 48, .box_h = 48, .ofs_x = 8, .ofs_y = 8}, - {.bitmap_index = 6102, .adv_w = 1024, .box_w = 32, .box_h = 48, .ofs_x = 16, .ofs_y = 8}, - {.bitmap_index = 6486, .adv_w = 1024, .box_w = 42, .box_h = 47, .ofs_x = 11, .ofs_y = 8}, - {.bitmap_index = 6980, .adv_w = 1024, .box_w = 44, .box_h = 44, .ofs_x = 10, .ofs_y = 10}, - {.bitmap_index = 7464, .adv_w = 1024, .box_w = 36, .box_h = 36, .ofs_x = 14, .ofs_y = 14}, - {.bitmap_index = 7788, .adv_w = 1024, .box_w = 48, .box_h = 32, .ofs_x = 8, .ofs_y = 16}, - {.bitmap_index = 8172, .adv_w = 1024, .box_w = 12, .box_h = 44, .ofs_x = 26, .ofs_y = 10}, - {.bitmap_index = 8304, .adv_w = 1024, .box_w = 44, .box_h = 44, .ofs_x = 10, .ofs_y = 10}, - {.bitmap_index = 8788, .adv_w = 1024, .box_w = 62, .box_h = 46, .ofs_x = 1, .ofs_y = 8}, - {.bitmap_index = 9501, .adv_w = 1024, .box_w = 42, .box_h = 30, .ofs_x = 11, .ofs_y = 17}, - {.bitmap_index = 9816, .adv_w = 1024, .box_w = 49, .box_h = 44, .ofs_x = 10, .ofs_y = 10}, - {.bitmap_index = 10355, .adv_w = 1024, .box_w = 48, .box_h = 44, .ofs_x = 8, .ofs_y = 10}, - {.bitmap_index = 10883, .adv_w = 1024, .box_w = 44, .box_h = 54, .ofs_x = 10, .ofs_y = 5}, - {.bitmap_index = 11477, .adv_w = 1024, .box_w = 54, .box_h = 50, .ofs_x = 5, .ofs_y = 9}, - {.bitmap_index = 12152, .adv_w = 1024, .box_w = 52, .box_h = 54, .ofs_x = 6, .ofs_y = 5}, - {.bitmap_index = 12854, .adv_w = 1024, .box_w = 54, .box_h = 54, .ofs_x = 5, .ofs_y = 5}, - {.bitmap_index = 13583, .adv_w = 1024, .box_w = 40, .box_h = 54, .ofs_x = 12, .ofs_y = 5}, - {.bitmap_index = 14123, .adv_w = 1024, .box_w = 44, .box_h = 48, .ofs_x = 10, .ofs_y = 8}, - {.bitmap_index = 14651, .adv_w = 1024, .box_w = 54, .box_h = 44, .ofs_x = 5, .ofs_y = 10}, - {.bitmap_index = 15245, .adv_w = 1024, .box_w = 64, .box_h = 62, .ofs_x = 0, .ofs_y = 2}, - {.bitmap_index = 16237, .adv_w = 1024, .box_w = 48, .box_h = 48, .ofs_x = 8, .ofs_y = 8}, - {.bitmap_index = 16813, .adv_w = 1024, .box_w = 54, .box_h = 54, .ofs_x = 5, .ofs_y = 5}, - {.bitmap_index = 17542, .adv_w = 1024, .box_w = 48, .box_h = 48, .ofs_x = 8, .ofs_y = 8}, - {.bitmap_index = 18118, .adv_w = 1024, .box_w = 54, .box_h = 44, .ofs_x = 5, .ofs_y = 10}, - {.bitmap_index = 18712, .adv_w = 1024, .box_w = 54, .box_h = 49, .ofs_x = 5, .ofs_y = 7}, - {.bitmap_index = 19374, .adv_w = 1024, .box_w = 48, .box_h = 54, .ofs_x = 8, .ofs_y = 5}, - {.bitmap_index = 20022, .adv_w = 1024, .box_w = 44, .box_h = 54, .ofs_x = 10, .ofs_y = 5}, - {.bitmap_index = 20616, .adv_w = 1024, .box_w = 49, .box_h = 44, .ofs_x = 10, .ofs_y = 10}, - {.bitmap_index = 21155, .adv_w = 1024, .box_w = 54, .box_h = 54, .ofs_x = 5, .ofs_y = 5}, - {.bitmap_index = 21884, .adv_w = 1024, .box_w = 47, .box_h = 48, .ofs_x = 8, .ofs_y = 8}, - {.bitmap_index = 22448, .adv_w = 1024, .box_w = 48, .box_h = 48, .ofs_x = 8, .ofs_y = 8}, - {.bitmap_index = 23024, .adv_w = 1024, .box_w = 60, .box_h = 44, .ofs_x = 2, .ofs_y = 10}, - {.bitmap_index = 23684, .adv_w = 1024, .box_w = 44, .box_h = 44, .ofs_x = 10, .ofs_y = 10}, - {.bitmap_index = 24168, .adv_w = 1024, .box_w = 60, .box_h = 44, .ofs_x = 2, .ofs_y = 10}, - {.bitmap_index = 24828, .adv_w = 1024, .box_w = 48, .box_h = 54, .ofs_x = 8, .ofs_y = 5}, - {.bitmap_index = 25476, .adv_w = 1024, .box_w = 54, .box_h = 54, .ofs_x = 5, .ofs_y = 5}, - {.bitmap_index = 26205, .adv_w = 1024, .box_w = 54, .box_h = 54, .ofs_x = 5, .ofs_y = 5} -}; - -/*--------------------- - * CHARACTER MAPPING - *--------------------*/ - -static const uint16_t unicode_list_0[] = { - 0x0, 0x14, 0x62, 0x9b, 0x148, 0x182, 0x1ca, 0x1d1, - 0x1e1, 0x26a, 0x2af, 0x2c0, 0x418, 0x47e, 0x488, 0x48d, - 0x48f, 0x490, 0x4f9, 0x523, 0x600, 0x62b, 0x757, 0x76a, - 0x773, 0x7b8, 0x7ca, 0x7e9, 0x874, 0x8af, 0x8b2, 0x8c2, - 0x991, 0xa49, 0xa52, 0xa87, 0xad7, 0xdfb, 0xe05, 0xe35, - 0xea1, 0xee3, 0xf4b, 0x1017, 0x15db, 0x1782 -}; - -/*Collect the unicode lists and glyph_id offsets*/ -static const lv_font_fmt_txt_cmap_t cmaps[] = -{ - { - .range_start = 57669, .range_length = 6019, .glyph_id_start = 1, - .unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 46, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY - }, - { - .range_start = 1048437, .range_length = 1, .glyph_id_start = 47, - .unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY - } -}; - - - -/*-------------------- - * ALL CUSTOM DATA - *--------------------*/ - -#if LVGL_VERSION_MAJOR == 8 -/*Store all the custom data of the font*/ -static lv_font_fmt_txt_glyph_cache_t cache; -#endif - -#if LVGL_VERSION_MAJOR >= 8 -static const lv_font_fmt_txt_dsc_t font_dsc = { -#else -static lv_font_fmt_txt_dsc_t font_dsc = { -#endif - .glyph_bitmap = glyph_bitmap, - .glyph_dsc = glyph_dsc, - .cmaps = cmaps, - .kern_dsc = NULL, - .kern_scale = 0, - .cmap_num = 2, - .bpp = 2, - .kern_classes = 0, - .bitmap_format = 0, -#if LVGL_VERSION_MAJOR == 8 - .cache = &cache -#endif -}; - - - -/*----------------- - * PUBLIC FONT - *----------------*/ - -/*Initialize a public general font descriptor*/ -#if LVGL_VERSION_MAJOR >= 8 -const lv_font_t material_symbols_shared_64 = { -#else -lv_font_t material_symbols_shared_64 = { -#endif - .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ - .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ - .line_height = 62, /*The maximum line height required by the font*/ - .base_line = -2, /*Baseline measured from the bottom of the line*/ -#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) - .subpx = LV_FONT_SUBPX_NONE, -#endif -#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 - .underline_position = 0, - .underline_thickness = 0, -#endif - .dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ -#if LV_VERSION_CHECK(8, 2, 0) || LVGL_VERSION_MAJOR >= 9 - .fallback = NULL, -#endif - .user_data = NULL, -}; - - - -#endif /*#if MATERIAL_SYMBOLS_SHARED_64*/ - diff --git a/Modules/lvgl-module/source-fonts/material_symbols_statusbar_12.c b/Modules/lvgl-module/source-fonts/material_symbols_statusbar_12.c deleted file mode 100644 index 2da0fbd9f..000000000 --- a/Modules/lvgl-module/source-fonts/material_symbols_statusbar_12.c +++ /dev/null @@ -1,280 +0,0 @@ -/******************************************************************************* - * Size: 12 px - * Bpp: 2 - * Opts: --no-compress --no-prefilter --bpp 2 --size 12 --font MaterialSymbolsRounded.ttf -r 0xF1DB,0xF15C,0xE322,0xE623,0xF057,0xF0B0,0xEBE4,0xEBD6,0xEBE1,0xF065,0xE1DA,0xF064,0xF257,0xF256,0xF255,0xF254,0xF253,0xF252,0xF24F,0xF250,0xE1A7,0xE60F,0xE1A8,0xE1A9,0xE1E0 --format lvgl -o source-fonts/material_symbols_statusbar_12.c --force-fast-kern-format - ******************************************************************************/ - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -#ifndef MATERIAL_SYMBOLS_STATUSBAR_12 -#define MATERIAL_SYMBOLS_STATUSBAR_12 1 -#endif - -#if MATERIAL_SYMBOLS_STATUSBAR_12 - -/*----------------- - * BITMAPS - *----------------*/ - -/*Store the image of the glyphs*/ -static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { - /* U+E1A7 "" */ - 0x1, 0x40, 0xb, 0x47, 0x2b, 0x7, 0xec, 0x7, - 0xc0, 0x1f, 0x1, 0xfb, 0x1c, 0x9d, 0x2, 0xd0, - 0x9, 0x0, - - /* U+E1A8 "" */ - 0x0, 0x20, 0x0, 0x7, 0x80, 0xd, 0x7a, 0x0, - 0x3b, 0xd0, 0x20, 0xf4, 0x82, 0xf, 0x48, 0x3, - 0xbd, 0x0, 0xd6, 0xa0, 0x0, 0x7c, 0x0, 0x2, - 0x0, - - /* U+E1A9 "" */ - 0x0, 0x14, 0x0, 0xd0, 0xb4, 0x0, 0xd2, 0xb0, - 0x0, 0xd6, 0xc0, 0x0, 0xd4, 0x0, 0x2, 0xd0, - 0x0, 0x1f, 0xd0, 0x1, 0xca, 0xd0, 0x0, 0x2e, - 0xd0, 0x0, 0x90, 0xc0, 0x0, 0x0, 0x0, - - /* U+E1DA "" */ - 0x50, 0x0, 0x0, 0x38, 0xff, 0x80, 0x2e, 0x0, - 0x78, 0xa3, 0x80, 0xe, 0x34, 0xe0, 0x1c, 0xd, - 0x38, 0x70, 0x3, 0x4e, 0x0, 0x0, 0xd7, 0x80, - 0x0, 0x3c, 0xe0, 0x0, 0x0, 0x34, 0x0, 0x0, - 0x0, - - /* U+E1E0 "" */ - 0x2, 0x0, 0x7, 0x80, 0x3, 0x0, 0x73, 0x3c, - 0xb3, 0x3c, 0x33, 0x18, 0x3f, 0xf4, 0x3, 0x0, - 0x3, 0x40, 0x3, 0x40, - - /* U+E322 "" */ - 0x0, 0x0, 0x0, 0x77, 0x40, 0x2e, 0xab, 0x3, - 0x45, 0x34, 0x77, 0xf3, 0x83, 0x77, 0x34, 0x75, - 0xa3, 0x82, 0x55, 0x70, 0x1b, 0xfe, 0x0, 0x11, - 0x0, - - /* U+E60F "" */ - 0x1, 0x40, 0x0, 0x2d, 0x0, 0x72, 0xb0, 0x1, - 0xfb, 0xc, 0x7, 0xc8, 0x80, 0x7c, 0x88, 0x1f, - 0xb0, 0xc7, 0x27, 0x40, 0x2, 0xd0, 0x0, 0x24, - 0x0, - - /* U+E623 "" */ - 0x7, 0xff, 0x1c, 0x3, 0x70, 0x43, 0xc5, 0xd7, - 0xc0, 0x43, 0xc0, 0x3, 0xc0, 0x3, 0xc0, 0x3, - 0xc0, 0x3, 0xff, 0xff, - - /* U+EBD6 "" */ - 0x6, 0xff, 0x80, 0x3d, 0x0, 0xb8, 0xa0, 0x0, - 0xc, 0x30, 0x0, 0x28, 0x1d, 0xbd, 0xa0, 0x7, - 0xff, 0x80, 0x1, 0xfe, 0x0, 0x0, 0x78, 0x0, - 0x0, 0x0, 0x0, - - /* U+EBE1 "" */ - 0x6, 0xff, 0x80, 0x3d, 0x0, 0xb8, 0xa0, 0x0, - 0xc, 0x35, 0xfe, 0x28, 0x1f, 0xff, 0xe0, 0x7, - 0xff, 0x80, 0x1, 0xfe, 0x0, 0x0, 0x78, 0x0, - 0x0, 0x0, 0x0, - - /* U+EBE4 "" */ - 0x6, 0xff, 0x80, 0x3d, 0x0, 0xb8, 0xa0, 0x0, - 0xc, 0x30, 0x0, 0x28, 0x1c, 0x0, 0xa0, 0x7, - 0xba, 0x80, 0x1, 0xfe, 0x0, 0x0, 0x78, 0x0, - 0x0, 0x0, 0x0, - - /* U+F057 "" */ - 0x7, 0xff, 0x1c, 0x3, 0x70, 0x3, 0xc1, 0x43, - 0xc1, 0x43, 0xc1, 0x43, 0xc0, 0x3, 0xc0, 0x3, - 0xc0, 0x3, 0xff, 0xff, - - /* U+F064 "" */ - 0x6, 0xff, 0x80, 0x3d, 0x0, 0xb8, 0xa0, 0x0, - 0xd, 0x30, 0x0, 0x18, 0x1c, 0x0, 0x0, 0x7, - 0x0, 0xe8, 0x1, 0xd0, 0xb0, 0x0, 0x78, 0xe8, - 0x0, 0x0, 0x0, - - /* U+F065 "" */ - 0x6, 0xff, 0x80, 0x3f, 0xff, 0xf8, 0xbf, 0xff, - 0xfc, 0x3f, 0xff, 0xf8, 0x1f, 0xff, 0xe0, 0x7, - 0xff, 0x80, 0x1, 0xfe, 0x0, 0x0, 0x78, 0x0, - 0x0, 0x0, 0x0, - - /* U+F0B0 "" */ - 0x6, 0xff, 0x80, 0x3d, 0x0, 0xb8, 0xa0, 0x0, - 0xc, 0x30, 0x0, 0x28, 0x1c, 0x0, 0xa0, 0x7, - 0x2, 0x80, 0x1, 0xda, 0x0, 0x0, 0x78, 0x0, - 0x0, 0x0, 0x0, - - /* U+F15C "" */ - 0x0, 0xbd, 0x0, 0x3, 0x43, 0x40, 0x9, 0x0, - 0xc0, 0x38, 0x0, 0xd0, 0xa0, 0x0, 0x68, 0x90, - 0x0, 0xc, 0x70, 0x0, 0xc, 0x1f, 0xff, 0xf4, - - /* U+F1DB "" */ - 0xb, 0xe0, 0x34, 0x1c, 0x90, 0x6, 0xc3, 0xc3, - 0xc3, 0xc3, 0x90, 0x6, 0x30, 0xc, 0x1c, 0x34, - 0xb, 0xe0, 0x1, 0x40, - - /* U+F24F "" */ - 0x7f, 0xff, 0xe0, 0x96, 0xaa, 0x70, 0xaf, 0xff, - 0xb9, 0xaf, 0xff, 0xb9, 0x96, 0xaa, 0x70, 0x7f, - 0xff, 0xe0, - - /* U+F250 "" */ - 0x7f, 0xff, 0x0, 0x96, 0xa4, 0x20, 0xaf, 0xfc, - 0xf4, 0xaf, 0xf0, 0xb4, 0x96, 0x40, 0x20, 0x7f, - 0xfd, 0x0, - - /* U+F252 "" */ - 0x7f, 0xff, 0xe0, 0x96, 0xa9, 0x30, 0xaf, 0xff, - 0x39, 0xaf, 0xff, 0x39, 0x96, 0xa9, 0x30, 0x7f, - 0xff, 0xe0, - - /* U+F253 "" */ - 0x7f, 0xff, 0xe0, 0x96, 0xa4, 0x30, 0xaf, 0xfc, - 0x39, 0xaf, 0xfc, 0x39, 0x96, 0xa4, 0x30, 0x7f, - 0xff, 0xe0, - - /* U+F254 "" */ - 0x7f, 0xff, 0xe0, 0x96, 0x90, 0x30, 0xaf, 0xf0, - 0x39, 0xaf, 0xf0, 0x39, 0x96, 0x90, 0x30, 0x7f, - 0xff, 0xe0, - - /* U+F255 "" */ - 0x7f, 0xff, 0xe0, 0x96, 0x40, 0x30, 0xaf, 0xc0, - 0x39, 0xaf, 0xc0, 0x39, 0x96, 0x40, 0x30, 0x7f, - 0xff, 0xe0, - - /* U+F256 "" */ - 0x7f, 0xff, 0xe0, 0x95, 0x0, 0x30, 0xaf, 0x0, - 0x39, 0xaf, 0x0, 0x39, 0x95, 0x0, 0x30, 0x7f, - 0xff, 0xe0, - - /* U+F257 "" */ - 0x7f, 0xff, 0xe0, 0x94, 0x0, 0x30, 0xac, 0x0, - 0x39, 0xac, 0x0, 0x39, 0x94, 0x0, 0x30, 0x7f, - 0xff, 0xe0 -}; - - -/*--------------------- - * GLYPH DESCRIPTION - *--------------------*/ - -static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { - {.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */, - {.bitmap_index = 0, .adv_w = 192, .box_w = 7, .box_h = 10, .ofs_x = 2, .ofs_y = 1}, - {.bitmap_index = 18, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 43, .adv_w = 192, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 74, .adv_w = 192, .box_w = 12, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 107, .adv_w = 192, .box_w = 8, .box_h = 10, .ofs_x = 2, .ofs_y = 1}, - {.bitmap_index = 127, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 152, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 177, .adv_w = 192, .box_w = 8, .box_h = 10, .ofs_x = 2, .ofs_y = 1}, - {.bitmap_index = 197, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 224, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 251, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 278, .adv_w = 192, .box_w = 8, .box_h = 10, .ofs_x = 2, .ofs_y = 1}, - {.bitmap_index = 298, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 325, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 352, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 379, .adv_w = 192, .box_w = 12, .box_h = 8, .ofs_x = 0, .ofs_y = 2}, - {.bitmap_index = 403, .adv_w = 192, .box_w = 8, .box_h = 10, .ofs_x = 2, .ofs_y = 1}, - {.bitmap_index = 423, .adv_w = 192, .box_w = 12, .box_h = 6, .ofs_x = 0, .ofs_y = 3}, - {.bitmap_index = 441, .adv_w = 192, .box_w = 12, .box_h = 6, .ofs_x = 0, .ofs_y = 3}, - {.bitmap_index = 459, .adv_w = 192, .box_w = 12, .box_h = 6, .ofs_x = 0, .ofs_y = 3}, - {.bitmap_index = 477, .adv_w = 192, .box_w = 12, .box_h = 6, .ofs_x = 0, .ofs_y = 3}, - {.bitmap_index = 495, .adv_w = 192, .box_w = 12, .box_h = 6, .ofs_x = 0, .ofs_y = 3}, - {.bitmap_index = 513, .adv_w = 192, .box_w = 12, .box_h = 6, .ofs_x = 0, .ofs_y = 3}, - {.bitmap_index = 531, .adv_w = 192, .box_w = 12, .box_h = 6, .ofs_x = 0, .ofs_y = 3}, - {.bitmap_index = 549, .adv_w = 192, .box_w = 12, .box_h = 6, .ofs_x = 0, .ofs_y = 3} -}; - -/*--------------------- - * CHARACTER MAPPING - *--------------------*/ - -static const uint16_t unicode_list_0[] = { - 0x0, 0x1, 0x2, 0x33, 0x39, 0x17b, 0x468, 0x47c, - 0xa2f, 0xa3a, 0xa3d, 0xeb0, 0xebd, 0xebe, 0xf09, 0xfb5, - 0x1034, 0x10a8, 0x10a9, 0x10ab, 0x10ac, 0x10ad, 0x10ae, 0x10af, - 0x10b0 -}; - -/*Collect the unicode lists and glyph_id offsets*/ -static const lv_font_fmt_txt_cmap_t cmaps[] = -{ - { - .range_start = 57767, .range_length = 4273, .glyph_id_start = 1, - .unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 25, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY - } -}; - - - -/*-------------------- - * ALL CUSTOM DATA - *--------------------*/ - -#if LVGL_VERSION_MAJOR == 8 -/*Store all the custom data of the font*/ -static lv_font_fmt_txt_glyph_cache_t cache; -#endif - -#if LVGL_VERSION_MAJOR >= 8 -static const lv_font_fmt_txt_dsc_t font_dsc = { -#else -static lv_font_fmt_txt_dsc_t font_dsc = { -#endif - .glyph_bitmap = glyph_bitmap, - .glyph_dsc = glyph_dsc, - .cmaps = cmaps, - .kern_dsc = NULL, - .kern_scale = 0, - .cmap_num = 1, - .bpp = 2, - .kern_classes = 0, - .bitmap_format = 0, -#if LVGL_VERSION_MAJOR == 8 - .cache = &cache -#endif -}; - - - -/*----------------- - * PUBLIC FONT - *----------------*/ - -/*Initialize a public general font descriptor*/ -#if LVGL_VERSION_MAJOR >= 8 -const lv_font_t material_symbols_statusbar_12 = { -#else -lv_font_t material_symbols_statusbar_12 = { -#endif - .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ - .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ - .line_height = 11, /*The maximum line height required by the font*/ - .base_line = 0, /*Baseline measured from the bottom of the line*/ -#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) - .subpx = LV_FONT_SUBPX_NONE, -#endif -#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 - .underline_position = 0, - .underline_thickness = 0, -#endif - .dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ -#if LV_VERSION_CHECK(8, 2, 0) || LVGL_VERSION_MAJOR >= 9 - .fallback = NULL, -#endif - .user_data = NULL, -}; - - - -#endif /*#if MATERIAL_SYMBOLS_STATUSBAR_12*/ - diff --git a/Modules/lvgl-module/source-fonts/material_symbols_statusbar_16.c b/Modules/lvgl-module/source-fonts/material_symbols_statusbar_16.c deleted file mode 100644 index 85af971ee..000000000 --- a/Modules/lvgl-module/source-fonts/material_symbols_statusbar_16.c +++ /dev/null @@ -1,326 +0,0 @@ -/******************************************************************************* - * Size: 16 px - * Bpp: 2 - * Opts: --no-compress --no-prefilter --bpp 2 --size 16 --font MaterialSymbolsRounded.ttf -r 0xF1DB,0xF15C,0xE322,0xE623,0xF057,0xF0B0,0xEBE4,0xEBD6,0xEBE1,0xF065,0xE1DA,0xF064,0xF257,0xF256,0xF255,0xF254,0xF253,0xF252,0xF24F,0xF250,0xE1A7,0xE60F,0xE1A8,0xE1A9,0xE1E0 --format lvgl -o source-fonts/material_symbols_statusbar_16.c --force-fast-kern-format - ******************************************************************************/ - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -#ifndef MATERIAL_SYMBOLS_STATUSBAR_16 -#define MATERIAL_SYMBOLS_STATUSBAR_16 1 -#endif - -#if MATERIAL_SYMBOLS_STATUSBAR_16 - -/*----------------- - * BITMAPS - *----------------*/ - -/*Store the image of the glyphs*/ -static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { - /* U+E1A7 "" */ - 0x0, 0x40, 0x0, 0x3c, 0x1, 0xf, 0xc1, 0xd3, - 0x6c, 0x1d, 0xef, 0x1, 0xff, 0x0, 0x1f, 0x0, - 0xf, 0xd0, 0xf, 0xfd, 0xf, 0x36, 0xcb, 0xe, - 0xe0, 0x3, 0xe0, 0x0, 0xe0, 0x0, 0x0, 0x0, - - /* U+E1A8 "" */ - 0x0, 0x10, 0x0, 0x0, 0x3c, 0x0, 0x14, 0x3f, - 0x0, 0x1d, 0x36, 0xc0, 0x7, 0x77, 0xc0, 0x1, - 0xff, 0x0, 0xb0, 0xbc, 0xe, 0x60, 0xfd, 0x9, - 0x3, 0xff, 0x40, 0xf, 0x36, 0xc0, 0x2c, 0x3b, - 0x80, 0x0, 0x3e, 0x0, 0x0, 0x38, 0x0, 0x0, - 0x0, 0x0, - - /* U+E1A9 "" */ - 0x0, 0x4, 0x0, 0x38, 0x3, 0xc0, 0x7, 0x80, - 0xfc, 0x0, 0x78, 0x36, 0xc0, 0x7, 0x8a, 0xf0, - 0x0, 0x78, 0xb0, 0x0, 0x7, 0x80, 0x0, 0x0, - 0xf8, 0x0, 0x0, 0xff, 0x80, 0x0, 0xf3, 0xf8, - 0x0, 0xb0, 0xef, 0x80, 0x0, 0x3e, 0x78, 0x0, - 0xe, 0x7, 0x40, 0x0, 0x0, 0x40, - - /* U+E1DA "" */ - 0x0, 0x0, 0x0, 0x0, 0x34, 0x1, 0x40, 0x0, - 0x1d, 0x2f, 0xfe, 0x40, 0x1f, 0x40, 0x6, 0xf0, - 0x79, 0xd0, 0x0, 0x2d, 0xb4, 0x74, 0x0, 0x1d, - 0x2d, 0x1d, 0x0, 0x74, 0xb, 0x47, 0x41, 0xd0, - 0x2, 0xd1, 0xd1, 0x40, 0x0, 0xb4, 0x74, 0x0, - 0x0, 0x2d, 0x7d, 0x0, 0x0, 0xb, 0xd7, 0x40, - 0x0, 0x1, 0x41, 0xd0, 0x0, 0x0, 0x0, 0x70, - 0x0, 0x0, 0x0, 0x0, - - /* U+E1E0 "" */ - 0x0, 0x0, 0x0, 0xe, 0x0, 0x2, 0xf0, 0x0, - 0xe, 0x0, 0x10, 0xd1, 0x5b, 0xcd, 0x3e, 0x78, - 0xd3, 0xe3, 0x4d, 0x1c, 0x39, 0xe6, 0xc2, 0xff, - 0xf4, 0x0, 0xd0, 0x0, 0xe, 0x0, 0x1, 0xf0, - 0x0, 0xe, 0x0, - - /* U+E322 "" */ - 0x0, 0x21, 0x40, 0x0, 0x6e, 0xf5, 0x0, 0xff, - 0xff, 0xd0, 0x34, 0x0, 0x34, 0x3d, 0x3f, 0x8f, - 0x87, 0x4d, 0xb3, 0x81, 0xd3, 0x6c, 0xe0, 0xf4, - 0xfe, 0x3e, 0xd, 0x0, 0xd, 0x3, 0x95, 0x57, - 0x40, 0x7f, 0xff, 0xc0, 0x0, 0xca, 0x0, 0x0, - 0x0, 0x0, 0x0, - - /* U+E60F "" */ - 0x0, 0x40, 0x0, 0x0, 0xf0, 0x0, 0x50, 0xfc, - 0x0, 0x74, 0xdb, 0x0, 0x2d, 0xdf, 0x9, 0xb, - 0xfc, 0x7, 0x2, 0xf0, 0xd3, 0x3, 0xf4, 0xd3, - 0xf, 0xfd, 0x7, 0x3c, 0xdb, 0x9, 0xb0, 0xee, - 0x0, 0x0, 0xf8, 0x0, 0x0, 0xe0, 0x0, 0x0, - 0x0, 0x0, - - /* U+E623 "" */ - 0x0, 0x15, 0x54, 0x1, 0xff, 0xfc, 0x7, 0x80, - 0xd, 0x1e, 0x0, 0xd, 0x38, 0xdd, 0xdd, 0x70, - 0xdd, 0xdd, 0x70, 0x0, 0xd, 0x70, 0x0, 0xd, - 0x70, 0x0, 0xd, 0x70, 0x0, 0xd, 0x70, 0x0, - 0xd, 0x70, 0x0, 0xd, 0x7a, 0xaa, 0xad, 0x2a, - 0xaa, 0xa8, - - /* U+EBD6 "" */ - 0x0, 0x1, 0x40, 0x0, 0x1, 0xbf, 0xff, 0x40, - 0xf, 0x90, 0x6, 0xf4, 0x3c, 0x0, 0x0, 0x2d, - 0x38, 0x0, 0x0, 0x1d, 0x1e, 0x0, 0x0, 0x78, - 0x7, 0x8b, 0xe5, 0xe0, 0x1, 0xff, 0xff, 0x80, - 0x0, 0x7f, 0xfe, 0x0, 0x0, 0x1f, 0xf8, 0x0, - 0x0, 0x7, 0xe0, 0x0, 0x0, 0x0, 0x40, 0x0, - - /* U+EBE1 "" */ - 0x0, 0x1, 0x40, 0x0, 0x1, 0xbf, 0xff, 0x40, - 0xf, 0xd0, 0x6, 0xf4, 0x3d, 0x0, 0x0, 0x2d, - 0x34, 0x0, 0x0, 0xd, 0x1d, 0x2f, 0xf9, 0x38, - 0x7, 0xff, 0xff, 0xe0, 0x1, 0xff, 0xff, 0xc0, - 0x0, 0xbf, 0xff, 0x0, 0x0, 0x2f, 0xfc, 0x0, - 0x0, 0xb, 0xf0, 0x0, 0x0, 0x1, 0x80, 0x0, - - /* U+EBE4 "" */ - 0x0, 0x1, 0x40, 0x0, 0x1, 0xbf, 0xff, 0x40, - 0xf, 0x90, 0x6, 0xf4, 0x38, 0x0, 0x0, 0x2d, - 0x38, 0x0, 0x0, 0x1d, 0x1e, 0x0, 0x0, 0x78, - 0x7, 0x80, 0x1, 0xe0, 0x0, 0xe6, 0x97, 0x80, - 0x0, 0x3f, 0xfd, 0x0, 0x0, 0xf, 0xf4, 0x0, - 0x0, 0x3, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x0, - - /* U+F057 "" */ - 0x0, 0x15, 0x54, 0x1, 0xff, 0xfc, 0x7, 0x80, - 0xd, 0x1e, 0x0, 0xd, 0x38, 0x0, 0xd, 0x70, - 0x28, 0xd, 0x70, 0x28, 0xd, 0x70, 0x14, 0xd, - 0x70, 0x0, 0xd, 0x70, 0x28, 0xd, 0x70, 0x0, - 0xd, 0x70, 0x0, 0xd, 0x7a, 0xaa, 0xad, 0x2a, - 0xaa, 0xa8, - - /* U+F064 "" */ - 0x0, 0x1, 0x40, 0x0, 0x1, 0xbf, 0xff, 0x40, - 0xf, 0x90, 0x6, 0xf4, 0x38, 0x0, 0x0, 0x2d, - 0x38, 0x0, 0x0, 0x1d, 0x1e, 0x0, 0x0, 0x28, - 0x7, 0x80, 0x0, 0x0, 0x1, 0xe0, 0x2, 0x18, - 0x0, 0x78, 0x3, 0xf4, 0x0, 0x1e, 0x41, 0xf0, - 0x0, 0x7, 0xd3, 0x78, 0x0, 0x0, 0x0, 0x0, - - /* U+F065 "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xfe, 0x0, - 0xb, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xfc, - 0x3f, 0xff, 0xff, 0xfd, 0x2f, 0xff, 0xff, 0xfc, - 0xb, 0xff, 0xff, 0xf0, 0x2, 0xff, 0xff, 0xc0, - 0x0, 0xbf, 0xff, 0x0, 0x0, 0x2f, 0xfc, 0x0, - 0x0, 0xb, 0xf0, 0x0, 0x0, 0x1, 0x80, 0x0, - - /* U+F0B0 "" */ - 0x0, 0x1, 0x40, 0x0, 0x1, 0xbf, 0xff, 0x40, - 0xf, 0x90, 0x6, 0xf4, 0x3c, 0x0, 0x0, 0x2d, - 0x38, 0x0, 0x0, 0x1d, 0x1e, 0x0, 0x0, 0x78, - 0x7, 0x80, 0x1, 0xe0, 0x1, 0xe0, 0x7, 0x80, - 0x0, 0x78, 0x1e, 0x0, 0x0, 0x1e, 0x78, 0x0, - 0x0, 0x7, 0xe0, 0x0, 0x0, 0x0, 0x40, 0x0, - - /* U+F15C "" */ - 0x0, 0x1, 0x40, 0x0, 0x0, 0x2f, 0xf4, 0x0, - 0x0, 0xb4, 0x2d, 0x0, 0x1, 0xc0, 0xb, 0x0, - 0x7, 0xc0, 0x3, 0x40, 0x2e, 0x0, 0x3, 0xd0, - 0x34, 0x0, 0x2, 0xb8, 0x70, 0x0, 0x0, 0x1c, - 0x30, 0x0, 0x0, 0xd, 0x3c, 0x0, 0x0, 0x2c, - 0xf, 0xff, 0xff, 0xf4, 0x0, 0x55, 0x55, 0x40, - - /* U+F1DB "" */ - 0x0, 0x55, 0x0, 0x3, 0xff, 0xc0, 0xe, 0x0, - 0xb0, 0x3c, 0x0, 0x3c, 0x34, 0x14, 0x1c, 0x70, - 0x3c, 0xd, 0x70, 0x3c, 0xd, 0x34, 0x0, 0x1c, - 0x2c, 0x0, 0x38, 0xe, 0x0, 0xb0, 0x3, 0x41, - 0xc0, 0x1, 0xd7, 0x40, 0x0, 0x7d, 0x0, 0x0, - 0x0, 0x0, - - /* U+F24F "" */ - 0x2f, 0xff, 0xff, 0x80, 0x35, 0x55, 0x55, 0xd0, - 0x73, 0xff, 0xfd, 0xd4, 0x77, 0xff, 0xfd, 0xdc, - 0x77, 0xff, 0xfd, 0xdc, 0x77, 0xff, 0xfd, 0xd8, - 0x35, 0x55, 0x55, 0xd0, 0x2f, 0xff, 0xff, 0x80, - - /* U+F250 "" */ - 0x2f, 0xff, 0xfc, 0x0, 0x35, 0x55, 0x50, 0x50, - 0x73, 0xff, 0xe1, 0xc0, 0x77, 0xff, 0xc3, 0xe8, - 0x77, 0xff, 0x46, 0xf4, 0x73, 0xfe, 0x0, 0xe0, - 0x35, 0x55, 0x50, 0xc0, 0x2f, 0xff, 0xf0, 0x0, - - /* U+F252 "" */ - 0x2f, 0xff, 0xff, 0x80, 0x35, 0x55, 0x55, 0xd0, - 0x73, 0xff, 0xf4, 0xd4, 0x77, 0xff, 0xf4, 0xdc, - 0x77, 0xff, 0xf4, 0xdc, 0x77, 0xff, 0xf4, 0xd8, - 0x35, 0x55, 0x55, 0xd0, 0x2f, 0xff, 0xff, 0x80, - - /* U+F253 "" */ - 0x2f, 0xff, 0xff, 0x80, 0x35, 0x55, 0x55, 0xd0, - 0x73, 0xff, 0xc0, 0xd4, 0x77, 0xff, 0xc0, 0xdc, - 0x77, 0xff, 0xc0, 0xdc, 0x77, 0xff, 0xc0, 0xd8, - 0x35, 0x55, 0x55, 0xd0, 0x2f, 0xff, 0xff, 0x80, - - /* U+F254 "" */ - 0x2f, 0xff, 0xff, 0x80, 0x35, 0x55, 0x55, 0xd0, - 0x73, 0xfe, 0x0, 0xd4, 0x77, 0xff, 0x0, 0xdc, - 0x77, 0xff, 0x0, 0xdc, 0x77, 0xff, 0x0, 0xd8, - 0x35, 0x55, 0x55, 0xd0, 0x2f, 0xff, 0xff, 0x80, - - /* U+F255 "" */ - 0x2f, 0xff, 0xff, 0x80, 0x35, 0x55, 0x55, 0xd0, - 0x73, 0xf4, 0x0, 0xd4, 0x77, 0xf8, 0x0, 0xdc, - 0x77, 0xf8, 0x0, 0xdc, 0x77, 0xf8, 0x0, 0xd8, - 0x35, 0x55, 0x55, 0xd0, 0x2f, 0xff, 0xff, 0x80, - - /* U+F256 "" */ - 0x2f, 0xff, 0xff, 0x80, 0x35, 0x55, 0x55, 0xd0, - 0x73, 0xc0, 0x0, 0xd4, 0x77, 0xd0, 0x0, 0xdc, - 0x77, 0xd0, 0x0, 0xdc, 0x77, 0xc0, 0x0, 0xd8, - 0x35, 0x55, 0x55, 0xd0, 0x2f, 0xff, 0xff, 0x80, - - /* U+F257 "" */ - 0x2f, 0xff, 0xff, 0x80, 0x35, 0x55, 0x55, 0xd0, - 0x72, 0x0, 0x0, 0xd4, 0x77, 0x0, 0x0, 0xdc, - 0x77, 0x0, 0x0, 0xdc, 0x77, 0x0, 0x0, 0xd8, - 0x35, 0x55, 0x55, 0xd0, 0x2f, 0xff, 0xff, 0x80 -}; - - -/*--------------------- - * GLYPH DESCRIPTION - *--------------------*/ - -static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { - {.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */, - {.bitmap_index = 0, .adv_w = 256, .box_w = 9, .box_h = 14, .ofs_x = 3, .ofs_y = 1}, - {.bitmap_index = 32, .adv_w = 256, .box_w = 12, .box_h = 14, .ofs_x = 2, .ofs_y = 1}, - {.bitmap_index = 74, .adv_w = 256, .box_w = 13, .box_h = 14, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 120, .adv_w = 256, .box_w = 16, .box_h = 15, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 180, .adv_w = 256, .box_w = 10, .box_h = 14, .ofs_x = 3, .ofs_y = 1}, - {.bitmap_index = 215, .adv_w = 256, .box_w = 13, .box_h = 13, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 258, .adv_w = 256, .box_w = 12, .box_h = 14, .ofs_x = 2, .ofs_y = 1}, - {.bitmap_index = 300, .adv_w = 256, .box_w = 12, .box_h = 14, .ofs_x = 2, .ofs_y = 1}, - {.bitmap_index = 342, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 2}, - {.bitmap_index = 390, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 2}, - {.bitmap_index = 438, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 2}, - {.bitmap_index = 486, .adv_w = 256, .box_w = 12, .box_h = 14, .ofs_x = 2, .ofs_y = 1}, - {.bitmap_index = 528, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 2}, - {.bitmap_index = 576, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 2}, - {.bitmap_index = 624, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 2}, - {.bitmap_index = 672, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 2}, - {.bitmap_index = 720, .adv_w = 256, .box_w = 12, .box_h = 14, .ofs_x = 2, .ofs_y = 1}, - {.bitmap_index = 762, .adv_w = 256, .box_w = 16, .box_h = 8, .ofs_x = 0, .ofs_y = 4}, - {.bitmap_index = 794, .adv_w = 256, .box_w = 16, .box_h = 8, .ofs_x = 0, .ofs_y = 4}, - {.bitmap_index = 826, .adv_w = 256, .box_w = 16, .box_h = 8, .ofs_x = 0, .ofs_y = 4}, - {.bitmap_index = 858, .adv_w = 256, .box_w = 16, .box_h = 8, .ofs_x = 0, .ofs_y = 4}, - {.bitmap_index = 890, .adv_w = 256, .box_w = 16, .box_h = 8, .ofs_x = 0, .ofs_y = 4}, - {.bitmap_index = 922, .adv_w = 256, .box_w = 16, .box_h = 8, .ofs_x = 0, .ofs_y = 4}, - {.bitmap_index = 954, .adv_w = 256, .box_w = 16, .box_h = 8, .ofs_x = 0, .ofs_y = 4}, - {.bitmap_index = 986, .adv_w = 256, .box_w = 16, .box_h = 8, .ofs_x = 0, .ofs_y = 4} -}; - -/*--------------------- - * CHARACTER MAPPING - *--------------------*/ - -static const uint16_t unicode_list_0[] = { - 0x0, 0x1, 0x2, 0x33, 0x39, 0x17b, 0x468, 0x47c, - 0xa2f, 0xa3a, 0xa3d, 0xeb0, 0xebd, 0xebe, 0xf09, 0xfb5, - 0x1034, 0x10a8, 0x10a9, 0x10ab, 0x10ac, 0x10ad, 0x10ae, 0x10af, - 0x10b0 -}; - -/*Collect the unicode lists and glyph_id offsets*/ -static const lv_font_fmt_txt_cmap_t cmaps[] = -{ - { - .range_start = 57767, .range_length = 4273, .glyph_id_start = 1, - .unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 25, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY - } -}; - - - -/*-------------------- - * ALL CUSTOM DATA - *--------------------*/ - -#if LVGL_VERSION_MAJOR == 8 -/*Store all the custom data of the font*/ -static lv_font_fmt_txt_glyph_cache_t cache; -#endif - -#if LVGL_VERSION_MAJOR >= 8 -static const lv_font_fmt_txt_dsc_t font_dsc = { -#else -static lv_font_fmt_txt_dsc_t font_dsc = { -#endif - .glyph_bitmap = glyph_bitmap, - .glyph_dsc = glyph_dsc, - .cmaps = cmaps, - .kern_dsc = NULL, - .kern_scale = 0, - .cmap_num = 1, - .bpp = 2, - .kern_classes = 0, - .bitmap_format = 0, -#if LVGL_VERSION_MAJOR == 8 - .cache = &cache -#endif -}; - - - -/*----------------- - * PUBLIC FONT - *----------------*/ - -/*Initialize a public general font descriptor*/ -#if LVGL_VERSION_MAJOR >= 8 -const lv_font_t material_symbols_statusbar_16 = { -#else -lv_font_t material_symbols_statusbar_16 = { -#endif - .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ - .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ - .line_height = 15, /*The maximum line height required by the font*/ - .base_line = 0, /*Baseline measured from the bottom of the line*/ -#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) - .subpx = LV_FONT_SUBPX_NONE, -#endif -#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 - .underline_position = 0, - .underline_thickness = 0, -#endif - .dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ -#if LV_VERSION_CHECK(8, 2, 0) || LVGL_VERSION_MAJOR >= 9 - .fallback = NULL, -#endif - .user_data = NULL, -}; - - - -#endif /*#if MATERIAL_SYMBOLS_STATUSBAR_16*/ - diff --git a/Modules/lvgl-module/source-fonts/material_symbols_statusbar_20.c b/Modules/lvgl-module/source-fonts/material_symbols_statusbar_20.c deleted file mode 100644 index dbb2f4869..000000000 --- a/Modules/lvgl-module/source-fonts/material_symbols_statusbar_20.c +++ /dev/null @@ -1,394 +0,0 @@ -/******************************************************************************* - * Size: 20 px - * Bpp: 2 - * Opts: --no-compress --no-prefilter --bpp 2 --size 20 --font MaterialSymbolsRounded.ttf -r 0xF1DB,0xF15C,0xE322,0xE623,0xF057,0xF0B0,0xEBE4,0xEBD6,0xEBE1,0xF065,0xE1DA,0xF064,0xF257,0xF256,0xF255,0xF254,0xF253,0xF252,0xF24F,0xF250,0xE1A7,0xE60F,0xE1A8,0xE1A9,0xE1E0 --format lvgl -o source-fonts/material_symbols_statusbar_20.c --force-fast-kern-format - ******************************************************************************/ - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -#ifndef MATERIAL_SYMBOLS_STATUSBAR_20 -#define MATERIAL_SYMBOLS_STATUSBAR_20 1 -#endif - -#if MATERIAL_SYMBOLS_STATUSBAR_20 - -/*----------------- - * BITMAPS - *----------------*/ - -/*Store the image of the glyphs*/ -static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { - /* U+E1A7 "" */ - 0x0, 0x28, 0x0, 0x0, 0xf8, 0x1, 0x3, 0xf8, - 0x1e, 0xe, 0xb8, 0x2e, 0x38, 0xf0, 0x2e, 0xfb, - 0x80, 0x2f, 0xf8, 0x0, 0x2f, 0x80, 0x0, 0xbe, - 0x0, 0xb, 0xfe, 0x0, 0xbb, 0xee, 0xb, 0x8e, - 0x3c, 0x78, 0x3a, 0xe0, 0x40, 0xfe, 0x0, 0x3, - 0xe0, 0x0, 0xa, 0x0, - - /* U+E1A8 "" */ - 0x0, 0x2, 0x80, 0x0, 0x0, 0x3, 0xe0, 0x0, - 0x1, 0x3, 0xf8, 0x0, 0x7, 0x83, 0xae, 0x0, - 0x2, 0xe3, 0x8f, 0x0, 0x0, 0xbb, 0xee, 0x0, - 0x0, 0x2f, 0xf8, 0x0, 0x3d, 0xb, 0xe0, 0x7c, - 0x3d, 0xb, 0xe0, 0x7c, 0x0, 0x2f, 0xf8, 0x0, - 0x0, 0xbb, 0xee, 0x0, 0x2, 0xe3, 0x8f, 0x0, - 0x7, 0x83, 0xae, 0x0, 0x1, 0x3, 0xf8, 0x0, - 0x0, 0x3, 0xe0, 0x0, 0x0, 0x2, 0x80, 0x0, - - /* U+E1A9 "" */ - 0x0, 0x0, 0xa0, 0x0, 0x1d, 0x0, 0x3e, 0x0, - 0x3, 0xd0, 0xf, 0xe0, 0x0, 0x3d, 0x3, 0xae, - 0x0, 0x3, 0xd0, 0xe3, 0xc0, 0x0, 0x3d, 0x1a, - 0xe0, 0x0, 0x3, 0xd1, 0xe0, 0x0, 0x0, 0x3d, - 0x0, 0x0, 0x0, 0x3, 0xd0, 0x0, 0x0, 0x2, - 0xfd, 0x0, 0x0, 0x2, 0xef, 0xd0, 0x0, 0x2, - 0xe3, 0xfd, 0x0, 0x1, 0xe0, 0xeb, 0xd0, 0x0, - 0x10, 0x3f, 0xbd, 0x0, 0x0, 0xf, 0x83, 0xd0, - 0x0, 0x2, 0x80, 0x3c, 0x0, 0x0, 0x0, 0x1, - 0x0, - - /* U+E1DA "" */ - 0x34, 0x0, 0x0, 0x0, 0x0, 0x3d, 0x1, 0xaa, - 0x40, 0x0, 0xf, 0x47, 0xff, 0xfd, 0x0, 0xb, - 0xd0, 0x0, 0x6f, 0xd0, 0x3e, 0xf4, 0x0, 0x1, - 0xf8, 0xb8, 0x3d, 0x0, 0x0, 0x3d, 0x3d, 0xf, - 0x40, 0x0, 0xbc, 0xf, 0x43, 0xd0, 0x2, 0xf0, - 0x3, 0xd0, 0xf4, 0xb, 0xc0, 0x0, 0xf4, 0x3d, - 0xf, 0x0, 0x0, 0x3d, 0xf, 0x40, 0x0, 0x0, - 0xf, 0x43, 0xd0, 0x0, 0x0, 0x3, 0xd7, 0xf4, - 0x0, 0x0, 0x0, 0xff, 0x3d, 0x0, 0x0, 0x0, - 0x3c, 0xf, 0x40, 0x0, 0x0, 0x0, 0x3, 0xd0, - 0x0, 0x0, 0x0, 0x0, 0xe0, 0x0, 0x0, 0x0, - 0x0, 0x0, - - /* U+E1E0 "" */ - 0x0, 0x0, 0x0, 0x0, 0x28, 0x0, 0x0, 0x7d, - 0x0, 0x0, 0xff, 0x0, 0x0, 0x38, 0x0, 0x10, - 0x38, 0x14, 0xbc, 0x38, 0x7f, 0xfd, 0x38, 0x7f, - 0x7c, 0x38, 0x7f, 0x38, 0x38, 0x2c, 0x3d, 0x7d, - 0x6c, 0x2f, 0xff, 0xfc, 0x5, 0x7d, 0x50, 0x0, - 0x38, 0x0, 0x0, 0x3c, 0x0, 0x0, 0xbe, 0x0, - 0x0, 0x7d, 0x0, 0x0, 0x0, 0x0, - - /* U+E322 "" */ - 0x0, 0x0, 0x10, 0x0, 0x0, 0x2c, 0x34, 0x0, - 0x2, 0xbe, 0xfe, 0x80, 0xf, 0xff, 0xff, 0xe0, - 0xe, 0x0, 0x0, 0xe0, 0x2e, 0xa, 0x90, 0xf4, - 0x7e, 0x2f, 0xf4, 0xfd, 0xe, 0x2c, 0x74, 0xf0, - 0xe, 0x2c, 0x74, 0xf0, 0x7e, 0x2f, 0xf4, 0xfd, - 0x2e, 0xa, 0xa0, 0xf4, 0xe, 0x0, 0x0, 0xe0, - 0xf, 0xaa, 0xaa, 0xe0, 0x7, 0xff, 0xff, 0xc0, - 0x0, 0x2c, 0x34, 0x0, 0x0, 0x4, 0x20, 0x0, - - /* U+E60F "" */ - 0x0, 0x1c, 0x0, 0x0, 0x0, 0x2f, 0x0, 0x0, - 0x10, 0x2f, 0xc0, 0x0, 0x3c, 0x2d, 0xf0, 0x0, - 0x1f, 0x2c, 0xb8, 0x28, 0x7, 0xee, 0xf0, 0x2c, - 0x1, 0xff, 0xc1, 0xc, 0x0, 0x7f, 0xb, 0xd, - 0x0, 0x7f, 0xb, 0xd, 0x1, 0xff, 0xc1, 0xc, - 0x7, 0xee, 0xf0, 0x2c, 0x1f, 0x2c, 0xb8, 0x28, - 0x3c, 0x2d, 0xf0, 0x0, 0x10, 0x2f, 0xc0, 0x0, - 0x0, 0x2f, 0x0, 0x0, 0x0, 0x1c, 0x0, 0x0, - - /* U+E623 "" */ - 0x0, 0x1a, 0xaa, 0x40, 0xb, 0xff, 0xfd, 0x2, - 0xe0, 0x0, 0xe0, 0xb8, 0x0, 0xe, 0x2e, 0x10, - 0x4, 0xe7, 0x87, 0x3c, 0xce, 0xb0, 0x73, 0xdc, - 0xeb, 0x7, 0x3c, 0xce, 0xb0, 0x0, 0x0, 0xeb, - 0x0, 0x0, 0xe, 0xb0, 0x0, 0x0, 0xeb, 0x0, - 0x0, 0xe, 0xb0, 0x0, 0x0, 0xeb, 0x0, 0x0, - 0xe, 0xb0, 0x0, 0x0, 0xeb, 0x55, 0x55, 0x5e, - 0x7f, 0xff, 0xff, 0xd0, 0x55, 0x55, 0x50, - - /* U+EBD6 "" */ - 0x0, 0x1, 0xaa, 0x40, 0x0, 0x0, 0xbf, 0xff, - 0xfe, 0x0, 0x7, 0xf9, 0x0, 0x6f, 0xd0, 0x2f, - 0x40, 0x0, 0x1, 0xf8, 0x38, 0x0, 0x0, 0x0, - 0x2c, 0x3d, 0x0, 0x0, 0x0, 0x7c, 0xf, 0x40, - 0x0, 0x1, 0xf0, 0x3, 0xd1, 0xbe, 0x47, 0xc0, - 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x3f, 0xff, - 0xfc, 0x0, 0x0, 0xf, 0xff, 0xf0, 0x0, 0x0, - 0x3, 0xff, 0xc0, 0x0, 0x0, 0x0, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x28, 0x0, 0x0, - - /* U+EBE1 "" */ - 0x0, 0x1, 0xaa, 0x40, 0x0, 0x0, 0xbf, 0xff, - 0xfe, 0x0, 0x7, 0xf9, 0x0, 0x6f, 0xd0, 0x2f, - 0x40, 0x0, 0x1, 0xf8, 0x38, 0x0, 0x0, 0x0, - 0x2c, 0x3d, 0x1, 0xaa, 0x40, 0x7c, 0xf, 0x5f, - 0xff, 0xf5, 0xf0, 0x3, 0xff, 0xff, 0xff, 0xc0, - 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x3f, 0xff, - 0xfc, 0x0, 0x0, 0xf, 0xff, 0xf0, 0x0, 0x0, - 0x3, 0xff, 0xc0, 0x0, 0x0, 0x0, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x28, 0x0, 0x0, - - /* U+EBE4 "" */ - 0x0, 0x1, 0xaa, 0x40, 0x0, 0x0, 0xbf, 0xff, - 0xfe, 0x0, 0x7, 0xf9, 0x0, 0x6f, 0xd0, 0x2f, - 0x40, 0x0, 0x1, 0xf8, 0x38, 0x0, 0x0, 0x0, - 0x2c, 0x3d, 0x0, 0x0, 0x0, 0x7c, 0xf, 0x40, - 0x0, 0x1, 0xf0, 0x3, 0xd0, 0x0, 0x7, 0xc0, - 0x0, 0xf4, 0x0, 0x1f, 0x0, 0x0, 0x3e, 0xff, - 0xbc, 0x0, 0x0, 0xf, 0xff, 0xf0, 0x0, 0x0, - 0x3, 0xff, 0xc0, 0x0, 0x0, 0x0, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x28, 0x0, 0x0, - - /* U+F057 "" */ - 0x0, 0x1a, 0xaa, 0x40, 0xb, 0xff, 0xfd, 0x2, - 0xe0, 0x0, 0xe0, 0xb8, 0x0, 0xe, 0x2e, 0x0, - 0x0, 0xe7, 0x80, 0x50, 0xe, 0xb0, 0xf, 0x0, - 0xeb, 0x0, 0xf0, 0xe, 0xb0, 0xf, 0x0, 0xeb, - 0x0, 0xa0, 0xe, 0xb0, 0x0, 0x0, 0xeb, 0x0, - 0x0, 0xe, 0xb0, 0xa, 0x0, 0xeb, 0x0, 0x0, - 0xe, 0xb0, 0x0, 0x0, 0xeb, 0x55, 0x55, 0x5e, - 0x7f, 0xff, 0xff, 0xd0, 0x55, 0x55, 0x50, - - /* U+F064 "" */ - 0x0, 0x1, 0xaa, 0x40, 0x0, 0x0, 0xbf, 0xff, - 0xfe, 0x0, 0x7, 0xf9, 0x0, 0x6f, 0xd0, 0x2f, - 0x40, 0x0, 0x1, 0xf8, 0x38, 0x0, 0x0, 0x0, - 0x2c, 0x3d, 0x0, 0x0, 0x0, 0x7c, 0xf, 0x40, - 0x0, 0x0, 0xb0, 0x3, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x3d, 0x0, - 0x2d, 0xb4, 0x0, 0xf, 0x40, 0xf, 0xe0, 0x0, - 0x3, 0xd0, 0xb, 0xd0, 0x0, 0x0, 0xfe, 0x1f, - 0xf0, 0x0, 0x0, 0x3c, 0x18, 0x20, - - /* U+F065 "" */ - 0x0, 0x1, 0x69, 0x40, 0x0, 0x0, 0x7f, 0xff, - 0xfd, 0x0, 0x7, 0xff, 0xff, 0xff, 0xd0, 0x2f, - 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, - 0xfc, 0x3f, 0xff, 0xff, 0xff, 0xfc, 0xf, 0xff, - 0xff, 0xff, 0xf0, 0x3, 0xff, 0xff, 0xff, 0xc0, - 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x3f, 0xff, - 0xfc, 0x0, 0x0, 0xf, 0xff, 0xf0, 0x0, 0x0, - 0x3, 0xff, 0xc0, 0x0, 0x0, 0x0, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x28, 0x0, 0x0, - - /* U+F0B0 "" */ - 0x0, 0x1, 0xaa, 0x40, 0x0, 0x0, 0xbf, 0xff, - 0xfe, 0x0, 0x7, 0xf9, 0x0, 0x6f, 0xd0, 0x2f, - 0x40, 0x0, 0x1, 0xf8, 0x38, 0x0, 0x0, 0x0, - 0x2c, 0x3d, 0x0, 0x0, 0x0, 0x7c, 0xf, 0x40, - 0x0, 0x1, 0xf0, 0x3, 0xd0, 0x0, 0x7, 0xc0, - 0x0, 0xf4, 0x0, 0x1f, 0x0, 0x0, 0x3d, 0x0, - 0x7c, 0x0, 0x0, 0xf, 0x41, 0xf0, 0x0, 0x0, - 0x3, 0xd7, 0xc0, 0x0, 0x0, 0x0, 0xff, 0x0, - 0x0, 0x0, 0x0, 0x28, 0x0, 0x0, - - /* U+F15C "" */ - 0x0, 0x0, 0x69, 0x0, 0x0, 0x0, 0xb, 0xff, - 0xd0, 0x0, 0x0, 0x2f, 0x41, 0xf4, 0x0, 0x0, - 0x3c, 0x0, 0x3c, 0x0, 0x0, 0xb0, 0x0, 0x1d, - 0x0, 0x7, 0xf0, 0x0, 0xe, 0x0, 0x1f, 0x40, - 0x0, 0xf, 0x80, 0x3c, 0x0, 0x0, 0xf, 0xf0, - 0x38, 0x0, 0x0, 0x0, 0x3c, 0x38, 0x0, 0x0, - 0x0, 0x2c, 0x3c, 0x0, 0x0, 0x0, 0x2c, 0x1e, - 0x0, 0x0, 0x0, 0x7c, 0xb, 0xff, 0xff, 0xff, - 0xf0, 0x0, 0xaa, 0xaa, 0xaa, 0x80, - - /* U+F1DB "" */ - 0x0, 0x15, 0x40, 0x0, 0x1f, 0xff, 0x40, 0xb, - 0xd0, 0x7e, 0x2, 0xe0, 0x0, 0xb8, 0x3c, 0x0, - 0x3, 0xc7, 0x40, 0x50, 0x1d, 0xb0, 0x1f, 0x40, - 0xeb, 0x2, 0xf8, 0xe, 0xb0, 0xf, 0x0, 0xe7, - 0x80, 0x0, 0x2c, 0x3c, 0x0, 0x3, 0xc1, 0xf0, - 0x0, 0xf4, 0xb, 0x80, 0x2e, 0x0, 0x3e, 0xb, - 0xc0, 0x0, 0xfa, 0xf0, 0x0, 0x3, 0xfc, 0x0, - 0x0, 0xa, 0x0, 0x0, - - /* U+F24F "" */ - 0xf, 0xff, 0xff, 0xff, 0x0, 0x3e, 0xaa, 0xaa, - 0xab, 0xc0, 0x38, 0x6a, 0xaa, 0x92, 0xc0, 0x3a, - 0xff, 0xff, 0xfa, 0xcc, 0x3a, 0xff, 0xff, 0xfa, - 0xcc, 0x3a, 0xff, 0xff, 0xfa, 0xcc, 0x3a, 0xff, - 0xff, 0xfa, 0xcc, 0x38, 0x6a, 0xaa, 0x92, 0xc0, - 0x3e, 0xaa, 0xaa, 0xab, 0xc0, 0xf, 0xff, 0xff, - 0xff, 0x0, - - /* U+F250 "" */ - 0xf, 0xff, 0xff, 0xe0, 0x0, 0xfa, 0xaa, 0xaa, - 0x43, 0x3, 0x86, 0xaa, 0x90, 0x28, 0xe, 0xbf, - 0xff, 0xc2, 0xe0, 0x3a, 0xff, 0xfe, 0x1f, 0xf8, - 0xeb, 0xff, 0xe0, 0xbf, 0xc3, 0xaf, 0xff, 0x0, - 0x2d, 0xe, 0x1a, 0x90, 0x0, 0xe0, 0x3e, 0xaa, - 0xaa, 0x43, 0x0, 0x3f, 0xff, 0xff, 0x0, 0x0, - - /* U+F252 "" */ - 0xf, 0xff, 0xff, 0xff, 0x0, 0x3e, 0xaa, 0xaa, - 0xab, 0xc0, 0x38, 0x6a, 0xaa, 0x42, 0xc0, 0x3a, - 0xff, 0xff, 0xd2, 0xcc, 0x3a, 0xff, 0xff, 0xd2, - 0xcc, 0x3a, 0xff, 0xff, 0xd2, 0xcc, 0x3a, 0xff, - 0xff, 0xd2, 0xcc, 0x38, 0x6a, 0xaa, 0x42, 0xc0, - 0x3e, 0xaa, 0xaa, 0xab, 0xc0, 0xf, 0xff, 0xff, - 0xff, 0x0, - - /* U+F253 "" */ - 0xf, 0xff, 0xff, 0xff, 0x0, 0x3e, 0xaa, 0xaa, - 0xab, 0xc0, 0x38, 0x6a, 0xa4, 0x2, 0xc0, 0x3a, - 0xff, 0xfe, 0x2, 0xcc, 0x3a, 0xff, 0xfe, 0x2, - 0xcc, 0x3a, 0xff, 0xfe, 0x2, 0xcc, 0x3a, 0xff, - 0xfe, 0x2, 0xcc, 0x38, 0x6a, 0xa4, 0x2, 0xc0, - 0x3e, 0xaa, 0xaa, 0xab, 0xc0, 0xf, 0xff, 0xff, - 0xff, 0x0, - - /* U+F254 "" */ - 0xf, 0xff, 0xff, 0xff, 0x0, 0x3e, 0xaa, 0xaa, - 0xab, 0xc0, 0x38, 0x6a, 0x90, 0x2, 0xc0, 0x3a, - 0xff, 0xf0, 0x2, 0xcc, 0x3a, 0xff, 0xf0, 0x2, - 0xcc, 0x3a, 0xff, 0xf0, 0x2, 0xcc, 0x3a, 0xff, - 0xf0, 0x2, 0xcc, 0x38, 0x6a, 0x90, 0x2, 0xc0, - 0x3e, 0xaa, 0xaa, 0xab, 0xc0, 0xf, 0xff, 0xff, - 0xff, 0x0, - - /* U+F255 "" */ - 0xf, 0xff, 0xff, 0xff, 0x0, 0x3e, 0xaa, 0xaa, - 0xab, 0xc0, 0x38, 0x69, 0x0, 0x2, 0xc0, 0x3a, - 0xff, 0x40, 0x2, 0xcc, 0x3a, 0xff, 0x40, 0x2, - 0xcc, 0x3a, 0xff, 0x40, 0x2, 0xcc, 0x3a, 0xff, - 0x40, 0x2, 0xcc, 0x38, 0x69, 0x0, 0x2, 0xc0, - 0x3e, 0xaa, 0xaa, 0xab, 0xc0, 0xf, 0xff, 0xff, - 0xff, 0x0, - - /* U+F256 "" */ - 0xf, 0xff, 0xff, 0xff, 0x0, 0x3e, 0xaa, 0xaa, - 0xab, 0xc0, 0x38, 0x50, 0x0, 0x2, 0xc0, 0x3a, - 0xf8, 0x0, 0x2, 0xcc, 0x3a, 0xf8, 0x0, 0x2, - 0xcc, 0x3a, 0xf8, 0x0, 0x2, 0xcc, 0x3a, 0xf8, - 0x0, 0x2, 0xcc, 0x38, 0x50, 0x0, 0x2, 0xc0, - 0x3e, 0xaa, 0xaa, 0xab, 0xc0, 0xf, 0xff, 0xff, - 0xff, 0x0, - - /* U+F257 "" */ - 0xf, 0xff, 0xff, 0xff, 0x0, 0x3e, 0xaa, 0xaa, - 0xab, 0xc0, 0x38, 0x40, 0x0, 0x2, 0xc0, 0x3a, - 0xc0, 0x0, 0x2, 0xcc, 0x3a, 0xc0, 0x0, 0x2, - 0xcc, 0x3a, 0xc0, 0x0, 0x2, 0xcc, 0x3a, 0xc0, - 0x0, 0x2, 0xcc, 0x38, 0x40, 0x0, 0x2, 0xc0, - 0x3e, 0xaa, 0xaa, 0xab, 0xc0, 0xf, 0xff, 0xff, - 0xff, 0x0 -}; - - -/*--------------------- - * GLYPH DESCRIPTION - *--------------------*/ - -static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { - {.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */, - {.bitmap_index = 0, .adv_w = 320, .box_w = 11, .box_h = 16, .ofs_x = 4, .ofs_y = 2}, - {.bitmap_index = 44, .adv_w = 320, .box_w = 16, .box_h = 16, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 108, .adv_w = 320, .box_w = 17, .box_h = 17, .ofs_x = 1, .ofs_y = 1}, - {.bitmap_index = 181, .adv_w = 320, .box_w = 20, .box_h = 18, .ofs_x = 0, .ofs_y = 0}, - {.bitmap_index = 271, .adv_w = 320, .box_w = 12, .box_h = 18, .ofs_x = 4, .ofs_y = 1}, - {.bitmap_index = 325, .adv_w = 320, .box_w = 16, .box_h = 16, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 389, .adv_w = 320, .box_w = 16, .box_h = 16, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 453, .adv_w = 320, .box_w = 14, .box_h = 18, .ofs_x = 3, .ofs_y = 1}, - {.bitmap_index = 516, .adv_w = 320, .box_w = 20, .box_h = 14, .ofs_x = 0, .ofs_y = 3}, - {.bitmap_index = 586, .adv_w = 320, .box_w = 20, .box_h = 14, .ofs_x = 0, .ofs_y = 3}, - {.bitmap_index = 656, .adv_w = 320, .box_w = 20, .box_h = 14, .ofs_x = 0, .ofs_y = 3}, - {.bitmap_index = 726, .adv_w = 320, .box_w = 14, .box_h = 18, .ofs_x = 3, .ofs_y = 1}, - {.bitmap_index = 789, .adv_w = 320, .box_w = 20, .box_h = 14, .ofs_x = 0, .ofs_y = 3}, - {.bitmap_index = 859, .adv_w = 320, .box_w = 20, .box_h = 14, .ofs_x = 0, .ofs_y = 3}, - {.bitmap_index = 929, .adv_w = 320, .box_w = 20, .box_h = 14, .ofs_x = 0, .ofs_y = 3}, - {.bitmap_index = 999, .adv_w = 320, .box_w = 20, .box_h = 14, .ofs_x = 0, .ofs_y = 3}, - {.bitmap_index = 1069, .adv_w = 320, .box_w = 14, .box_h = 17, .ofs_x = 3, .ofs_y = 2}, - {.bitmap_index = 1129, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 5}, - {.bitmap_index = 1179, .adv_w = 320, .box_w = 19, .box_h = 10, .ofs_x = 0, .ofs_y = 5}, - {.bitmap_index = 1227, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 5}, - {.bitmap_index = 1277, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 5}, - {.bitmap_index = 1327, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 5}, - {.bitmap_index = 1377, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 5}, - {.bitmap_index = 1427, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 5}, - {.bitmap_index = 1477, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 5} -}; - -/*--------------------- - * CHARACTER MAPPING - *--------------------*/ - -static const uint16_t unicode_list_0[] = { - 0x0, 0x1, 0x2, 0x33, 0x39, 0x17b, 0x468, 0x47c, - 0xa2f, 0xa3a, 0xa3d, 0xeb0, 0xebd, 0xebe, 0xf09, 0xfb5, - 0x1034, 0x10a8, 0x10a9, 0x10ab, 0x10ac, 0x10ad, 0x10ae, 0x10af, - 0x10b0 -}; - -/*Collect the unicode lists and glyph_id offsets*/ -static const lv_font_fmt_txt_cmap_t cmaps[] = -{ - { - .range_start = 57767, .range_length = 4273, .glyph_id_start = 1, - .unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 25, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY - } -}; - - - -/*-------------------- - * ALL CUSTOM DATA - *--------------------*/ - -#if LVGL_VERSION_MAJOR == 8 -/*Store all the custom data of the font*/ -static lv_font_fmt_txt_glyph_cache_t cache; -#endif - -#if LVGL_VERSION_MAJOR >= 8 -static const lv_font_fmt_txt_dsc_t font_dsc = { -#else -static lv_font_fmt_txt_dsc_t font_dsc = { -#endif - .glyph_bitmap = glyph_bitmap, - .glyph_dsc = glyph_dsc, - .cmaps = cmaps, - .kern_dsc = NULL, - .kern_scale = 0, - .cmap_num = 1, - .bpp = 2, - .kern_classes = 0, - .bitmap_format = 0, -#if LVGL_VERSION_MAJOR == 8 - .cache = &cache -#endif -}; - - - -/*----------------- - * PUBLIC FONT - *----------------*/ - -/*Initialize a public general font descriptor*/ -#if LVGL_VERSION_MAJOR >= 8 -const lv_font_t material_symbols_statusbar_20 = { -#else -lv_font_t material_symbols_statusbar_20 = { -#endif - .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ - .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ - .line_height = 19, /*The maximum line height required by the font*/ - .base_line = 0, /*Baseline measured from the bottom of the line*/ -#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) - .subpx = LV_FONT_SUBPX_NONE, -#endif -#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 - .underline_position = 0, - .underline_thickness = 0, -#endif - .dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ -#if LV_VERSION_CHECK(8, 2, 0) || LVGL_VERSION_MAJOR >= 9 - .fallback = NULL, -#endif - .user_data = NULL, -}; - - - -#endif /*#if MATERIAL_SYMBOLS_STATUSBAR_20*/ - diff --git a/Modules/lvgl-module/source-fonts/material_symbols_statusbar_30.c b/Modules/lvgl-module/source-fonts/material_symbols_statusbar_30.c deleted file mode 100644 index 8afa3dbc4..000000000 --- a/Modules/lvgl-module/source-fonts/material_symbols_statusbar_30.c +++ /dev/null @@ -1,612 +0,0 @@ -/******************************************************************************* - * Size: 30 px - * Bpp: 2 - * Opts: --no-compress --no-prefilter --bpp 2 --size 30 --font MaterialSymbolsRounded.ttf -r 0xF1DB,0xF15C,0xE322,0xE623,0xF057,0xF0B0,0xEBE4,0xEBD6,0xEBE1,0xF065,0xE1DA,0xF064,0xF257,0xF256,0xF255,0xF254,0xF253,0xF252,0xF24F,0xF250,0xE1A7,0xE60F,0xE1A8,0xE1A9,0xE1E0 --format lvgl -o source-fonts/material_symbols_statusbar_30.c --force-fast-kern-format - ******************************************************************************/ - -#ifdef LV_LVGL_H_INCLUDE_SIMPLE -#include "lvgl.h" -#else -#include "lvgl/lvgl.h" -#endif - -#ifndef MATERIAL_SYMBOLS_STATUSBAR_30 -#define MATERIAL_SYMBOLS_STATUSBAR_30 1 -#endif - -#if MATERIAL_SYMBOLS_STATUSBAR_30 - -/*----------------- - * BITMAPS - *----------------*/ - -/*Store the image of the glyphs*/ -static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { - /* U+E1A7 "" */ - 0x0, 0x0, 0xb0, 0x0, 0x0, 0x0, 0xfc, 0x0, - 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0xff, 0xc0, - 0x3d, 0x0, 0xff, 0xf0, 0x3f, 0x40, 0xf5, 0xfc, - 0xf, 0xd0, 0xf4, 0x7e, 0x3, 0xf4, 0xf4, 0xfd, - 0x0, 0xfe, 0xfb, 0xf4, 0x0, 0x3f, 0xff, 0xd0, - 0x0, 0xf, 0xff, 0x40, 0x0, 0x3, 0xfd, 0x0, - 0x0, 0x3, 0xfd, 0x0, 0x0, 0xf, 0xff, 0x40, - 0x0, 0x3f, 0xff, 0xd0, 0x0, 0xfe, 0xfb, 0xf4, - 0x3, 0xf4, 0xf4, 0xfd, 0xf, 0xd0, 0xf4, 0x7e, - 0x3f, 0x40, 0xf5, 0xfc, 0x3d, 0x0, 0xff, 0xf0, - 0x0, 0x0, 0xff, 0xc0, 0x0, 0x0, 0xff, 0x0, - 0x0, 0x0, 0xfc, 0x0, 0x0, 0x0, 0xb0, 0x0, - - /* U+E1A8 "" */ - 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xfc, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xc0, 0x0, 0x3, 0xd0, - 0xf, 0xff, 0x0, 0x0, 0x3f, 0x40, 0xf5, 0xfc, - 0x0, 0x0, 0xfd, 0xf, 0x47, 0xe0, 0x0, 0x3, - 0xf4, 0xf4, 0xfd, 0x0, 0x0, 0xf, 0xef, 0xbf, - 0x40, 0x0, 0x0, 0x3f, 0xff, 0xd0, 0x0, 0x2d, - 0x0, 0xff, 0xf4, 0x7, 0x8b, 0xf0, 0x3, 0xfd, - 0x0, 0xfe, 0xbf, 0x0, 0x3f, 0xd0, 0xf, 0xe2, - 0xd0, 0xf, 0xff, 0x40, 0x78, 0x0, 0x3, 0xff, - 0xfd, 0x0, 0x0, 0x0, 0xfe, 0xfb, 0xf4, 0x0, - 0x0, 0x3f, 0x4f, 0x4f, 0xd0, 0x0, 0xf, 0xd0, - 0xf4, 0x7e, 0x0, 0x3, 0xf4, 0xf, 0x5f, 0xc0, - 0x0, 0x3d, 0x0, 0xff, 0xf0, 0x0, 0x0, 0x0, - 0xf, 0xfc, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, - 0x0, 0x0, 0x0, 0xf, 0xc0, 0x0, 0x0, 0x0, - 0x0, 0xb0, 0x0, 0x0, - - /* U+E1A9 "" */ - 0x0, 0x0, 0x0, 0xb0, 0x0, 0x0, 0x1e, 0x0, - 0x0, 0x3f, 0x0, 0x0, 0x7, 0xe0, 0x0, 0xf, - 0xf0, 0x0, 0x0, 0xfe, 0x0, 0x3, 0xff, 0x0, - 0x0, 0xf, 0xe0, 0x0, 0xff, 0xf0, 0x0, 0x0, - 0xfe, 0x0, 0x3d, 0x7f, 0x0, 0x0, 0xf, 0xe0, - 0xf, 0x47, 0xe0, 0x0, 0x0, 0xfe, 0x3, 0xd3, - 0xf4, 0x0, 0x0, 0xf, 0xe0, 0x3b, 0xf4, 0x0, - 0x0, 0x0, 0xfe, 0x3, 0xf4, 0x0, 0x0, 0x0, - 0xf, 0xe0, 0x34, 0x0, 0x0, 0x0, 0x0, 0xfe, - 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xe0, 0x0, - 0x0, 0x0, 0x0, 0x3, 0xfe, 0x0, 0x0, 0x0, - 0x0, 0x3, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x3, - 0xfb, 0xfe, 0x0, 0x0, 0x0, 0x3, 0xf4, 0xff, - 0xe0, 0x0, 0x0, 0x3, 0xf4, 0x3d, 0xfe, 0x0, - 0x0, 0x3, 0xf4, 0xf, 0x5f, 0xe0, 0x0, 0x0, - 0xf4, 0x3, 0xff, 0xfe, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xdf, 0xe0, 0x0, 0x0, 0x0, 0x3f, 0xc0, - 0xfe, 0x0, 0x0, 0x0, 0xf, 0xc0, 0xf, 0xe0, - 0x0, 0x0, 0x2, 0xc0, 0x0, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0x0, 0xa, 0x0, - - /* U+E1DA "" */ - 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, - 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xd0, 0x6, 0xff, 0xf9, 0x0, 0x0, 0x0, 0x3f, - 0x40, 0xff, 0xff, 0xff, 0x80, 0x0, 0x1, 0xfd, - 0xb, 0xaa, 0xaf, 0xff, 0x80, 0x0, 0x2f, 0xf4, - 0x0, 0x0, 0x7, 0xff, 0x40, 0xf, 0xff, 0xd0, - 0x0, 0x0, 0x2, 0xfe, 0x7, 0xf8, 0x3f, 0x40, - 0x0, 0x0, 0x3, 0xfc, 0xbe, 0x0, 0xfd, 0x0, - 0x0, 0x0, 0xf, 0xc3, 0xf8, 0x3, 0xf4, 0x0, - 0x0, 0x3, 0xf8, 0xf, 0xe0, 0xf, 0xd0, 0x0, - 0x0, 0xfe, 0x0, 0x3f, 0x80, 0x3f, 0x40, 0x0, - 0x3f, 0x80, 0x0, 0xfe, 0x0, 0xfd, 0x0, 0xf, - 0xe0, 0x0, 0x3, 0xf8, 0x3, 0xf4, 0x3, 0xf8, - 0x0, 0x0, 0xf, 0xe0, 0xf, 0xd0, 0x3e, 0x0, - 0x0, 0x0, 0x3f, 0x80, 0x3f, 0x40, 0x0, 0x0, - 0x0, 0x0, 0xfe, 0x0, 0xfd, 0x0, 0x0, 0x0, - 0x0, 0x3, 0xf8, 0x7, 0xf4, 0x0, 0x0, 0x0, - 0x0, 0xf, 0xe0, 0xff, 0xd0, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0xbf, 0xbf, 0x40, 0x0, 0x0, 0x0, - 0x0, 0xff, 0xe0, 0xfd, 0x0, 0x0, 0x0, 0x0, - 0x3, 0xf8, 0x3, 0xf4, 0x0, 0x0, 0x0, 0x0, - 0x9, 0x0, 0xf, 0xd0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x3f, 0x40, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x2, 0x0, - - /* U+E1E0 "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0x0, - 0x0, 0x0, 0x2, 0xf4, 0x0, 0x0, 0x0, 0x7f, - 0xc0, 0x0, 0x0, 0xf, 0xff, 0x0, 0x0, 0x0, - 0x6f, 0x90, 0x0, 0x0, 0x1, 0xf0, 0x0, 0x0, - 0x0, 0x1f, 0x0, 0x0, 0x2f, 0x1, 0xf0, 0x3f, - 0xfb, 0xfc, 0x1f, 0x3, 0xff, 0xbf, 0xc1, 0xf0, - 0x3f, 0xfb, 0xfc, 0x1f, 0x3, 0xff, 0x2f, 0x1, - 0xf0, 0x3f, 0xf2, 0xf0, 0x1f, 0x0, 0xf8, 0x2f, - 0x1, 0xf0, 0xf, 0x81, 0xfa, 0xaf, 0xaa, 0xf8, - 0x1f, 0xff, 0xff, 0xff, 0x40, 0x7f, 0xff, 0xff, - 0xe0, 0x0, 0x1, 0xf0, 0x0, 0x0, 0x0, 0x1f, - 0x0, 0x0, 0x0, 0x1, 0xf0, 0x0, 0x0, 0x0, - 0x3f, 0xc0, 0x0, 0x0, 0xb, 0xfc, 0x0, 0x0, - 0x0, 0xbf, 0xc0, 0x0, 0x0, 0x3, 0xf8, 0x0, - 0x0, 0x0, 0x5, 0x0, 0x0, - - /* U+E322 "" */ - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xb4, 0x2d, 0x0, 0x0, 0x0, 0x0, 0xf8, 0x3e, - 0x0, 0x0, 0x0, 0x6a, 0xfe, 0xbf, 0xa4, 0x0, - 0x1, 0xff, 0xff, 0xff, 0xff, 0x0, 0x3, 0xff, - 0xff, 0xff, 0xff, 0x40, 0x3, 0xe0, 0x0, 0x0, - 0xf, 0x80, 0x3, 0xe0, 0x0, 0x0, 0xf, 0x80, - 0x2b, 0xe0, 0x6a, 0xa8, 0xf, 0xe4, 0x7f, 0xe0, - 0xff, 0xfe, 0xf, 0xfc, 0x3f, 0xe0, 0xff, 0xfe, - 0xf, 0xf8, 0x3, 0xe0, 0xf8, 0x3e, 0xf, 0x80, - 0x3, 0xe0, 0xf8, 0x3e, 0xf, 0x80, 0x2b, 0xe0, - 0xfe, 0xbe, 0xf, 0xe4, 0x7f, 0xe0, 0xff, 0xfe, - 0xf, 0xfc, 0x3f, 0xe0, 0x7f, 0xfc, 0xf, 0xf8, - 0x3, 0xe0, 0x0, 0x0, 0xf, 0x80, 0x3, 0xe0, - 0x0, 0x0, 0xf, 0x80, 0x3, 0xfa, 0xaa, 0xaa, - 0xaf, 0x80, 0x2, 0xff, 0xff, 0xff, 0xff, 0x40, - 0x0, 0xbf, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x0, - 0xf8, 0x3e, 0x0, 0x0, 0x0, 0x0, 0xf4, 0x3d, - 0x0, 0x0, 0x0, 0x0, 0x10, 0x4, 0x0, 0x0, - - /* U+E60F "" */ - 0x0, 0x2, 0xd0, 0x0, 0x0, 0x0, 0x0, 0xf, - 0xd0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0xd0, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xd0, 0x0, 0x0, 0xb8, - 0x3, 0xff, 0xd0, 0x0, 0x2, 0xf8, 0xf, 0x9f, - 0xd0, 0x0, 0x3, 0xf8, 0x3e, 0x1f, 0xc0, 0x28, - 0x3, 0xf8, 0xf8, 0xfe, 0x0, 0xf0, 0x3, 0xfb, - 0xef, 0xe0, 0x2, 0xe0, 0x3, 0xff, 0xfe, 0x0, - 0x7, 0xc0, 0x3, 0xff, 0xe0, 0x3c, 0xf, 0x0, - 0x3, 0xfe, 0x3, 0xf0, 0x3c, 0x0, 0xf, 0xf8, - 0xf, 0xc0, 0xf0, 0x0, 0xff, 0xf8, 0xf, 0x3, - 0xc0, 0xf, 0xff, 0xf8, 0x0, 0x1f, 0x0, 0xfe, - 0xfb, 0xf8, 0x0, 0xb4, 0xf, 0xe3, 0xe3, 0xf8, - 0x3, 0xc0, 0xfe, 0xf, 0x87, 0xf0, 0xa, 0xb, - 0xe0, 0x3e, 0x3f, 0x40, 0x0, 0x2e, 0x0, 0xff, - 0xf4, 0x0, 0x0, 0x0, 0x3, 0xff, 0x40, 0x0, - 0x0, 0x0, 0xf, 0xf4, 0x0, 0x0, 0x0, 0x0, - 0x3f, 0x40, 0x0, 0x0, 0x0, 0x0, 0xb4, 0x0, - 0x0, 0x0, - - /* U+E623 "" */ - 0x0, 0x0, 0x6a, 0xaa, 0x90, 0x0, 0x7, 0xff, - 0xff, 0xfd, 0x0, 0x1f, 0xff, 0xff, 0xff, 0x0, - 0x7f, 0x0, 0x0, 0x2f, 0x1, 0xfc, 0x0, 0x0, - 0x2f, 0x7, 0xf0, 0x0, 0x0, 0x2f, 0x1f, 0xc0, - 0x0, 0x0, 0x2f, 0x7f, 0xb, 0x8f, 0x4f, 0x2f, - 0xfc, 0xb, 0x8f, 0x8f, 0x2f, 0xf8, 0xb, 0x8f, - 0x8f, 0x2f, 0xf8, 0xb, 0x8f, 0x8f, 0x2f, 0xf8, - 0x6, 0x46, 0xa, 0x2f, 0xf8, 0x0, 0x0, 0x0, - 0x2f, 0xf8, 0x0, 0x0, 0x0, 0x2f, 0xf8, 0x0, - 0x0, 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x0, 0x2f, - 0xf8, 0x0, 0x0, 0x0, 0x2f, 0xf8, 0x0, 0x0, - 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x0, 0x2f, 0xf8, - 0x0, 0x0, 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x0, - 0x2f, 0xf8, 0x0, 0x0, 0x0, 0x2f, 0xf8, 0x0, - 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x7f, 0xff, 0xff, 0xff, 0xfd, 0x6, 0xaa, 0xaa, - 0xaa, 0x90, - - /* U+EBD6 "" */ - 0x0, 0x0, 0x1b, 0xff, 0xe4, 0x0, 0x0, 0x0, - 0xb, 0xff, 0xff, 0xff, 0xe0, 0x0, 0x0, 0xff, - 0xfe, 0xaa, 0xbf, 0xff, 0x0, 0xb, 0xfe, 0x40, - 0x0, 0x1, 0xbf, 0xe0, 0x3f, 0xe0, 0x0, 0x0, - 0x0, 0xb, 0xfc, 0xbe, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xbe, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3f, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfd, - 0x2f, 0xc0, 0x0, 0x0, 0x0, 0x3, 0xf8, 0xb, - 0xf0, 0x0, 0x0, 0x0, 0xf, 0xe0, 0x2, 0xfc, - 0x2, 0xbe, 0x80, 0x3f, 0x80, 0x0, 0xbf, 0x2f, - 0xff, 0xf8, 0xfe, 0x0, 0x0, 0x2f, 0xff, 0xff, - 0xff, 0xf8, 0x0, 0x0, 0xb, 0xff, 0xff, 0xff, - 0xe0, 0x0, 0x0, 0x2, 0xff, 0xff, 0xff, 0x80, - 0x0, 0x0, 0x0, 0xbf, 0xff, 0xfe, 0x0, 0x0, - 0x0, 0x0, 0x2f, 0xff, 0xf8, 0x0, 0x0, 0x0, - 0x0, 0xb, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0x2, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, - - /* U+EBE1 "" */ - 0x0, 0x0, 0x1b, 0xff, 0xe4, 0x0, 0x0, 0x0, - 0xb, 0xff, 0xff, 0xff, 0xe0, 0x0, 0x1, 0xff, - 0xfe, 0xaa, 0xbf, 0xff, 0x40, 0xb, 0xfe, 0x40, - 0x0, 0x1, 0xbf, 0xe0, 0x3f, 0xe0, 0x0, 0x0, - 0x0, 0xb, 0xfc, 0xbe, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xbe, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3f, 0x7f, 0x0, 0x1, 0xaa, 0x40, 0x0, 0xfd, - 0x2f, 0xc0, 0x7f, 0xff, 0xfd, 0x3, 0xf8, 0xb, - 0xf7, 0xff, 0xff, 0xff, 0xdf, 0xe0, 0x2, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x80, 0x0, 0xbf, 0xff, - 0xff, 0xff, 0xfe, 0x0, 0x0, 0x2f, 0xff, 0xff, - 0xff, 0xf8, 0x0, 0x0, 0xb, 0xff, 0xff, 0xff, - 0xe0, 0x0, 0x0, 0x2, 0xff, 0xff, 0xff, 0x80, - 0x0, 0x0, 0x0, 0xbf, 0xff, 0xfe, 0x0, 0x0, - 0x0, 0x0, 0x2f, 0xff, 0xf8, 0x0, 0x0, 0x0, - 0x0, 0xb, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0x2, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, - - /* U+EBE4 "" */ - 0x0, 0x0, 0x1b, 0xff, 0xe4, 0x0, 0x0, 0x0, - 0xb, 0xff, 0xff, 0xff, 0xe0, 0x0, 0x0, 0xff, - 0xfe, 0xaa, 0xbf, 0xff, 0x0, 0xb, 0xfe, 0x40, - 0x0, 0x1, 0xbf, 0xe0, 0x3f, 0xe0, 0x0, 0x0, - 0x0, 0xb, 0xfc, 0xbf, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xfe, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3f, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, - 0x2f, 0xc0, 0x0, 0x0, 0x0, 0x3, 0xf8, 0xb, - 0xf0, 0x0, 0x0, 0x0, 0xf, 0xe0, 0x2, 0xfc, - 0x0, 0x0, 0x0, 0x3f, 0x80, 0x0, 0xbf, 0x0, - 0x0, 0x0, 0xfe, 0x0, 0x0, 0x2f, 0xc0, 0x0, - 0x3, 0xf8, 0x0, 0x0, 0xb, 0xf2, 0xff, 0x8f, - 0xe0, 0x0, 0x0, 0x2, 0xff, 0xff, 0xff, 0x80, - 0x0, 0x0, 0x0, 0xbf, 0xff, 0xfe, 0x0, 0x0, - 0x0, 0x0, 0x2f, 0xff, 0xf8, 0x0, 0x0, 0x0, - 0x0, 0xb, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0x2, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, - - /* U+F057 "" */ - 0x0, 0x0, 0x6a, 0xaa, 0x90, 0x0, 0x7, 0xff, - 0xff, 0xfd, 0x0, 0x1f, 0xff, 0xff, 0xff, 0x0, - 0x7f, 0x0, 0x0, 0x2f, 0x1, 0xfc, 0x0, 0x0, - 0x2f, 0x7, 0xf0, 0x0, 0x0, 0x2f, 0x1f, 0xc0, - 0x0, 0x0, 0x2f, 0x7f, 0x0, 0x0, 0x0, 0x2f, - 0xfc, 0x0, 0x3c, 0x0, 0x2f, 0xf8, 0x0, 0x3c, - 0x0, 0x2f, 0xf8, 0x0, 0x3c, 0x0, 0x2f, 0xf8, - 0x0, 0x3c, 0x0, 0x2f, 0xf8, 0x0, 0x3c, 0x0, - 0x2f, 0xf8, 0x0, 0x3c, 0x0, 0x2f, 0xf8, 0x0, - 0x0, 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x0, 0x2f, - 0xf8, 0x0, 0x0, 0x0, 0x2f, 0xf8, 0x0, 0x3c, - 0x0, 0x2f, 0xf8, 0x0, 0x3c, 0x0, 0x2f, 0xf8, - 0x0, 0x0, 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x0, - 0x2f, 0xf8, 0x0, 0x0, 0x0, 0x2f, 0xf8, 0x0, - 0x0, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x7f, 0xff, 0xff, 0xff, 0xfd, 0x6, 0xaa, 0xaa, - 0xaa, 0x90, - - /* U+F064 "" */ - 0x0, 0x0, 0x6b, 0xff, 0xe9, 0x0, 0x0, 0x0, - 0xb, 0xff, 0xff, 0xff, 0xe0, 0x0, 0x0, 0xff, - 0xfe, 0xaa, 0xbf, 0xff, 0x0, 0xb, 0xfe, 0x40, - 0x0, 0x1, 0xbf, 0xe0, 0x3f, 0xe0, 0x0, 0x0, - 0x0, 0xb, 0xfc, 0xbe, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xbe, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3f, 0x7f, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfd, - 0x2f, 0xc0, 0x0, 0x0, 0x0, 0x1, 0xf8, 0xb, - 0xf0, 0x0, 0x0, 0x0, 0x1, 0xe0, 0x2, 0xfc, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xc0, 0x0, - 0x1, 0x40, 0x20, 0x0, 0xb, 0xf0, 0x0, 0x3, - 0xe1, 0xf8, 0x0, 0x2, 0xfc, 0x0, 0x2, 0xff, - 0xf4, 0x0, 0x0, 0xbf, 0x0, 0x0, 0xbf, 0xd0, - 0x0, 0x0, 0x2f, 0xc0, 0x0, 0x7f, 0xc0, 0x0, - 0x0, 0xb, 0xfb, 0x1, 0xff, 0xe0, 0x0, 0x0, - 0x2, 0xff, 0x43, 0xf6, 0xf4, 0x0, 0x0, 0x0, - 0xbe, 0x3, 0xd0, 0xb4, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, - - /* U+F065 "" */ - 0x0, 0x0, 0x1b, 0xff, 0xe4, 0x0, 0x0, 0x0, - 0xb, 0xff, 0xff, 0xff, 0xe0, 0x0, 0x0, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x0, 0xb, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfc, 0xbf, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xb, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x2, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x80, 0x0, 0xbf, 0xff, - 0xff, 0xff, 0xfe, 0x0, 0x0, 0x2f, 0xff, 0xff, - 0xff, 0xf8, 0x0, 0x0, 0xb, 0xff, 0xff, 0xff, - 0xe0, 0x0, 0x0, 0x2, 0xff, 0xff, 0xff, 0x80, - 0x0, 0x0, 0x0, 0xbf, 0xff, 0xfe, 0x0, 0x0, - 0x0, 0x0, 0x2f, 0xff, 0xf8, 0x0, 0x0, 0x0, - 0x0, 0xb, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0x2, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, - - /* U+F0B0 "" */ - 0x0, 0x0, 0x1b, 0xff, 0xe4, 0x0, 0x0, 0x0, - 0xb, 0xff, 0xff, 0xff, 0xe0, 0x0, 0x0, 0xff, - 0xfe, 0xaa, 0xbf, 0xff, 0x0, 0xb, 0xfe, 0x40, - 0x0, 0x1, 0xbf, 0xe0, 0x3f, 0xe0, 0x0, 0x0, - 0x0, 0xb, 0xfc, 0xbe, 0x0, 0x0, 0x0, 0x0, - 0x0, 0xbe, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3f, 0xbf, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, - 0x2f, 0xc0, 0x0, 0x0, 0x0, 0x3, 0xf8, 0xb, - 0xf0, 0x0, 0x0, 0x0, 0xf, 0xe0, 0x2, 0xfc, - 0x0, 0x0, 0x0, 0x3f, 0x80, 0x0, 0xbf, 0x0, - 0x0, 0x0, 0xfe, 0x0, 0x0, 0x2f, 0xc0, 0x0, - 0x3, 0xf8, 0x0, 0x0, 0xb, 0xf0, 0x0, 0xf, - 0xe0, 0x0, 0x0, 0x2, 0xfc, 0x0, 0x3f, 0x80, - 0x0, 0x0, 0x0, 0xbf, 0x0, 0xfe, 0x0, 0x0, - 0x0, 0x0, 0x2f, 0xc3, 0xf8, 0x0, 0x0, 0x0, - 0x0, 0xb, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x0, - 0x2, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, - 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, - - /* U+F15C "" */ - 0x0, 0x0, 0x6, 0xff, 0x80, 0x0, 0x0, 0x0, - 0x0, 0x3f, 0xff, 0xf8, 0x0, 0x0, 0x0, 0x0, - 0xff, 0xaa, 0xff, 0x0, 0x0, 0x0, 0x3, 0xf8, - 0x0, 0x2f, 0xc0, 0x0, 0x0, 0xb, 0xd0, 0x0, - 0xb, 0xd0, 0x0, 0x0, 0xf, 0x80, 0x0, 0x3, - 0xf0, 0x0, 0x0, 0x2f, 0x0, 0x0, 0x1, 0xf4, - 0x0, 0x2, 0xff, 0x0, 0x0, 0x0, 0xf4, 0x0, - 0xf, 0xfe, 0x0, 0x0, 0x0, 0xf8, 0x0, 0x2f, - 0x80, 0x0, 0x0, 0x0, 0xff, 0x80, 0x3e, 0x0, - 0x0, 0x0, 0x0, 0xff, 0xf0, 0xbc, 0x0, 0x0, - 0x0, 0x0, 0x16, 0xfc, 0xbc, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x7d, 0xbc, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x3e, 0xbc, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x3e, 0x7d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, - 0x3f, 0x40, 0x0, 0x0, 0x0, 0x0, 0xbd, 0xf, - 0xfa, 0xaa, 0xaa, 0xaa, 0xab, 0xfc, 0x7, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0, 0x7f, 0xff, - 0xff, 0xff, 0xff, 0x40, - - /* U+F1DB "" */ - 0x0, 0x0, 0x55, 0x0, 0x0, 0x0, 0x1f, 0xff, - 0xf4, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0, 0x3, - 0xfd, 0x0, 0x7f, 0xc0, 0xf, 0xd0, 0x0, 0x7, - 0xf0, 0x2f, 0x40, 0x0, 0x1, 0xf8, 0x3e, 0x0, - 0x0, 0x0, 0xbc, 0xbc, 0x0, 0x0, 0x0, 0x3e, - 0xfc, 0x0, 0x7d, 0x0, 0x3f, 0xf8, 0x0, 0xff, - 0x0, 0x2f, 0xf8, 0x1, 0xff, 0x40, 0x2f, 0xf8, - 0x0, 0xff, 0x0, 0x2f, 0xfc, 0x0, 0x7d, 0x0, - 0x3f, 0xbc, 0x0, 0x0, 0x0, 0x3d, 0x3e, 0x0, - 0x0, 0x0, 0xbc, 0x2f, 0x0, 0x0, 0x0, 0xf8, - 0xf, 0xc0, 0x0, 0x3, 0xf0, 0x7, 0xe0, 0x0, - 0xb, 0xd0, 0x2, 0xf4, 0x0, 0x1f, 0x80, 0x0, - 0xfd, 0x0, 0x7f, 0x0, 0x0, 0x3f, 0x41, 0xfc, - 0x0, 0x0, 0xf, 0xd7, 0xf0, 0x0, 0x0, 0x7, - 0xff, 0xd0, 0x0, 0x0, 0x1, 0xff, 0x40, 0x0, - 0x0, 0x0, 0x28, 0x0, 0x0, - - /* U+F24F "" */ - 0x1, 0xaa, 0xaa, 0xaa, 0xaa, 0x50, 0x0, 0x2f, - 0xff, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x7f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x0, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0x1f, 0x40, 0xf8, 0x6a, 0xaa, 0xaa, - 0xaa, 0xf, 0x40, 0xf8, 0xff, 0xff, 0xff, 0xff, - 0x8f, 0x4d, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xcf, - 0x4f, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xcf, 0x4f, - 0xf8, 0xff, 0xff, 0xff, 0xff, 0xcf, 0x4f, 0xf8, - 0xff, 0xff, 0xff, 0xff, 0xcf, 0x4f, 0xf8, 0xff, - 0xff, 0xff, 0xff, 0xcf, 0x4e, 0xf8, 0xbf, 0xff, - 0xff, 0xff, 0x4f, 0x44, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x1f, 0x40, 0x7f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0x0, 0x1, 0xaa, 0xaa, 0xaa, 0xaa, 0x50, 0x0, - - /* U+F250 "" */ - 0x1, 0xaa, 0xaa, 0xaa, 0xa4, 0x0, 0x0, 0x2f, - 0xff, 0xff, 0xff, 0xfd, 0x0, 0x0, 0x7f, 0xff, - 0xff, 0xff, 0xfc, 0x3, 0x0, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0xb, 0x0, 0xf8, 0x6a, 0xaa, 0xaa, - 0x40, 0x2f, 0x0, 0xf8, 0xff, 0xff, 0xff, 0xc0, - 0x7e, 0x0, 0xf8, 0xff, 0xff, 0xff, 0x80, 0xfe, - 0x0, 0xf8, 0xff, 0xff, 0xff, 0x3, 0xff, 0xfc, - 0xf8, 0xff, 0xff, 0xfc, 0xb, 0xff, 0xf0, 0xf8, - 0xff, 0xff, 0xf4, 0x1, 0x5f, 0xd0, 0xf8, 0xff, - 0xff, 0xe0, 0x0, 0x1f, 0x80, 0xf8, 0xbf, 0xff, - 0x80, 0x0, 0x2f, 0x0, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x3c, 0x0, 0x7f, 0xff, 0xff, 0xff, 0xf0, - 0x30, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xf0, 0x10, - 0x0, 0x1, 0xaa, 0xaa, 0xaa, 0x50, 0x0, 0x0, - - /* U+F252 "" */ - 0x1, 0xaa, 0xaa, 0xaa, 0xaa, 0x50, 0x0, 0x2f, - 0xff, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x7f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x0, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0x1f, 0x40, 0xf8, 0x6a, 0xaa, 0xaa, - 0xa0, 0xf, 0x40, 0xf8, 0xff, 0xff, 0xff, 0xfc, - 0xf, 0x4d, 0xf8, 0xff, 0xff, 0xff, 0xfc, 0xf, - 0x4f, 0xf8, 0xff, 0xff, 0xff, 0xfc, 0xf, 0x4f, - 0xf8, 0xff, 0xff, 0xff, 0xfc, 0xf, 0x4f, 0xf8, - 0xff, 0xff, 0xff, 0xfc, 0xf, 0x4f, 0xf8, 0xff, - 0xff, 0xff, 0xfc, 0xf, 0x4e, 0xf8, 0xbf, 0xff, - 0xff, 0xf8, 0xf, 0x44, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x1f, 0x40, 0x7f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0x0, 0x1, 0xaa, 0xaa, 0xaa, 0xaa, 0x50, 0x0, - - /* U+F253 "" */ - 0x1, 0xaa, 0xaa, 0xaa, 0xaa, 0x50, 0x0, 0x2f, - 0xff, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x7f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x0, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0x1f, 0x40, 0xf8, 0x6a, 0xaa, 0xa9, - 0x0, 0xf, 0x40, 0xf8, 0xff, 0xff, 0xff, 0x40, - 0xf, 0x4d, 0xf8, 0xff, 0xff, 0xff, 0x40, 0xf, - 0x4f, 0xf8, 0xff, 0xff, 0xff, 0x40, 0xf, 0x4f, - 0xf8, 0xff, 0xff, 0xff, 0x40, 0xf, 0x4f, 0xf8, - 0xff, 0xff, 0xff, 0x40, 0xf, 0x4f, 0xf8, 0xff, - 0xff, 0xff, 0x40, 0xf, 0x4e, 0xf8, 0xbf, 0xff, - 0xff, 0x0, 0xf, 0x44, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x1f, 0x40, 0x7f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0x0, 0x1, 0xaa, 0xaa, 0xaa, 0xaa, 0x50, 0x0, - - /* U+F254 "" */ - 0x1, 0xaa, 0xaa, 0xaa, 0xaa, 0x50, 0x0, 0x2f, - 0xff, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x7f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x0, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0x1f, 0x40, 0xf8, 0x6a, 0xaa, 0x80, - 0x0, 0xf, 0x40, 0xf8, 0xff, 0xff, 0xf0, 0x0, - 0xf, 0x4d, 0xf8, 0xff, 0xff, 0xf0, 0x0, 0xf, - 0x4f, 0xf8, 0xff, 0xff, 0xf0, 0x0, 0xf, 0x4f, - 0xf8, 0xff, 0xff, 0xf0, 0x0, 0xf, 0x4f, 0xf8, - 0xff, 0xff, 0xf0, 0x0, 0xf, 0x4f, 0xf8, 0xff, - 0xff, 0xf0, 0x0, 0xf, 0x4e, 0xf8, 0xbf, 0xff, - 0xe0, 0x0, 0xf, 0x44, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x1f, 0x40, 0x7f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0x0, 0x1, 0xaa, 0xaa, 0xaa, 0xaa, 0x50, 0x0, - - /* U+F255 "" */ - 0x1, 0xaa, 0xaa, 0xaa, 0xaa, 0x50, 0x0, 0x2f, - 0xff, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x7f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x0, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0x1f, 0x40, 0xf8, 0x6a, 0xa4, 0x0, - 0x0, 0xf, 0x40, 0xf8, 0xff, 0xfd, 0x0, 0x0, - 0xf, 0x4d, 0xf8, 0xff, 0xfd, 0x0, 0x0, 0xf, - 0x4f, 0xf8, 0xff, 0xfd, 0x0, 0x0, 0xf, 0x4f, - 0xf8, 0xff, 0xfd, 0x0, 0x0, 0xf, 0x4f, 0xf8, - 0xff, 0xfd, 0x0, 0x0, 0xf, 0x4f, 0xf8, 0xff, - 0xfd, 0x0, 0x0, 0xf, 0x4e, 0xf8, 0xbf, 0xfc, - 0x0, 0x0, 0xf, 0x44, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x1f, 0x40, 0x7f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0x0, 0x1, 0xaa, 0xaa, 0xaa, 0xaa, 0x50, 0x0, - - /* U+F256 "" */ - 0x1, 0xaa, 0xaa, 0xaa, 0xaa, 0x50, 0x0, 0x2f, - 0xff, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x7f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x0, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0x1f, 0x40, 0xf8, 0x6a, 0x0, 0x0, - 0x0, 0xf, 0x40, 0xf8, 0xff, 0xc0, 0x0, 0x0, - 0xf, 0x4d, 0xf8, 0xff, 0xc0, 0x0, 0x0, 0xf, - 0x4f, 0xf8, 0xff, 0xc0, 0x0, 0x0, 0xf, 0x4f, - 0xf8, 0xff, 0xc0, 0x0, 0x0, 0xf, 0x4f, 0xf8, - 0xff, 0xc0, 0x0, 0x0, 0xf, 0x4f, 0xf8, 0xff, - 0xc0, 0x0, 0x0, 0xf, 0x4e, 0xf8, 0xbf, 0x80, - 0x0, 0x0, 0xf, 0x44, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x1f, 0x40, 0x7f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0x0, 0x1, 0xaa, 0xaa, 0xaa, 0xaa, 0x50, 0x0, - - /* U+F257 "" */ - 0x1, 0xaa, 0xaa, 0xaa, 0xaa, 0x50, 0x0, 0x2f, - 0xff, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x7f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x0, 0xfc, 0x0, 0x0, - 0x0, 0x0, 0x1f, 0x40, 0xf8, 0x60, 0x0, 0x0, - 0x0, 0xf, 0x40, 0xf8, 0xf4, 0x0, 0x0, 0x0, - 0xf, 0x4d, 0xf8, 0xf4, 0x0, 0x0, 0x0, 0xf, - 0x4f, 0xf8, 0xf4, 0x0, 0x0, 0x0, 0xf, 0x4f, - 0xf8, 0xf4, 0x0, 0x0, 0x0, 0xf, 0x4f, 0xf8, - 0xf4, 0x0, 0x0, 0x0, 0xf, 0x4f, 0xf8, 0xf4, - 0x0, 0x0, 0x0, 0xf, 0x4e, 0xf8, 0xb0, 0x0, - 0x0, 0x0, 0xf, 0x40, 0xfc, 0x0, 0x0, 0x0, - 0x0, 0x1f, 0x40, 0x7f, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x0, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xfd, - 0x0, 0x1, 0xaa, 0xaa, 0xaa, 0xaa, 0x50, 0x0 -}; - - -/*--------------------- - * GLYPH DESCRIPTION - *--------------------*/ - -static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { - {.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */, - {.bitmap_index = 0, .adv_w = 480, .box_w = 16, .box_h = 24, .ofs_x = 6, .ofs_y = 3}, - {.bitmap_index = 96, .adv_w = 480, .box_w = 22, .box_h = 24, .ofs_x = 4, .ofs_y = 3}, - {.bitmap_index = 228, .adv_w = 480, .box_w = 25, .box_h = 25, .ofs_x = 2, .ofs_y = 2}, - {.bitmap_index = 385, .adv_w = 480, .box_w = 30, .box_h = 26, .ofs_x = 0, .ofs_y = 1}, - {.bitmap_index = 580, .adv_w = 480, .box_w = 18, .box_h = 26, .ofs_x = 6, .ofs_y = 2}, - {.bitmap_index = 697, .adv_w = 480, .box_w = 24, .box_h = 24, .ofs_x = 3, .ofs_y = 3}, - {.bitmap_index = 841, .adv_w = 480, .box_w = 23, .box_h = 24, .ofs_x = 4, .ofs_y = 3}, - {.bitmap_index = 979, .adv_w = 480, .box_w = 20, .box_h = 26, .ofs_x = 5, .ofs_y = 2}, - {.bitmap_index = 1109, .adv_w = 480, .box_w = 28, .box_h = 21, .ofs_x = 1, .ofs_y = 4}, - {.bitmap_index = 1256, .adv_w = 480, .box_w = 28, .box_h = 21, .ofs_x = 1, .ofs_y = 4}, - {.bitmap_index = 1403, .adv_w = 480, .box_w = 28, .box_h = 21, .ofs_x = 1, .ofs_y = 4}, - {.bitmap_index = 1550, .adv_w = 480, .box_w = 20, .box_h = 26, .ofs_x = 5, .ofs_y = 2}, - {.bitmap_index = 1680, .adv_w = 480, .box_w = 28, .box_h = 21, .ofs_x = 1, .ofs_y = 4}, - {.bitmap_index = 1827, .adv_w = 480, .box_w = 28, .box_h = 21, .ofs_x = 1, .ofs_y = 4}, - {.bitmap_index = 1974, .adv_w = 480, .box_w = 28, .box_h = 21, .ofs_x = 1, .ofs_y = 4}, - {.bitmap_index = 2121, .adv_w = 480, .box_w = 28, .box_h = 20, .ofs_x = 1, .ofs_y = 5}, - {.bitmap_index = 2261, .adv_w = 480, .box_w = 20, .box_h = 25, .ofs_x = 5, .ofs_y = 3}, - {.bitmap_index = 2386, .adv_w = 480, .box_w = 28, .box_h = 16, .ofs_x = 1, .ofs_y = 7}, - {.bitmap_index = 2498, .adv_w = 480, .box_w = 28, .box_h = 16, .ofs_x = 1, .ofs_y = 7}, - {.bitmap_index = 2610, .adv_w = 480, .box_w = 28, .box_h = 16, .ofs_x = 1, .ofs_y = 7}, - {.bitmap_index = 2722, .adv_w = 480, .box_w = 28, .box_h = 16, .ofs_x = 1, .ofs_y = 7}, - {.bitmap_index = 2834, .adv_w = 480, .box_w = 28, .box_h = 16, .ofs_x = 1, .ofs_y = 7}, - {.bitmap_index = 2946, .adv_w = 480, .box_w = 28, .box_h = 16, .ofs_x = 1, .ofs_y = 7}, - {.bitmap_index = 3058, .adv_w = 480, .box_w = 28, .box_h = 16, .ofs_x = 1, .ofs_y = 7}, - {.bitmap_index = 3170, .adv_w = 480, .box_w = 28, .box_h = 16, .ofs_x = 1, .ofs_y = 7} -}; - -/*--------------------- - * CHARACTER MAPPING - *--------------------*/ - -static const uint16_t unicode_list_0[] = { - 0x0, 0x1, 0x2, 0x33, 0x39, 0x17b, 0x468, 0x47c, - 0xa2f, 0xa3a, 0xa3d, 0xeb0, 0xebd, 0xebe, 0xf09, 0xfb5, - 0x1034, 0x10a8, 0x10a9, 0x10ab, 0x10ac, 0x10ad, 0x10ae, 0x10af, - 0x10b0 -}; - -/*Collect the unicode lists and glyph_id offsets*/ -static const lv_font_fmt_txt_cmap_t cmaps[] = -{ - { - .range_start = 57767, .range_length = 4273, .glyph_id_start = 1, - .unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 25, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY - } -}; - - - -/*-------------------- - * ALL CUSTOM DATA - *--------------------*/ - -#if LVGL_VERSION_MAJOR == 8 -/*Store all the custom data of the font*/ -static lv_font_fmt_txt_glyph_cache_t cache; -#endif - -#if LVGL_VERSION_MAJOR >= 8 -static const lv_font_fmt_txt_dsc_t font_dsc = { -#else -static lv_font_fmt_txt_dsc_t font_dsc = { -#endif - .glyph_bitmap = glyph_bitmap, - .glyph_dsc = glyph_dsc, - .cmaps = cmaps, - .kern_dsc = NULL, - .kern_scale = 0, - .cmap_num = 1, - .bpp = 2, - .kern_classes = 0, - .bitmap_format = 0, -#if LVGL_VERSION_MAJOR == 8 - .cache = &cache -#endif -}; - - - -/*----------------- - * PUBLIC FONT - *----------------*/ - -/*Initialize a public general font descriptor*/ -#if LVGL_VERSION_MAJOR >= 8 -const lv_font_t material_symbols_statusbar_30 = { -#else -lv_font_t material_symbols_statusbar_30 = { -#endif - .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ - .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ - .line_height = 27, /*The maximum line height required by the font*/ - .base_line = -1, /*Baseline measured from the bottom of the line*/ -#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) - .subpx = LV_FONT_SUBPX_NONE, -#endif -#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 - .underline_position = 0, - .underline_thickness = 0, -#endif - .dsc = &font_dsc, /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ -#if LV_VERSION_CHECK(8, 2, 0) || LVGL_VERSION_MAJOR >= 9 - .fallback = NULL, -#endif - .user_data = NULL, -}; - - - -#endif /*#if MATERIAL_SYMBOLS_STATUSBAR_30*/ - diff --git a/Modules/lvgl-module/source/binfont.c b/Modules/lvgl-module/source/binfont.c new file mode 100644 index 000000000..a166ee266 --- /dev/null +++ b/Modules/lvgl-module/source/binfont.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: Apache-2.0 +#include + +#include +#include + +static bool get_glyph_dsc(const lv_font_t* font, lv_font_glyph_dsc_t* dsc, uint32_t letter, uint32_t letter_next) { + struct BinFont* binfont = (struct BinFont*)font->dsc; + BinFontGlyph glyph; + if (!binfont_get_glyph(binfont, letter, &glyph)) { + return false; + } + + int32_t advance_x16 = (int32_t)glyph.advance_x16; + BinFontGlyph next; + if (font->kerning == LV_FONT_KERNING_NORMAL && letter_next != 0 && binfont_get_glyph(binfont, letter_next, &next)) { + advance_x16 += binfont_get_kerning_x16(binfont, glyph.glyph_id, next.glyph_id); + } + + dsc->adv_w = (uint16_t)((advance_x16 + 8) >> 4); + dsc->box_w = glyph.width; + dsc->box_h = glyph.height; + dsc->ofs_x = glyph.x; + dsc->ofs_y = glyph.y; + dsc->stride = 0; + dsc->format = LV_FONT_GLYPH_FORMAT_A8; + dsc->is_placeholder = false; + dsc->gid.index = glyph.glyph_id; + return true; +} + +static const void* get_glyph_bitmap(lv_font_glyph_dsc_t* dsc, lv_draw_buf_t* draw_buf) { + if (dsc->box_w == 0 || dsc->box_h == 0) { + return NULL; + } + struct BinFont* binfont = (struct BinFont*)dsc->resolved_font->dsc; + const BinFontGlyph glyph = { + .glyph_id = dsc->gid.index, + .width = dsc->box_w, + .height = dsc->box_h, + }; + if (binfont_get_glyph_bitmap(binfont, &glyph, draw_buf->data, draw_buf->header.stride) != ERROR_NONE) { + return NULL; + } + lv_draw_buf_flush_cache(draw_buf, NULL); + return draw_buf; +} + +lv_font_t* lvgl_binfont_create(struct BinFont* font) { + lv_font_t* lv_font = memory_calloc(1, sizeof(lv_font_t)); + if (lv_font == NULL) { + return NULL; + } + + BinFontMetrics metrics; + binfont_get_metrics(font, &metrics); + + lv_font->get_glyph_dsc = get_glyph_dsc; + lv_font->get_glyph_bitmap = get_glyph_bitmap; + lv_font->line_height = metrics.line_height; + lv_font->base_line = metrics.base_line; + lv_font->subpx = LV_FONT_SUBPX_NONE; + lv_font->kerning = LV_FONT_KERNING_NORMAL; + lv_font->underline_position = (int8_t)metrics.underline_position; + lv_font->underline_thickness = (int8_t)metrics.underline_thickness; + lv_font->dsc = font; + return lv_font; +} + +void lvgl_binfont_destroy(lv_font_t* font) { + memory_free(font); +} diff --git a/Modules/lvgl-module/source/fonts.c b/Modules/lvgl-module/source/fonts.c index 862bfd745..1c2b42cb3 100644 --- a/Modules/lvgl-module/source/fonts.c +++ b/Modules/lvgl-module/source/fonts.c @@ -9,10 +9,16 @@ extern const lv_font_t TT_LVGL_TEXT_FONT_SMALL_SYMBOL; extern const lv_font_t TT_LVGL_TEXT_FONT_DEFAULT_SYMBOL; extern const lv_font_t TT_LVGL_TEXT_FONT_LARGE_SYMBOL; -extern const lv_font_t TT_LVGL_LAUNCHER_FONT_ICON_SYMBOL; -extern const lv_font_t TT_LVGL_STATUSBAR_FONT_ICON_SYMBOL; -extern const lv_font_t TT_LVGL_SHARED_FONT_ICON_SYMBOL; -extern const lv_font_t TT_LVGL_SHARED_FONT_ICON_2X_SYMBOL; +static const lv_font_t* icon_fonts[LVGL_ICON_FONT_SHARED_2X + 1]; + +void lvgl_set_icon_font(enum LvglIconFont icon_font, const lv_font_t* font) { + icon_fonts[icon_font] = font; +} + +static const lv_font_t* get_icon_font(enum LvglIconFont icon_font) { + const lv_font_t* font = icon_fonts[icon_font]; + return font != NULL ? font : &TT_LVGL_TEXT_FONT_DEFAULT_SYMBOL; +} uint32_t lvgl_get_text_font_height(enum LvglFontSize font_size) { switch (font_size) { @@ -33,16 +39,16 @@ const lv_font_t* lvgl_get_text_font(enum LvglFontSize font_size) { uint32_t lvgl_get_shared_icon_font_height() { return TT_LVGL_SHARED_FONT_ICON_SIZE; } -const lv_font_t* lvgl_get_shared_icon_font() { return &TT_LVGL_SHARED_FONT_ICON_SYMBOL; } +const lv_font_t* lvgl_get_shared_icon_font() { return get_icon_font(LVGL_ICON_FONT_SHARED); } uint32_t lvgl_get_shared_icon_font_2x_height() { return TT_LVGL_SHARED_FONT_ICON_SIZE * 2; } -const lv_font_t* lvgl_get_shared_icon_font_2x() { return &TT_LVGL_SHARED_FONT_ICON_2X_SYMBOL; } +const lv_font_t* lvgl_get_shared_icon_font_2x() { return get_icon_font(LVGL_ICON_FONT_SHARED_2X); } uint32_t lvgl_get_launcher_icon_font_height() { return TT_LVGL_LAUNCHER_FONT_ICON_SIZE; } -const lv_font_t* lvgl_get_launcher_icon_font() { return &TT_LVGL_LAUNCHER_FONT_ICON_SYMBOL; } +const lv_font_t* lvgl_get_launcher_icon_font() { return get_icon_font(LVGL_ICON_FONT_LAUNCHER); } uint32_t lvgl_get_statusbar_icon_font_height() { return TT_LVGL_STATUSBAR_FONT_ICON_SIZE; } -const lv_font_t* lvgl_get_statusbar_icon_font() { return &TT_LVGL_STATUSBAR_FONT_ICON_SYMBOL; } +const lv_font_t* lvgl_get_statusbar_icon_font() { return get_icon_font(LVGL_ICON_FONT_STATUSBAR); } diff --git a/Modules/lvgl-module/source/icon_names.c b/Modules/lvgl-module/source/icon_names.c new file mode 100644 index 000000000..c39be6eac --- /dev/null +++ b/Modules/lvgl-module/source/icon_names.c @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: Apache-2.0 +// Generated by generate-icons.py + +#include + +const char* const lvgl_icon_shared_names[] = { + "add", + "apps", + "area_chart", + "app_registration", + "calendar_month", + "cable", + "circle", + "close", + "cloud", + "check", + "delete", + "devices", + "display_settings", + "edit_note", + "electric_bolt", + "folder", + "deployed_code", + "download", + "forum", + "gamepad", + "help", + "hub", + "image", + "keyboard_arrow_up", + "lightbulb", + "language", + "lists", + "mail", + "menu", + "mop", + "more_vert", + "music_note", + "note_add", + "power_settings_new", + "refresh", + "search", + "settings", + "toolbar", + "navigation", + "keyboard_alt", + "usb", + "wifi", + "bluetooth", + "terminal", + "logo_dev", + "camera", + "lightstrip", +}; + +const size_t lvgl_icon_shared_name_count = sizeof(lvgl_icon_shared_names) / sizeof(lvgl_icon_shared_names[0]); + +const char* const lvgl_icon_statusbar_names[] = { + "location_on", + "cloud", + "memory", + "sd_card", + "sd_card_alert", + "signal_wifi_0_bar", + "network_wifi_1_bar", + "network_wifi_2_bar", + "network_wifi_3_bar", + "signal_wifi_4_bar", + "signal_wifi_off", + "signal_wifi_bad", + "battery_android_frame_1", + "battery_android_frame_2", + "battery_android_frame_3", + "battery_android_frame_4", + "battery_android_frame_5", + "battery_android_frame_6", + "battery_android_frame_full", + "battery_android_frame_bolt", + "bluetooth", + "bluetooth_searching", + "bluetooth_connected", + "bluetooth_disabled", + "usb", +}; + +const size_t lvgl_icon_statusbar_name_count = sizeof(lvgl_icon_statusbar_names) / sizeof(lvgl_icon_statusbar_names[0]); + +const char* const lvgl_icon_launcher_names[] = { + "apps", + "folder", + "settings", +}; + +const size_t lvgl_icon_launcher_name_count = sizeof(lvgl_icon_launcher_names) / sizeof(lvgl_icon_launcher_names[0]); + diff --git a/Modules/lvgl-module/source/symbols.c b/Modules/lvgl-module/source/symbols.c index 276f08633..e5c02078d 100644 --- a/Modules/lvgl-module/source/symbols.c +++ b/Modules/lvgl-module/source/symbols.c @@ -1,4 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 +#include #include #include #include @@ -26,6 +27,9 @@ const struct ModuleSymbol lvgl_module_symbols[] = { // lvgl module DEFINE_MODULE_SYMBOL(lvgl_module), DEFINE_MODULE_SYMBOL(lvgl_module_configure), + // lvgl_binfont + DEFINE_MODULE_SYMBOL(lvgl_binfont_create), + DEFINE_MODULE_SYMBOL(lvgl_binfont_destroy), // lvgl_fonts DEFINE_MODULE_SYMBOL(lvgl_get_shared_icon_font), DEFINE_MODULE_SYMBOL(lvgl_get_shared_icon_font_height), diff --git a/Tactility/CMakeLists.txt b/Tactility/CMakeLists.txt index 2d12f6cdb..bc07fde26 100644 --- a/Tactility/CMakeLists.txt +++ b/Tactility/CMakeLists.txt @@ -31,6 +31,7 @@ list(APPEND REQUIRES_LIST app-module coreutils-module audio-decoder-module + binfont-module c-symbols-module cjson-module cpp-symbols-module diff --git a/Tactility/Private/Tactility/lvgl/IconFonts.h b/Tactility/Private/Tactility/lvgl/IconFonts.h new file mode 100644 index 000000000..56da2d0fa --- /dev/null +++ b/Tactility/Private/Tactility/lvgl/IconFonts.h @@ -0,0 +1,12 @@ +#pragma once + +namespace tt::lvgl { + +/** + * Loads the icon fonts and registers them with lvgl_set_icon_font(). + * A font is rasterized from the system TTF when it's not cached in the data path yet. + * Must be called before LVGL starts. + */ +void initIconFonts(); + +} diff --git a/Tactility/Source/Tactility.cpp b/Tactility/Source/Tactility.cpp index e6bf9e71a..c823fdc47 100644 --- a/Tactility/Source/Tactility.cpp +++ b/Tactility/Source/Tactility.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -40,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -542,6 +544,7 @@ void run(Module* const dtsModules[], const DtsDevice dtsDevices[]) { // Other libraries check(module_ensure_started(&http_module) == ERROR_NONE); check(module_ensure_started(&graphics_module) == ERROR_NONE); + check(module_ensure_started(&binfont_module) == ERROR_NONE); check(module_ensure_started(&app_module) == ERROR_NONE); check(module_ensure_started(&coreutils_module) == ERROR_NONE); check(module_ensure_started(&crypt_module) == ERROR_NONE); @@ -571,6 +574,8 @@ void run(Module* const dtsModules[], const DtsDevice dtsDevices[]) { registerAndStartServices(); + lvgl::initIconFonts(); + lvgl_module_configure((LvglModuleConfig) { .on_start = onLvglStarted, .on_stop = onLvglStopped, diff --git a/Tactility/Source/lvgl/IconFonts.cpp b/Tactility/Source/lvgl/IconFonts.cpp new file mode 100644 index 000000000..8505f99cc --- /dev/null +++ b/Tactility/Source/lvgl/IconFonts.cpp @@ -0,0 +1,188 @@ +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace tt::lvgl { + +constexpr auto* TAG = "IconFonts"; +constexpr uint8_t ICON_FONT_BPP = 2; +constexpr auto* CACHE_FILE_PREFIX = "material_symbols_"; + +struct IconFontDefinition { + LvglIconFont id; + const char* name; + uint16_t size; + const char* const* iconNames; + size_t iconNameCount; +}; + +static std::string getSystemFontPath(const char* fileName) { + return std::format("{}/fonts/{}", file::MOUNT_POINT_SYSTEM, fileName); +} + +static std::string getCacheDirectory() { + char data_path[FILE_MAX_PATH_STRING_LENGTH]; + if (paths_get_data_path(data_path, sizeof(data_path)) != ERROR_NONE) { + return ""; + } + auto directory = std::format("{}/cache/fonts", data_path); + if (!file::findOrCreateDirectory(directory, 0777)) { + LOG_W(TAG, "Failed to create %s", directory.c_str()); + return ""; + } + return directory; +} + +static std::string getCacheFileName(const IconFontDefinition& definition) { + return std::format("{}{}_{}_{:08x}.bin", CACHE_FILE_PREFIX, definition.name, definition.size, LVGL_ICON_FONT_VERSION); +} + +static void deleteStaleCacheFiles(const std::string& directory, const std::vector& currentFileNames) { + std::vector stale; + file::listDirectory(directory, [&](const dirent& entry) { + const std::string name = entry.d_name; + if (name.starts_with(CACHE_FILE_PREFIX) && std::find(currentFileNames.begin(), currentFileNames.end(), name) == currentFileNames.end()) { + stale.push_back(name); + } + }); + for (const auto& name : stale) { + LOG_I(TAG, "Deleting stale %s", name.c_str()); + file::deleteFile(file::getChildPath(directory, name)); + } +} + +/** Parses a .codepoints file: one " " pair per line */ +static std::unordered_map loadCodepoints(const std::string& path) { + std::unordered_map codepoints; + file::readLines(path, true, [&codepoints](const char* line) { + const char* separator = strchr(line, ' '); + if (separator != nullptr) { + codepoints[std::string(line, separator - line)] = static_cast(strtoul(separator + 1, nullptr, 16)); + } + }); + return codepoints; +} + +static BinFont* generateFont(const IconFontDefinition& definition, const std::unordered_map& codepointMap, const std::string& cachePath) { + std::vector codepoints; + codepoints.reserve(definition.iconNameCount); + for (size_t i = 0; i < definition.iconNameCount; i++) { + const auto entry = codepointMap.find(definition.iconNames[i]); + if (entry != codepointMap.end()) { + codepoints.push_back(entry->second); + } else { + LOG_W(TAG, "No codepoint for icon %s", definition.iconNames[i]); + } + } + + const auto ttf_path = getSystemFontPath("MaterialSymbolsRounded.ttf"); + const BinFontGeneratorConfig config = { + .ttf_path = ttf_path.c_str(), + .size = definition.size, + .bpp = ICON_FONT_BPP, + .codepoints = codepoints.data(), + .codepoint_count = codepoints.size(), + }; + + const auto start_time = get_millis(); + uint8_t* data = nullptr; + size_t size = 0; + const error_t error = binfont_generate(&config, &data, &size); + if (error != ERROR_NONE) { + LOG_E(TAG, "Failed to generate %s font from %s (%s)", definition.name, ttf_path.c_str(), error_to_string(error)); + return nullptr; + } + LOG_I(TAG, "Generated %s font (%zu bytes) in %zu ms", definition.name, size, get_millis() - start_time); + + if (!cachePath.empty()) { + FILE* file = fopen(cachePath.c_str(), "wb"); + const bool written = file != nullptr && fwrite(data, 1, size, file) == size; + if (file != nullptr && fclose(file) != 0) { + LOG_W(TAG, "Failed to close %s", cachePath.c_str()); + } + if (!written) { + LOG_W(TAG, "Failed to write %s", cachePath.c_str()); + file::deleteFile(cachePath); + } + } + + BinFont* font = nullptr; + if (binfont_open_memory(data, size, true, &font) != ERROR_NONE) { + LOG_E(TAG, "Failed to open generated %s font", definition.name); + return nullptr; + } + return font; +} + +void initIconFonts() { + const IconFontDefinition definitions[] = { + { LVGL_ICON_FONT_STATUSBAR, "statusbar", TT_LVGL_STATUSBAR_FONT_ICON_SIZE, lvgl_icon_statusbar_names, lvgl_icon_statusbar_name_count }, + { LVGL_ICON_FONT_LAUNCHER, "launcher", TT_LVGL_LAUNCHER_FONT_ICON_SIZE, lvgl_icon_launcher_names, lvgl_icon_launcher_name_count }, + { LVGL_ICON_FONT_SHARED, "shared", TT_LVGL_SHARED_FONT_ICON_SIZE, lvgl_icon_shared_names, lvgl_icon_shared_name_count }, + { LVGL_ICON_FONT_SHARED_2X, "shared2x", TT_LVGL_SHARED_FONT_ICON_2X_SIZE, lvgl_icon_shared_names, lvgl_icon_shared_name_count }, + }; + + const auto cache_directory = getCacheDirectory(); + if (cache_directory.empty()) { + LOG_W(TAG, "No data path available, icon fonts won't be cached"); + } else { + std::vector file_names; + for (const auto& definition : definitions) { + file_names.push_back(getCacheFileName(definition)); + } + deleteStaleCacheFiles(cache_directory, file_names); + } + + std::unordered_map codepoint_map; + for (const auto& definition : definitions) { + const auto cache_path = cache_directory.empty() ? std::string() : file::getChildPath(cache_directory, getCacheFileName(definition)); + + BinFont* font = nullptr; + if (!cache_path.empty() && file::isFile(cache_path)) { + if (binfont_open_file(cache_path.c_str(), &font) != ERROR_NONE) { + LOG_W(TAG, "Failed to open %s, regenerating", cache_path.c_str()); + font = nullptr; + } + } + + if (font == nullptr) { + if (codepoint_map.empty()) { + codepoint_map = loadCodepoints(getSystemFontPath("MaterialSymbolsRounded.codepoints")); + } + font = generateFont(definition, codepoint_map, cache_path); + if (font == nullptr) { + continue; + } + } + + lv_font_t* lv_font = lvgl_binfont_create(font); + if (lv_font == nullptr) { + LOG_E(TAG, "Failed to create LVGL font for %s", definition.name); + binfont_close(font); + continue; + } + lvgl_set_icon_font(definition.id, lv_font); + } +} + +} diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 6b4803fa0..0fa2547a0 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -12,6 +12,7 @@ add_subdirectory(${CMAKE_SOURCE_DIR}/Modules/crypt-module/tests ${CMAKE_CURRENT_ add_subdirectory(${CMAKE_SOURCE_DIR}/Modules/app-module/tests ${CMAKE_CURRENT_BINARY_DIR}/app-module) add_subdirectory(${CMAKE_SOURCE_DIR}/Modules/app-posix-module/tests ${CMAKE_CURRENT_BINARY_DIR}/app-posix-module) add_subdirectory(${CMAKE_SOURCE_DIR}/Modules/http-module/tests ${CMAKE_CURRENT_BINARY_DIR}/http-module) +add_subdirectory(${CMAKE_SOURCE_DIR}/Modules/binfont-module/tests ${CMAKE_CURRENT_BINARY_DIR}/binfont-module) add_custom_target(build-tests) add_dependencies(build-tests ServiceModuleTests) @@ -23,3 +24,4 @@ add_dependencies(build-tests CryptModuleTests) add_dependencies(build-tests AppModuleTests) add_dependencies(build-tests AppPosixModuleTests) add_dependencies(build-tests HttpModuleTests) +add_dependencies(build-tests BinFontModuleTests) From b845607cc4a1fcae4c44d5c2e8f7e1ee37c44a06 Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Sun, 4 Oct 2026 15:27:42 +0200 Subject: [PATCH 2/5] Various fixes and improvements --- ...roperties => sdkconfig-default.properties} | 2 +- CMakeLists.txt | 1 + Data/system/app/Boot/assets/logo_large.png | Bin 0 -> 3411 bytes .../system/app/Boot/assets/logo_usb_large.png | Bin 0 -> 1243 bytes .../system/app/Boot/assets/logo_usb_small.png | Bin 0 -> 685 bytes Data/system_sources/App Icons.svg | 306 - .../app_icon_calculator.png | Bin 446 -> 0 bytes .../Old Light Mode Icons/app_icon_chat.png | Bin 522 -> 0 bytes .../app_icon_display_settings.png | Bin 333 -> 0 bytes .../app_icon_fallback.png | Bin 240 -> 0 bytes .../Old Light Mode Icons/app_icon_files.png | Bin 286 -> 0 bytes .../Old Light Mode Icons/app_icon_gpio.png | Bin 403 -> 0 bytes .../Old Light Mode Icons/app_icon_i2c.png | Bin 429 -> 0 bytes .../Old Light Mode Icons/app_icon_notes.png | Bin 491 -> 0 bytes .../app_icon_power_settings.png | Bin 299 -> 0 bytes .../app_icon_settings.png | Bin 535 -> 0 bytes .../app_icon_system_info.png | Bin 436 -> 0 bytes .../app_icon_time_date_settings.png | Bin 392 -> 0 bytes Data/system_sources/Statusbar Battery.kra | Bin 559354 -> 0 bytes Data/system_sources/Statusbar sdcard.kra | Bin 50396 -> 0 bytes Data/system_sources/app/Launcher/apps.svg | 42 - Data/system_sources/app/Launcher/folder.svg | 42 - Data/system_sources/app/Launcher/settings.svg | 42 - Data/system_sources/app/TimeZone/search.svg | 42 - Data/system_sources/app/WifiManage/lock.svg | 42 - .../app/WifiManage/signal_medium.svg | 50 - .../app/WifiManage/signal_strong.svg | 50 - .../app/WifiManage/signal_weak.svg | 50 - Data/system_sources/app_icon_calculator.svg | 3 - Data/system_sources/app_icon_chat.svg | 3 - Data/system_sources/app_icon_gpio.svg | 3 - Data/system_sources/app_icon_notes.svg | 7 - .../app_icon_time_date_settings.svg | 42 - Data/system_sources/location.svg | 42 - Data/system_sources/wifi_off_white.svg | 41 - Data/system_sources/wifi_scan_white.svg | 41 - .../wifi_signal_medium_white.svg | 48 - .../wifi_signal_strong_white.svg | 47 - .../system_sources/wifi_signal_weak_white.svg | 49 - Devices/m5stack-tab5/m5stack,tab5.dts | 2 +- Documentation/ideas.md | 2 +- Libraries/lv_screenshot/CMakeLists.txt | 4 +- Libraries/lv_screenshot/Source/save_png.c | 27 +- Modules/lodepng-module/CMakeLists.txt | 15 + Modules/lodepng-module/LICENSE-Apache-2.0.md | 195 + Modules/lodepng-module/LICENSE-lodepng.txt | 25 + Modules/lodepng-module/README.md | 10 + .../lodepng-module/include/lodepng/lodepng.h | 25 + .../include/lodepng/lodepng_upstream.h | 2188 +++++ .../lodepng-module/include/lodepng/module.h | 14 + Modules/lodepng-module/source/allocators.c | 22 + Modules/lodepng-module/source/lodepng.c | 7249 +++++++++++++++++ Modules/lodepng-module/source/module.c | 37 + Modules/lodepng-module/tests/CMakeLists.txt | 20 + .../tests/source/lodepng_test.cpp | 47 + Modules/lodepng-module/tests/source/main.cpp | 64 + Modules/lvgl-module/CMakeLists.txt | 1 + Modules/lvgl-module/private/png_decoder.h | 5 + Modules/lvgl-module/source/arch/lvgl_esp32.c | 5 + Modules/lvgl-module/source/arch/lvgl_posix.c | 2 + Modules/lvgl-module/source/png_decoder.c | 175 + Tactility/CMakeLists.txt | 1 + Tactility/Include/Tactility/Tactility.h | 5 +- .../Private/Tactility/TactilityPrivate.h | 16 + .../Private/Tactility/app/boot/BootScreen.h | 61 + .../Private/Tactility/app/boot/BootSequence.h | 15 + Tactility/Source/Init.cpp | 66 + Tactility/Source/InitApps.cpp | 230 + Tactility/Source/InitModules.cpp | 82 + Tactility/Source/InitServices.cpp | 59 + Tactility/Source/Main.cpp | 17 +- Tactility/Source/MainDispatcher.cpp | 35 + Tactility/Source/Tactility.cpp | 610 -- Tactility/Source/app/boot/Boot.cpp | 363 +- Tactility/Source/app/boot/BootScreen.cpp | 303 + Tactility/Source/app/boot/BootSequence.cpp | 265 + .../Source/app/usbsettings/UsbSettings.cpp | 1 + Tactility/Source/lvgl/Lvgl.cpp | 232 + Tactility/Source/service/audio/Audio.cpp | 2 +- Tactility/Source/service/rtctime/RtcTime.cpp | 2 +- .../service/webserver/WebServerService.cpp | 2 +- Tactility/Source/settings/DisplaySettings.cpp | 29 +- TactilityKernel/source/driver.cpp | 12 +- Tests/CMakeLists.txt | 2 + device.py | 2 +- lv_conf.h | 2 +- 86 files changed, 11551 insertions(+), 1992 deletions(-) rename Buildscripts/{sdkconfig/default.properties => sdkconfig-default.properties} (99%) create mode 100644 Data/system/app/Boot/assets/logo_large.png create mode 100644 Data/system/app/Boot/assets/logo_usb_large.png create mode 100644 Data/system/app/Boot/assets/logo_usb_small.png delete mode 100644 Data/system_sources/App Icons.svg delete mode 100644 Data/system_sources/Old Light Mode Icons/app_icon_calculator.png delete mode 100644 Data/system_sources/Old Light Mode Icons/app_icon_chat.png delete mode 100644 Data/system_sources/Old Light Mode Icons/app_icon_display_settings.png delete mode 100644 Data/system_sources/Old Light Mode Icons/app_icon_fallback.png delete mode 100644 Data/system_sources/Old Light Mode Icons/app_icon_files.png delete mode 100644 Data/system_sources/Old Light Mode Icons/app_icon_gpio.png delete mode 100644 Data/system_sources/Old Light Mode Icons/app_icon_i2c.png delete mode 100644 Data/system_sources/Old Light Mode Icons/app_icon_notes.png delete mode 100644 Data/system_sources/Old Light Mode Icons/app_icon_power_settings.png delete mode 100644 Data/system_sources/Old Light Mode Icons/app_icon_settings.png delete mode 100644 Data/system_sources/Old Light Mode Icons/app_icon_system_info.png delete mode 100644 Data/system_sources/Old Light Mode Icons/app_icon_time_date_settings.png delete mode 100644 Data/system_sources/Statusbar Battery.kra delete mode 100644 Data/system_sources/Statusbar sdcard.kra delete mode 100644 Data/system_sources/app/Launcher/apps.svg delete mode 100644 Data/system_sources/app/Launcher/folder.svg delete mode 100644 Data/system_sources/app/Launcher/settings.svg delete mode 100644 Data/system_sources/app/TimeZone/search.svg delete mode 100644 Data/system_sources/app/WifiManage/lock.svg delete mode 100644 Data/system_sources/app/WifiManage/signal_medium.svg delete mode 100644 Data/system_sources/app/WifiManage/signal_strong.svg delete mode 100644 Data/system_sources/app/WifiManage/signal_weak.svg delete mode 100644 Data/system_sources/app_icon_calculator.svg delete mode 100644 Data/system_sources/app_icon_chat.svg delete mode 100644 Data/system_sources/app_icon_gpio.svg delete mode 100644 Data/system_sources/app_icon_notes.svg delete mode 100644 Data/system_sources/app_icon_time_date_settings.svg delete mode 100644 Data/system_sources/location.svg delete mode 100644 Data/system_sources/wifi_off_white.svg delete mode 100644 Data/system_sources/wifi_scan_white.svg delete mode 100644 Data/system_sources/wifi_signal_medium_white.svg delete mode 100644 Data/system_sources/wifi_signal_strong_white.svg delete mode 100644 Data/system_sources/wifi_signal_weak_white.svg create mode 100644 Modules/lodepng-module/CMakeLists.txt create mode 100644 Modules/lodepng-module/LICENSE-Apache-2.0.md create mode 100644 Modules/lodepng-module/LICENSE-lodepng.txt create mode 100644 Modules/lodepng-module/README.md create mode 100644 Modules/lodepng-module/include/lodepng/lodepng.h create mode 100644 Modules/lodepng-module/include/lodepng/lodepng_upstream.h create mode 100644 Modules/lodepng-module/include/lodepng/module.h create mode 100644 Modules/lodepng-module/source/allocators.c create mode 100644 Modules/lodepng-module/source/lodepng.c create mode 100644 Modules/lodepng-module/source/module.c create mode 100644 Modules/lodepng-module/tests/CMakeLists.txt create mode 100644 Modules/lodepng-module/tests/source/lodepng_test.cpp create mode 100644 Modules/lodepng-module/tests/source/main.cpp create mode 100644 Modules/lvgl-module/private/png_decoder.h create mode 100644 Modules/lvgl-module/source/png_decoder.c create mode 100644 Tactility/Private/Tactility/app/boot/BootScreen.h create mode 100644 Tactility/Private/Tactility/app/boot/BootSequence.h create mode 100644 Tactility/Source/Init.cpp create mode 100644 Tactility/Source/InitApps.cpp create mode 100644 Tactility/Source/InitModules.cpp create mode 100644 Tactility/Source/InitServices.cpp create mode 100644 Tactility/Source/MainDispatcher.cpp delete mode 100644 Tactility/Source/Tactility.cpp create mode 100644 Tactility/Source/app/boot/BootScreen.cpp create mode 100644 Tactility/Source/app/boot/BootSequence.cpp create mode 100644 Tactility/Source/lvgl/Lvgl.cpp diff --git a/Buildscripts/sdkconfig/default.properties b/Buildscripts/sdkconfig-default.properties similarity index 99% rename from Buildscripts/sdkconfig/default.properties rename to Buildscripts/sdkconfig-default.properties index e9993bd35..3a6cdf62f 100644 --- a/Buildscripts/sdkconfig/default.properties +++ b/Buildscripts/sdkconfig-default.properties @@ -36,7 +36,7 @@ CONFIG_LV_USE_FS_STDIO=y CONFIG_LV_FS_STDIO_LETTER=65 CONFIG_LV_FS_STDIO_PATH="" CONFIG_LV_FS_STDIO_CACHE_SIZE=4096 -CONFIG_LV_USE_LODEPNG=y +CONFIG_LV_USE_LODEPNG=n CONFIG_LV_USE_BUILTIN_MALLOC=n # Routes lv_malloc/realloc/free through Modules/lvgl-module/source/lv_mem_custom.c, which prefers # PSRAM (falls back to internal RAM automatically) instead of a fixed-size pool or plain malloc. diff --git a/CMakeLists.txt b/CMakeLists.txt index f5e337a3e..7c0a581f2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -171,6 +171,7 @@ if (NOT DEFINED ENV{ESP_IDF_VERSION}) add_subdirectory(Modules/lvgl-module) add_subdirectory(Modules/audio-decoder-module) add_subdirectory(Modules/binfont-module) + add_subdirectory(Modules/lodepng-module) add_subdirectory(Modules/c-symbols-module) add_subdirectory(Modules/cjson-module) add_subdirectory(Modules/cpp-symbols-module) diff --git a/Data/system/app/Boot/assets/logo_large.png b/Data/system/app/Boot/assets/logo_large.png new file mode 100644 index 0000000000000000000000000000000000000000..f3cc7819ff2150e3bf262f96b6b331ed418be666 GIT binary patch literal 3411 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 literal 0 HcmV?d00001 diff --git a/Data/system/app/Boot/assets/logo_usb_large.png b/Data/system/app/Boot/assets/logo_usb_large.png new file mode 100644 index 0000000000000000000000000000000000000000..96bba1f0154e95b6acc6d9503574a7d48405d9c6 GIT binary patch literal 1243 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGooCO|{#S9GAd?3ttX4}GMprB-l zYeY$Kep*R+Vo@qXd3m{BW?pu2a$-TMUVc&f>~}U&3=Aw8o-U3d6?5Ls-k&WKE^vJR z=B_DDz9q-+o|+)9GIgV&UhK|^hAeB2{coIgVq+)^&&uGX94x{eO3iQgJ8X46;8x!t zJm*1+#!}%qkG_4YlW3Zyv3>HPu4J9{@5=61TYp~jbIS33wTJ6wNZP*DF*N3}6ne?f zXRYQSA*|5DDR7L1BblkiknxaSxw-|LSY%zN_4n~uyxp>5XU3ht>5RvDQGGgtA@Lr^ zUdR3azvyIaI=4WS;l0eCKP?W{33pzVO|RpVJ>2bM?e250pU+gPq ztUW0@6!tWd>{$7x7InS`{Hbd8g-#^lun%=eCQ`ymw_kFE9%Pz?(`TrNf zgx{;r`sI=TFX7LIQ(NY!e81$EeKqw!LfEWd#wGS|x9Bl$S-D3>l%e+SmBZ~v(pN>A z*)_AgPKaZCXnS5h<$5B2kG;c|W~S}4>vXg3b8;uEC!#qNn&MR#+?S7^TXi;} z51YE0Pd{VT=0`z#LUy%_?*7va$cPJ=&nP_a_KJ@{#gi6!T|2QLj)77BTI}fupX(NX z?5|>Es1GPtZM^qgy1V`gcS6F!#GiAH2Q)2+Yj_+J_+h79_!aJgIoe!y*B^IPG4d6= z_MZ8=V^N&L-<^xno>j#J)(coKcoh?vTx`2;#rX#2w7J?@HS3N~jWBv(xqgOr)03Ef o?TefhcRQA{?A?YDJ)iaadka@Qn17-NSTHeoy85}Sb4q9e0Ke%y&j0`b literal 0 HcmV?d00001 diff --git a/Data/system/app/Boot/assets/logo_usb_small.png b/Data/system/app/Boot/assets/logo_usb_small.png new file mode 100644 index 0000000000000000000000000000000000000000..8608c382a3423d019961ba22427951f6d559e79e GIT binary patch literal 685 zcmV;e0#f~nP)C@vZYCpQJR23$m(b#dIT&~zPP%f8`wACtvf&-+aL!nZs%=~o$Q`0j~fC~pUlyi1s`f*%7;~J>?!Ky%E zCpP(v>%27KnRp+Fe1?^JeZ_9esb({|na$4Dqx`FWu)5#Ywt1IzoN{ad)o;N=OJq$2 zNlrBzzTdd%x(jayo$00}47*Jp=$oQLQ&6ebS43Fb;RJ<+4!SWYxCsswAZnfN1`pxP z*aXl@mVh67RmtnI3CLuQ`W>trA=Ag7Nz1tB#})u^+&%WDyB7F-a(=!MMY!ZTBB6p? zavd4eBmVt90JH&HVR_FRS8}})RdQ87=xqrsht3W}WGnXk-~(`e2%-J(e#vz%4swW0 zK?k`f5Sjb^5NKG){YbxIKBKLz?`eCgbs6;c_@(4TcmSZvBZOjzcDprg7f;O11$_xa z7-}Tj{R3WwZQ-0F6#v`b&{%*dS9)vYsyUCrKvMOCyugcnM7I|g)6e2^8Qp*d*AEy) zt{HO0hoWEm*uIQSfGxU?QVK;cS#;J-xQvHVAmRIs9DwUC6oJ;b1^f|Aybt^W`ft2G TVIK7600000NkvXXu0mjf?m;zx literal 0 HcmV?d00001 diff --git a/Data/system_sources/App Icons.svg b/Data/system_sources/App Icons.svg deleted file mode 100644 index 160d79e1a..000000000 --- a/Data/system_sources/App Icons.svg +++ /dev/null @@ -1,306 +0,0 @@ - -Android O icon templateVenceslas DUETA collection of keylines and guides used to make adaptive icons for android O2021-02-14Android Icon Adaptive Keylines diff --git a/Data/system_sources/Old Light Mode Icons/app_icon_calculator.png b/Data/system_sources/Old Light Mode Icons/app_icon_calculator.png deleted file mode 100644 index 6500d82c749f9509befbfed7ea75b2ffc0380214..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 446 zcmV;v0YUzWP)Px$cu7P-R5(wilRZlVK@f&#c9oFETCh;C5zCnz*x3qpg82uEg$Svv6k{bevDAN{ zQU8FQosgTg(bmc)Al4yacg%()9{IR{Zgcx_``oRNVhbgrszBJwrZ z$H9b|s{nACce#J2-RGHzoX2$*&;)>*h+O1BnE3<%4n$;W6rhN>i-^v9e**yXSr8(& zz4!ap+5`Y@MZ``7sA{aLuBy)?fX(=U{`nXHnK=MJIlh31cOo*B7o|=+&w9|400640 z50iXQ)g45f%avfQee&MZBtW51kXEa;H51V3bk?17FU-7ZjL}A;@j*lz#bWV&CLo0H z+4o?%R4Ua%2yN%wF*7$q2;0`$m2TLgiBZZh2SbxYtE ovqsEG)j1cN@3)!a;xFy|16*S35r60BoB#j-07*qoM6N<$f?~PLMF0Q* diff --git a/Data/system_sources/Old Light Mode Icons/app_icon_chat.png b/Data/system_sources/Old Light Mode Icons/app_icon_chat.png deleted file mode 100644 index 69945f1d14743416511135a6808d386065e7617b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 522 zcmV+l0`>igP)Px$#7RU!R5(wikw0h@Q4q$zc`s>%!&GU+oM0t_-oEz^B8nV>2-jGhO~6(HHUYs} z1;N%oAS!}|*jR~`h@6Tk+@0OCve6?Fh;6)1bobLevd1M{^w6muZ)Sco^L>K<44KsL zoLe-;oCM&Cq9B0O81p(wlJ`67w*kEO2Lap!&<3z6BA-ak0;mI+Bl*l)yAsE7zXFW_ zjYi{uwe|ymHIf(8G<`chErie_c?ZD0q9~4LS@xyO4*{)KYi2MQtcr*Qu&Am(CY|QJ zpC$QDL|CiUj(5A=pF=1jiRV-j9D|roQ~u8d8K9+F%Vk)OV M07*qoM6N<$f@#6)1ONa4 diff --git a/Data/system_sources/Old Light Mode Icons/app_icon_display_settings.png b/Data/system_sources/Old Light Mode Icons/app_icon_display_settings.png deleted file mode 100644 index b92c3a653864624e33dbb32075661da29a1fa106..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 333 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#X!0Ygc<#+)i{6*$r9Iy zlHmNblJdl&REF~Ma=pyF?Be9af>gcyqV(DCY@~pSZh5*mhFJ72oxIVH*-*eG{axRm z3+tpkj=JAj-@?XuQSpb`tSzsV{!e0xT_i1~<67>g)EyqVdhW#Z>&sOBu+O?_-5}fG zySPm0r>n8Gm(_$j=2AI~OBfHdJt=qDvu#DNSN^1VyTm5$KCe<4DJ{mkJaz4a;&*3x z(#$5mxl@}fAjn^y*D$A8-BVMQ;eb}t?)k?H-(<51Ud-J1J*s7&#MENdb6+{?om^Z> z#ae|Dua@}lNMSJWtSb9Hn|aL!Rs-HicAonfDsoJIFn&0AD}9&QflY@_M_u+_6S&ur adw=f1$di({&*cDp$>8bg=d#Wzp$Py8LVzCt diff --git a/Data/system_sources/Old Light Mode Icons/app_icon_fallback.png b/Data/system_sources/Old Light Mode Icons/app_icon_fallback.png deleted file mode 100644 index b37a9039d900de9e18850488d504f4ab2326a745..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 240 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#X!0Ygc<#+)i{6*$r9Iy zlHmNblJdl&REF~Ma=pyF?Be9af>gcyqV(DCY@~pSYCT;XLo9mVPFCb&aujinKdCZ7 z!Sdv?@B;^053Fl`Q@f#J5~sSOkb`LR5gu)a55A%C^|L~@RVOg}WbS4+IPr~lhnnT~ z9jc`V_AqQ#IUegcyqV(DCY@~pSR(rZQhFJ8zoovf>C_%vGeoI8g za}7+9XG{xYWKW3y%xv(RP06^p{QRj+F;}lC8{cO9Y<`z}L+5Ov^8H>> zGj0k>nCW>3m-|aI@^fsco!TzIc3{V6(SHmbjb4{jS}x?@lx2J#5%lie>D?FI)D^Cu c-~W;AtC^{AwBhbPptBh~UHx3vIVCg!05-yCEdT%j diff --git a/Data/system_sources/Old Light Mode Icons/app_icon_gpio.png b/Data/system_sources/Old Light Mode Icons/app_icon_gpio.png deleted file mode 100644 index 962093a4a9b75177f0bad0a0438450429d1454b9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 403 zcmV;E0c`$>P)Px$O-V#SR5(wilf6m+U9Cw%gsA@1ApJE@8xn2K9@`Hh}LWNm^BP1%Rr~0XQ|Y z8CC5xn%Rb`zB6;fIp_LeIe>^L5$yw53n4rZ(NruBA-odNB7im#9eVGdx{w~AUawE4 zX?g@;AvTmr&VctJgo7kWK4MJ|5G4YbAflG{ezOdqs^K=-tNTgd!>0vHEyRb@d$E{G@w z{9UH^BsnB7?Z?r%KH`l7XlVVQNG=7cP->gy74^k zyc<~39L~81Np#cBxrz^9b{IhO40x7yS5EhB-Hb9~>3)j@I0i2F;2;dcBfuJs#)5M$ zHSu*2m;n~e4g-T(U<_l-U=$b!in&~_7nlQPv)ODPe5N36KLXR>O-XC<8!QXv8RkTA z4HSEzRIAmRk_wUv^?LmUz)uay=dbRPBuQY0@}{al^}{IuF4Da)4DW#6bpDFZ%t}EJ z6goL?W|L;N@m*lRId@}btDWGqB$c8lssJN?tJNCHWHS8#aU4JW0KWA+Z{q8s|Nl(y X!+?;{s(pxM00000NkvXXu0mjf7DcSD diff --git a/Data/system_sources/Old Light Mode Icons/app_icon_notes.png b/Data/system_sources/Old Light Mode Icons/app_icon_notes.png deleted file mode 100644 index fce91d6c8bc020e0ee4c761ce0530dd3897c7e22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 491 zcmVPx$rAb6VR5(wylRZxxK@f&#=6n)0QcwySLKQ`dbn9Ci8stDwI?6!!0W?S`iKx@$ z2OvrsM3DlKh9-ytXh0Z$?A|Fw8X81}ge)Leq_B4eon?>#V{nlzcW0h?XJ%i79*@@g zWhRrkDi(|X(p2mvUn%t(5q|+d;(6Y9xm>Q@0+dp3iKxF5(D(h{^?Ln8=)5Z+pU)3A8jXEKoUc}^TUzV)%)CrQ6O~Hk>~@Gs zsS!j>6-?hKNTgcyqV(DCY@~pSc6hothFJ7ooovW;C_upF{xSLH zCdC^PAH)tew8lo|KjM6|x9Ndx&ebTzoek;&QxX&p3QXF%{g;sAoPTHEo!hWz)s~5u zyZ*H`x&)e(%cNg4>D}1o;uRX38d+wdv`N$L>5fm?uUE$9eaOpWIK%TGev7w_3O_JsV$jk^KYy#`Rdtd-uIw0Y;nSGUX z1$Z4}e4^oSc%rWB9pLbS>vZuO7`UpcPIesDz+>m!igRuS*lKKTY&xADmzm+cKPzb) zI0_(XvnYyh59@TaIvT?p6X#+Ua z(tJ0w3-aC%fG=~0|HH1N(=Nui13UwM0dFOJT;TKxcmwnfL{rhEEF2@+J z#TZx3?0O@b@dLP-W!d={_O5khzeTm>+*S1G02UAjfTam3zijGHER Z@&~^9xwm^002ovPDHLkV1gx5>Gc2r diff --git a/Data/system_sources/Old Light Mode Icons/app_icon_system_info.png b/Data/system_sources/Old Light Mode Icons/app_icon_system_info.png deleted file mode 100644 index 8f85e639b45a013e8b72e8de078d41d7d028bb4e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 436 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ⅅ6R?hR4@qf6shGnF!tl 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®b$~>3( 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%0AJCAx`^k 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 z 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
EY4s^9c*>!SMsQ}j=Hb_(CXfJh#ETAM;T}Q}3 zPSL1cE<&^AFjG3pqC?-C`X1VlOHf<1ArXc2G}IZa9q8dN=(b;b4MKD?r%<(3r?OVATU{P@V&rVUwk83!1UYM)O1dc80us%0Aq)yunn5 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�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 diff --git a/Data/system_sources/Statusbar sdcard.kra b/Data/system_sources/Statusbar sdcard.kra deleted file mode 100644 index ca75f74fad43996f85b230a984130ef24c3d7e4b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50396 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 diff --git a/Data/system_sources/app/Launcher/apps.svg b/Data/system_sources/app/Launcher/apps.svg deleted file mode 100644 index 3d4efc504..000000000 --- a/Data/system_sources/app/Launcher/apps.svg +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - diff --git a/Data/system_sources/app/Launcher/folder.svg b/Data/system_sources/app/Launcher/folder.svg deleted file mode 100644 index 298363eeb..000000000 --- a/Data/system_sources/app/Launcher/folder.svg +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - diff --git a/Data/system_sources/app/Launcher/settings.svg b/Data/system_sources/app/Launcher/settings.svg deleted file mode 100644 index 45925e903..000000000 --- a/Data/system_sources/app/Launcher/settings.svg +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - diff --git a/Data/system_sources/app/TimeZone/search.svg b/Data/system_sources/app/TimeZone/search.svg deleted file mode 100644 index 11c909ddb..000000000 --- a/Data/system_sources/app/TimeZone/search.svg +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - diff --git a/Data/system_sources/app/WifiManage/lock.svg b/Data/system_sources/app/WifiManage/lock.svg deleted file mode 100644 index 0711d52fd..000000000 --- a/Data/system_sources/app/WifiManage/lock.svg +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - diff --git a/Data/system_sources/app/WifiManage/signal_medium.svg b/Data/system_sources/app/WifiManage/signal_medium.svg deleted file mode 100644 index b110e3915..000000000 --- a/Data/system_sources/app/WifiManage/signal_medium.svg +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - diff --git a/Data/system_sources/app/WifiManage/signal_strong.svg b/Data/system_sources/app/WifiManage/signal_strong.svg deleted file mode 100644 index 4b4279b06..000000000 --- a/Data/system_sources/app/WifiManage/signal_strong.svg +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - diff --git a/Data/system_sources/app/WifiManage/signal_weak.svg b/Data/system_sources/app/WifiManage/signal_weak.svg deleted file mode 100644 index 1890b0a18..000000000 --- a/Data/system_sources/app/WifiManage/signal_weak.svg +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - diff --git a/Data/system_sources/app_icon_calculator.svg b/Data/system_sources/app_icon_calculator.svg deleted file mode 100644 index fc18d18c3..000000000 --- a/Data/system_sources/app_icon_calculator.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/Data/system_sources/app_icon_chat.svg b/Data/system_sources/app_icon_chat.svg deleted file mode 100644 index d62f2916b..000000000 --- a/Data/system_sources/app_icon_chat.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/Data/system_sources/app_icon_gpio.svg b/Data/system_sources/app_icon_gpio.svg deleted file mode 100644 index 650e5ba2c..000000000 --- a/Data/system_sources/app_icon_gpio.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/Data/system_sources/app_icon_notes.svg b/Data/system_sources/app_icon_notes.svg deleted file mode 100644 index d5d7cc44e..000000000 --- a/Data/system_sources/app_icon_notes.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - note-line - - - \ No newline at end of file diff --git a/Data/system_sources/app_icon_time_date_settings.svg b/Data/system_sources/app_icon_time_date_settings.svg deleted file mode 100644 index 200affaac..000000000 --- a/Data/system_sources/app_icon_time_date_settings.svg +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - diff --git a/Data/system_sources/location.svg b/Data/system_sources/location.svg deleted file mode 100644 index 97b675d47..000000000 --- a/Data/system_sources/location.svg +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - diff --git a/Data/system_sources/wifi_off_white.svg b/Data/system_sources/wifi_off_white.svg deleted file mode 100644 index 2fe696b8e..000000000 --- a/Data/system_sources/wifi_off_white.svg +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - diff --git a/Data/system_sources/wifi_scan_white.svg b/Data/system_sources/wifi_scan_white.svg deleted file mode 100644 index a3da6b29d..000000000 --- a/Data/system_sources/wifi_scan_white.svg +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - diff --git a/Data/system_sources/wifi_signal_medium_white.svg b/Data/system_sources/wifi_signal_medium_white.svg deleted file mode 100644 index fb4692cf5..000000000 --- a/Data/system_sources/wifi_signal_medium_white.svg +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - diff --git a/Data/system_sources/wifi_signal_strong_white.svg b/Data/system_sources/wifi_signal_strong_white.svg deleted file mode 100644 index 51b325cbe..000000000 --- a/Data/system_sources/wifi_signal_strong_white.svg +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - diff --git a/Data/system_sources/wifi_signal_weak_white.svg b/Data/system_sources/wifi_signal_weak_white.svg deleted file mode 100644 index 2d9db58ec..000000000 --- a/Data/system_sources/wifi_signal_weak_white.svg +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - diff --git a/Devices/m5stack-tab5/m5stack,tab5.dts b/Devices/m5stack-tab5/m5stack,tab5.dts index 59452d951..470bbd632 100644 --- a/Devices/m5stack-tab5/m5stack,tab5.dts +++ b/Devices/m5stack-tab5/m5stack,tab5.dts @@ -67,7 +67,7 @@ i2c_internal: i2c0 { compatible = "espressif,esp32-i2c-master"; port = ; - clock-frequency = <100000>; + clock-frequency = <400000>; pin-sda = <&gpio0 31 GPIO_FLAG_PULL_UP>; pin-scl = <&gpio0 32 GPIO_FLAG_PULL_UP>; diff --git a/Documentation/ideas.md b/Documentation/ideas.md index 79bb1e8f5..28f10e2e2 100644 --- a/Documentation/ideas.md +++ b/Documentation/ideas.md @@ -32,7 +32,7 @@ - Improve Setup: Show "Step done" screen - Make it more clear to end-users that an SD card is required to run Tactility - Warn if file operations are done from prohibited tasks (e.g. lvgl task) -- stopAppFromToolbar() in Tactility.cpp stops the top-most app. Change it so the toolbar knows for which app id it is created, so it can rely on that. +- stopAppFromToolbar() in lvgl/Lvgl.cpp stops the top-most app. Change it so the toolbar knows for which app id it is created, so it can rely on that. - Consider not unpacking `.app` files and executing them directly. Might want to cache file offsets. Cache file must be pinned to app version. - lvgl-module's spinner relies on hard-coded spinner asset from Tactility main project. - esp_lvgl_port settings has a large stack size (~9kB) to fix stackoverflow when LVGL events (e.g. button click) do actions like file operations do actions like file operations. Can we reduce the callstack? diff --git a/Libraries/lv_screenshot/CMakeLists.txt b/Libraries/lv_screenshot/CMakeLists.txt index feee75d3b..4748ef560 100644 --- a/Libraries/lv_screenshot/CMakeLists.txt +++ b/Libraries/lv_screenshot/CMakeLists.txt @@ -5,7 +5,7 @@ if (DEFINED ENV{ESP_IDF_VERSION}) SRC_DIRS "Source/" INCLUDE_DIRS "Source/" PRIV_INCLUDE_DIRS "Private/" - REQUIRES lvgl + REQUIRES lvgl lodepng-module ) else() @@ -25,6 +25,6 @@ else() ) target_link_libraries(lv_screenshot - PUBLIC lvgl + PUBLIC lvgl lodepng-module ) endif() \ No newline at end of file diff --git a/Libraries/lv_screenshot/Source/save_png.c b/Libraries/lv_screenshot/Source/save_png.c index 3be555f79..5b89d4f09 100644 --- a/Libraries/lv_screenshot/Source/save_png.c +++ b/Libraries/lv_screenshot/Source/save_png.c @@ -1,11 +1,32 @@ -#include "src/libs/lodepng/lodepng.h" +#include "save_png.h" + +#include +#include bool lv_screenshot_save_png_file(const uint8_t* image, uint32_t w, uint32_t h, uint32_t bpp, const char* filename) { + unsigned char* png = NULL; + size_t png_size = 0; + unsigned error; if (bpp == 32) { - return lodepng_encode32_file(filename, image, w, h) == 0; + error = lodepng_encode32(&png, &png_size, image, w, h); } else if (bpp == 24) { - return lodepng_encode24_file(filename, image, w, h) == 0; + error = lodepng_encode24(&png, &png_size, image, w, h); } else { return false; } + if (error) { + lodepng_free(png); + return false; + } + + // Written through lv_fs, so LVGL drive letter paths ("A:...") work + bool success = false; + lv_fs_file_t file; + if (lv_fs_open(&file, filename, LV_FS_MODE_WR) == LV_FS_RES_OK) { + uint32_t written = 0; + success = lv_fs_write(&file, png, png_size, &written) == LV_FS_RES_OK && written == png_size; + lv_fs_close(&file); + } + lodepng_free(png); + return success; } diff --git a/Modules/lodepng-module/CMakeLists.txt b/Modules/lodepng-module/CMakeLists.txt new file mode 100644 index 000000000..7a5a48304 --- /dev/null +++ b/Modules/lodepng-module/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.20) + +include("${CMAKE_CURRENT_LIST_DIR}/../../Buildscripts/module.cmake") + +file(GLOB_RECURSE SOURCE_FILES "source/*.c*") + +list(APPEND REQUIRES_LIST + TactilityKernel +) + +tactility_add_module(lodepng-module + SRCS ${SOURCE_FILES} + INCLUDE_DIRS include/ + REQUIRES ${REQUIRES_LIST} +) diff --git a/Modules/lodepng-module/LICENSE-Apache-2.0.md b/Modules/lodepng-module/LICENSE-Apache-2.0.md new file mode 100644 index 000000000..f5f4b8b5e --- /dev/null +++ b/Modules/lodepng-module/LICENSE-Apache-2.0.md @@ -0,0 +1,195 @@ +Apache License +============== + +_Version 2.0, January 2004_ +_<>_ + +### 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. + diff --git a/Modules/lodepng-module/LICENSE-lodepng.txt b/Modules/lodepng-module/LICENSE-lodepng.txt new file mode 100644 index 000000000..c2b21cfb5 --- /dev/null +++ b/Modules/lodepng-module/LICENSE-lodepng.txt @@ -0,0 +1,25 @@ +/* +LodePNG version 20261001 + +Copyright (c) 2005-2026 Lode Vandevenne + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + diff --git a/Modules/lodepng-module/README.md b/Modules/lodepng-module/README.md new file mode 100644 index 000000000..ac2d88fc8 --- /dev/null +++ b/Modules/lodepng-module/README.md @@ -0,0 +1,10 @@ +# lodepng-module + +PNG decoding and encoding with [LodePNG](https://github.com/lvandeve/lodepng), usable with and without LVGL. + +Include `` and release decoded or encoded data with `lodepng_free()`. + +## License + +This module is licensed under the [Apache v2.0](LICENSE-Apache-2.0.md) license. +LodePNG is licensed under the [zlib](LICENSE-lodepng.txt) license. diff --git a/Modules/lodepng-module/include/lodepng/lodepng.h b/Modules/lodepng-module/include/lodepng/lodepng.h new file mode 100644 index 000000000..8a361b886 --- /dev/null +++ b/Modules/lodepng-module/include/lodepng/lodepng.h @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +// The C++ wrapper is not compiled: callers use the C API from C and C++ alike +#define LODEPNG_NO_COMPILE_CPP +// Allocations go through the kernel's memory API (see lodepng_malloc() below) +#define LODEPNG_NO_COMPILE_ALLOCATORS + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** Allocates memory, preferring external memory (PSRAM) */ +void* lodepng_malloc(size_t size); + +void* lodepng_realloc(void* ptr, size_t new_size); + +/** Releases memory from lodepng_malloc(), including images returned by the decode and encode functions */ +void lodepng_free(void* ptr); + +#ifdef __cplusplus +} +#endif diff --git a/Modules/lodepng-module/include/lodepng/lodepng_upstream.h b/Modules/lodepng-module/include/lodepng/lodepng_upstream.h new file mode 100644 index 000000000..e1d05c800 --- /dev/null +++ b/Modules/lodepng-module/include/lodepng/lodepng_upstream.h @@ -0,0 +1,2188 @@ +/* +LodePNG version 20261001 + +Copyright (c) 2005-2026 Lode Vandevenne + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +#ifndef LODEPNG_H +#define LODEPNG_H + +#include /*for size_t*/ + +extern const char* LODEPNG_VERSION_STRING; + +/* +The following #defines are used to create code sections. They can be disabled +to disable code sections, which can give faster compile time and smaller binary. +The "NO_COMPILE" defines are designed to be used to pass as defines to the +compiler command to disable them without modifying this header, e.g. +-DLODEPNG_NO_COMPILE_ZLIB for gcc or clang. +*/ +/*deflate & zlib. If disabled, you must specify alternative zlib functions in +the custom_zlib field of the compress and decompress settings*/ +#ifndef LODEPNG_NO_COMPILE_ZLIB +/*pass -DLODEPNG_NO_COMPILE_ZLIB to the compiler to disable this, or comment out LODEPNG_COMPILE_ZLIB below*/ +#define LODEPNG_COMPILE_ZLIB +#endif + +/*png encoder and png decoder*/ +#ifndef LODEPNG_NO_COMPILE_PNG +/*pass -DLODEPNG_NO_COMPILE_PNG to the compiler to disable this, or comment out LODEPNG_COMPILE_PNG below*/ +#define LODEPNG_COMPILE_PNG +#endif + +/*deflate&zlib decoder and png decoder*/ +#ifndef LODEPNG_NO_COMPILE_DECODER +/*pass -DLODEPNG_NO_COMPILE_DECODER to the compiler to disable this, or comment out LODEPNG_COMPILE_DECODER below*/ +#define LODEPNG_COMPILE_DECODER +#endif + +/*deflate&zlib encoder and png encoder*/ +#ifndef LODEPNG_NO_COMPILE_ENCODER +/*pass -DLODEPNG_NO_COMPILE_ENCODER to the compiler to disable this, or comment out LODEPNG_COMPILE_ENCODER below*/ +#define LODEPNG_COMPILE_ENCODER +#endif + +/*the optional built in harddisk file loading and saving functions*/ +#ifndef LODEPNG_NO_COMPILE_DISK +/*pass -DLODEPNG_NO_COMPILE_DISK to the compiler to disable this, or comment out LODEPNG_COMPILE_DISK below*/ +#define LODEPNG_COMPILE_DISK +#endif + +/*support for chunks other than IHDR, IDAT, PLTE, tRNS, IEND: ancillary and unknown chunks*/ +#ifndef LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS +/*pass -DLODEPNG_NO_COMPILE_ANCILLARY_CHUNKS to the compiler to disable this, +or comment out LODEPNG_COMPILE_ANCILLARY_CHUNKS below*/ +#define LODEPNG_COMPILE_ANCILLARY_CHUNKS +#endif + +/*ability to convert error numerical codes to English text string*/ +#ifndef LODEPNG_NO_COMPILE_ERROR_TEXT +/*pass -DLODEPNG_NO_COMPILE_ERROR_TEXT to the compiler to disable this, +or comment out LODEPNG_COMPILE_ERROR_TEXT below*/ +#define LODEPNG_COMPILE_ERROR_TEXT +#endif + +/*Compile the default allocators (C's free, malloc and realloc). If you disable this, +you can define the functions lodepng_free, lodepng_malloc and lodepng_realloc in your +source files with custom allocators.*/ +#ifndef LODEPNG_NO_COMPILE_ALLOCATORS +/*pass -DLODEPNG_NO_COMPILE_ALLOCATORS to the compiler to disable the built-in ones, +or comment out LODEPNG_COMPILE_ALLOCATORS below*/ +#define LODEPNG_COMPILE_ALLOCATORS +#endif + +/*Disable built-in CRC function, in that case a custom implementation of +lodepng_crc32 must be defined externally so that it can be linked in. +The default built-in CRC code comes with 8KB of lookup tables, so for memory constrained environment you may want it +disabled and provide a much smaller implementation externally as said above. You can find such an example implementation +in a comment in the lodepng.c(pp) file in the 'else' case of the searchable LODEPNG_COMPILE_CRC section.*/ +#ifndef LODEPNG_NO_COMPILE_CRC +/*pass -DLODEPNG_NO_COMPILE_CRC to the compiler to disable the built-in one, +or comment out LODEPNG_COMPILE_CRC below*/ +#define LODEPNG_COMPILE_CRC +#endif + +/*compile the C++ version (you can disable the C++ wrapper here even when compiling for C++)*/ +#ifdef __cplusplus +#ifndef LODEPNG_NO_COMPILE_CPP +/*pass -DLODEPNG_NO_COMPILE_CPP to the compiler to disable C++ (not needed if a C-only compiler), +or comment out LODEPNG_COMPILE_CPP below*/ +#define LODEPNG_COMPILE_CPP +#endif +#endif + +#ifdef LODEPNG_COMPILE_CPP +#include +#include +#endif /*LODEPNG_COMPILE_CPP*/ + +#ifdef LODEPNG_COMPILE_PNG +/*The PNG color types (also used for raw image).*/ +typedef enum LodePNGColorType { + LCT_GREY = 0, /*grayscale: 1,2,4,8,16 bit*/ + LCT_RGB = 2, /*RGB: 8,16 bit*/ + LCT_PALETTE = 3, /*palette: 1,2,4,8 bit*/ + LCT_GREY_ALPHA = 4, /*grayscale with alpha: 8,16 bit*/ + LCT_RGBA = 6, /*RGB with alpha: 8,16 bit*/ + /*LCT_MAX_OCTET_VALUE lets the compiler allow this enum to represent any invalid + byte value from 0 to 255 that could be present in an invalid PNG file header. Do + not use, compare with or set the name LCT_MAX_OCTET_VALUE, instead either use + the valid color type names above, or numeric values like 1 or 7 when checking for + particular disallowed color type byte values, or cast to integer to print it.*/ + LCT_MAX_OCTET_VALUE = 255 +} LodePNGColorType; + +#ifdef LODEPNG_COMPILE_DECODER +/* +Converts PNG data in memory to raw pixel data. +out: Output parameter. Pointer to buffer that will contain the raw pixel data. + After decoding, its size is w * h * (bytes per pixel) bytes larger than + initially. Bytes per pixel depends on colortype and bitdepth. + Must be freed after usage with free(*out). + Note: for 16-bit per channel colors, uses big endian format like PNG does. +w: Output parameter. Pointer to width of pixel data. +h: Output parameter. Pointer to height of pixel data. +in: Memory buffer with the PNG file. +insize: size of the in buffer. +colortype: the desired color type for the raw output image. See explanation on PNG color types. +bitdepth: the desired bit depth for the raw output image. See explanation on PNG color types. +Return value: LodePNG error code (0 means no error). +*/ +unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, + const unsigned char* in, size_t insize, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_decode_memory, but always decodes to 32-bit RGBA raw image*/ +unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, + const unsigned char* in, size_t insize); + +/*Same as lodepng_decode_memory, but always decodes to 24-bit RGB raw image*/ +unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, + const unsigned char* in, size_t insize); + +#ifdef LODEPNG_COMPILE_DISK +/* +Load PNG from disk, from file with given name. +Same as the other decode functions, but instead takes a filename as input. + +NOTE: Wide-character filenames are not supported, you can use an external method +to handle such files and decode in-memory.*/ +unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, + const char* filename, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_decode_file, but always decodes to 32-bit RGBA raw image. + +NOTE: Wide-character filenames are not supported, you can use an external method +to handle such files and decode in-memory.*/ +unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, + const char* filename); + +/*Same as lodepng_decode_file, but always decodes to 24-bit RGB raw image. + +NOTE: Wide-character filenames are not supported, you can use an external method +to handle such files and decode in-memory.*/ +unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, + const char* filename); +#endif /*LODEPNG_COMPILE_DISK*/ +#endif /*LODEPNG_COMPILE_DECODER*/ + + +#ifdef LODEPNG_COMPILE_ENCODER +/* +Converts raw pixel data into a PNG image in memory. The colortype and bitdepth + of the output PNG image cannot be chosen, they are automatically determined + by the colortype, bitdepth and content of the input pixel data. + Note: for 16-bit per channel colors, needs big endian format like PNG does. +out: Output parameter. Pointer to buffer that will contain the PNG image data. + Must be freed after usage with free(*out). +outsize: Output parameter. Pointer to the size in bytes of the out buffer. +image: The raw pixel data to encode. The size of this buffer should be + w * h * (bytes per pixel), bytes per pixel depends on colortype and bitdepth. +w: width of the raw pixel data in pixels. +h: height of the raw pixel data in pixels. +colortype: the color type of the raw input image. See explanation on PNG color types. +bitdepth: the bit depth of the raw input image. See explanation on PNG color types. +Return value: LodePNG error code (0 means no error). +*/ +unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_encode_memory, but always encodes from 32-bit RGBA raw image.*/ +unsigned lodepng_encode32(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h); + +/*Same as lodepng_encode_memory, but always encodes from 24-bit RGB raw image.*/ +unsigned lodepng_encode24(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h); + +#ifdef LODEPNG_COMPILE_DISK +/* +Converts raw pixel data into a PNG file on disk. +Same as the other encode functions, but instead takes a filename as output. + +NOTE: This overwrites existing files without warning! + +NOTE: Wide-character filenames are not supported, you can use an external method +to handle such files and encode in-memory.*/ +unsigned lodepng_encode_file(const char* filename, + const unsigned char* image, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_encode_file, but always encodes from 32-bit RGBA raw image. + +NOTE: Wide-character filenames are not supported, you can use an external method +to handle such files and encode in-memory.*/ +unsigned lodepng_encode32_file(const char* filename, + const unsigned char* image, unsigned w, unsigned h); + +/*Same as lodepng_encode_file, but always encodes from 24-bit RGB raw image. + +NOTE: Wide-character filenames are not supported, you can use an external method +to handle such files and encode in-memory.*/ +unsigned lodepng_encode24_file(const char* filename, + const unsigned char* image, unsigned w, unsigned h); +#endif /*LODEPNG_COMPILE_DISK*/ +#endif /*LODEPNG_COMPILE_ENCODER*/ + + +#ifdef LODEPNG_COMPILE_CPP +namespace lodepng { +#ifdef LODEPNG_COMPILE_DECODER +/*Same as lodepng_decode_memory, but decodes to an std::vector. The colortype +is the format to output the pixels to. Default is RGBA 8-bit per channel.*/ +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + const unsigned char* in, size_t insize, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + const std::vector& in, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +#ifdef LODEPNG_COMPILE_DISK +/* +Converts PNG file from disk to raw pixel data in memory. +Same as the other decode functions, but instead takes a filename as input. + +NOTE: Wide-character filenames are not supported, you can use an external method +to handle such files and decode in-memory. +*/ +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + const std::string& filename, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +#endif /* LODEPNG_COMPILE_DISK */ +#endif /* LODEPNG_COMPILE_DECODER */ + +#ifdef LODEPNG_COMPILE_ENCODER +/*Same as lodepng_encode_memory, but encodes to an std::vector. colortype +is that of the raw input data. The output PNG color type will be auto chosen.*/ +unsigned encode(std::vector& out, + const unsigned char* in, unsigned w, unsigned h, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +unsigned encode(std::vector& out, + const std::vector& in, unsigned w, unsigned h, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +#ifdef LODEPNG_COMPILE_DISK +/* +Converts 32-bit RGBA raw pixel data into a PNG file on disk. +Same as the other encode functions, but instead takes a filename as output. + +NOTE: This overwrites existing files without warning! + +NOTE: Wide-character filenames are not supported, you can use an external method +to handle such files and decode in-memory. +*/ +unsigned encode(const std::string& filename, + const unsigned char* in, unsigned w, unsigned h, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +unsigned encode(const std::string& filename, + const std::vector& in, unsigned w, unsigned h, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +#endif /* LODEPNG_COMPILE_DISK */ +#endif /* LODEPNG_COMPILE_ENCODER */ +} /* namespace lodepng */ +#endif /*LODEPNG_COMPILE_CPP*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +#ifdef LODEPNG_COMPILE_ERROR_TEXT +/*Returns an English description of the numerical error code.*/ +const char* lodepng_error_text(unsigned code); +#endif /*LODEPNG_COMPILE_ERROR_TEXT*/ + +#ifdef LODEPNG_COMPILE_DECODER +/*Settings for zlib decompression*/ +typedef struct LodePNGDecompressSettings LodePNGDecompressSettings; +struct LodePNGDecompressSettings { + /* Check LodePNGDecoderSettings for more ignorable errors such as ignore_crc */ + unsigned ignore_adler32; /*if 1, continue and don't give an error message if the Adler32 checksum is corrupted*/ + unsigned ignore_nlen; /*ignore complement of len checksum in uncompressed blocks*/ + + /*Maximum decompressed size, beyond this the decoder may (and is encouraged to) stop decoding, + return an error, output a data size > max_output_size and all the data up to that point. This is + not hard limit nor a guarantee, but can prevent excessive memory usage. This setting is + ignored by the PNG decoder, but is used by the deflate/zlib decoder and can be used by custom ones. + Set to 0 to impose no limit (the default).*/ + size_t max_output_size; + + /*use custom zlib decoder instead of built in one (default: null). + Should return 0 if success, any non-0 if error (numeric value not exposed).*/ + unsigned (*custom_zlib)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGDecompressSettings*); + /*use custom deflate decoder instead of built in one (default: null) + if custom_zlib is not null, custom_inflate is ignored (the zlib format uses deflate). + Should return 0 if success, any non-0 if error (numeric value not exposed).*/ + unsigned (*custom_inflate)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGDecompressSettings*); + + const void* custom_context; /*optional custom settings for custom functions*/ +}; + +extern const LodePNGDecompressSettings lodepng_default_decompress_settings; +void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/* +Settings for zlib compression. Tweaking these settings tweaks the balance +between speed and compression ratio. +*/ +typedef struct LodePNGCompressSettings LodePNGCompressSettings; +struct LodePNGCompressSettings /*deflate = compress*/ { + /*LZ77 related settings*/ + unsigned btype; /*the block type for LZ (0, 1, 2 or 3, see zlib standard). Should be 2 for proper compression.*/ + unsigned use_lz77; /*whether or not to use LZ77. Should be 1 for proper compression.*/ + unsigned windowsize; /*must be a power of two <= 32768. higher compresses more but is slower. Default value: 2048.*/ + unsigned minmatch; /*minimum lz77 length. 3 is normally best, 6 can be better for some PNGs. Default: 0*/ + unsigned nicematch; /*stop searching if >= this length found. Set to 258 for best compression. Default: 128*/ + unsigned lazymatching; /*use lazy matching: better compression but a bit slower. Default: true*/ + + /*use custom zlib encoder instead of built in one (default: null)*/ + unsigned (*custom_zlib)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGCompressSettings*); + /*use custom deflate encoder instead of built in one (default: null) + if custom_zlib is used, custom_deflate is ignored since only the built in + zlib function will call custom_deflate*/ + unsigned (*custom_deflate)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGCompressSettings*); + + const void* custom_context; /*optional custom settings for custom functions*/ +}; + +extern const LodePNGCompressSettings lodepng_default_compress_settings; +void lodepng_compress_settings_init(LodePNGCompressSettings* settings); +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_PNG +/* +Color mode of an image. Contains all information required to decode the pixel +bits to RGBA colors. This information is the same as used in the PNG file +format, and is used both for PNG and raw image data in LodePNG. +*/ +typedef struct LodePNGColorMode { + /*header (IHDR)*/ + LodePNGColorType colortype; /*color type, see PNG standard or documentation further in this header file*/ + unsigned bitdepth; /*bits per sample, see PNG standard or documentation further in this header file*/ + + /* + palette (PLTE and tRNS) + + Dynamically allocated with the colors of the palette, including alpha. + This field may not be allocated directly, use lodepng_color_mode_init first, + then lodepng_palette_add per color to correctly initialize it (to ensure size + of exactly 1024 bytes). + + The alpha channels must be set as well, set them to 255 for opaque images. + + When decoding, with the default settings you can ignore this palette, since + LodePNG already fills the palette colors in the pixels of the raw RGBA output, + but when decoding to the original PNG color mode it is needed to reconstruct + the colors. + + The palette is only supported for color type 3. + */ + unsigned char* palette; /*palette in RGBARGBA... order. Must be either 0, or when allocated must have 1024 bytes*/ + size_t palettesize; /*palette size in number of colors (amount of used bytes is 4 * palettesize)*/ + + /* + transparent color key (tRNS) + + This color uses the same bit depth as the bitdepth value in this struct, which can be 1-bit to 16-bit. + For grayscale PNGs, r, g and b will all 3 be set to the same. + + When decoding, by default you can ignore this information, since LodePNG sets + pixels with this key to transparent already in the raw RGBA output. + + The color key is only supported for color types 0 and 2. + */ + unsigned key_defined; /*is a transparent color key given? 0 = false, 1 = true*/ + unsigned key_r; /*red/grayscale component of color key*/ + unsigned key_g; /*green component of color key*/ + unsigned key_b; /*blue component of color key*/ +} LodePNGColorMode; + +/*init, cleanup and copy functions to use with this struct*/ +void lodepng_color_mode_init(LodePNGColorMode* info); +void lodepng_color_mode_cleanup(LodePNGColorMode* info); +/*return value is error code (0 means no error)*/ +unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source); +/* Makes a temporary LodePNGColorMode that does not need cleanup (no palette) */ +LodePNGColorMode lodepng_color_mode_make(LodePNGColorType colortype, unsigned bitdepth); + +void lodepng_palette_clear(LodePNGColorMode* info); +/*add 1 color to the palette*/ +unsigned lodepng_palette_add(LodePNGColorMode* info, + unsigned char r, unsigned char g, unsigned char b, unsigned char a); + +/*get the total amount of bits per pixel, based on colortype and bitdepth in the struct*/ +unsigned lodepng_get_bpp(const LodePNGColorMode* info); +/*get the amount of color channels used, based on colortype in the struct. +If a palette is used, it counts as 1 channel.*/ +unsigned lodepng_get_channels(const LodePNGColorMode* info); +/*is it a grayscale type? (only colortype 0 or 4)*/ +unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info); +/*has it got an alpha channel? (only colortype 2 or 6)*/ +unsigned lodepng_is_alpha_type(const LodePNGColorMode* info); +/*has it got a palette? (only colortype 3)*/ +unsigned lodepng_is_palette_type(const LodePNGColorMode* info); +/*only returns true if there is a palette and there is a value in the palette with alpha < 255. +Loops through the palette to check this.*/ +unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info); +/* +Check if the given color info indicates the possibility of having non-opaque pixels in the PNG image. +Returns true if the image can have translucent or invisible pixels (it still be opaque if it doesn't use such pixels). +Returns false if the image can only have opaque pixels. +In detail, it returns true only if it's a color type with alpha, or has a palette with non-opaque values, +or if "key_defined" is true. +*/ +unsigned lodepng_can_have_alpha(const LodePNGColorMode* info); +/*Returns the byte size of a raw image buffer with given width, height and color mode*/ +size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color); + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +/*The information of a Time chunk in PNG.*/ +typedef struct LodePNGTime { + unsigned year; /*2 bytes used (0-65535)*/ + unsigned month; /*1-12*/ + unsigned day; /*1-31*/ + unsigned hour; /*0-23*/ + unsigned minute; /*0-59*/ + unsigned second; /*0-60 (to allow for leap seconds)*/ +} LodePNGTime; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +/*Information about the PNG image, except pixels, width and height.*/ +typedef struct LodePNGInfo { + /*header (IHDR), palette (PLTE) and transparency (tRNS) chunks*/ + unsigned compression_method;/*compression method of the original file. Always 0.*/ + unsigned filter_method; /*filter method of the original file*/ + unsigned interlace_method; /*interlace method of the original file: 0=none, 1=Adam7*/ + LodePNGColorMode color; /*color type and bits, palette and transparency of the PNG file*/ + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /* + Suggested background color chunk (bKGD) + + This uses the same color mode and bit depth as the PNG (except no alpha channel), + with values truncated to the bit depth in the unsigned integer. + + For grayscale and palette PNGs, the value is stored in background_r. The values + in background_g and background_b are then unused. The decoder will set them + equal to background_r, the encoder ignores them in this case. + + When decoding, you may get these in a different color mode than the one you requested + for the raw pixels: the colortype and bitdepth defined by info_png.color, that is the + ones defined in the header of the PNG image, are used. + + When encoding with auto_convert, you must use the color model defined in info_png.color for + these values. The encoder normally ignores info_png.color when auto_convert is on, but will + use it to interpret these values (and convert copies of them to its chosen color model). + + When encoding, avoid setting this to an expensive color, such as a non-gray value + when the image is gray, or the compression will be worse since it will be forced to + write the PNG with a more expensive color mode (when auto_convert is on). + + The decoder does not use this background color to edit the color of pixels. This is a + completely optional metadata feature. + */ + unsigned background_defined; /*is a suggested background color given?*/ + unsigned background_r; /*red/gray/palette component of suggested background color*/ + unsigned background_g; /*green component of suggested background color*/ + unsigned background_b; /*blue component of suggested background color*/ + + /* + Non-international text chunks (tEXt and zTXt) + + The char** arrays each contain num strings. The actual messages are in + text_strings, while text_keys are keywords that give a short description what + the actual text represents, e.g. Title, Author, Description, or anything else. + + All the string fields below including strings, keys, names and language tags are null terminated. + The PNG specification uses null characters for the keys, names and tags, and forbids null + characters to appear in the main text which is why we can use null termination everywhere here. + + A keyword is minimum 1 character and maximum 79 characters long (plus the + additional null terminator). It's discouraged to use a single line length + longer than 79 characters for texts. + + Don't allocate these text buffers yourself. Use the init/cleanup functions + correctly and use lodepng_add_text and lodepng_clear_text. + + Standard text chunk keywords and strings are encoded using Latin-1. + */ + size_t text_num; /*the amount of texts in these char** buffers (there may be more texts in itext)*/ + char** text_keys; /*the keyword of a text chunk (e.g. "Comment")*/ + char** text_strings; /*the actual text*/ + + /* + International text chunks (iTXt) + Similar to the non-international text chunks, but with additional strings + "langtags" and "transkeys", and the following text encodings are used: + keys: Latin-1, langtags: ASCII, transkeys and strings: UTF-8. + keys must be 1-79 characters (plus the additional null terminator), the other + strings are any length. + */ + size_t itext_num; /*the amount of international texts in this PNG*/ + char** itext_keys; /*the English keyword of the text chunk (e.g. "Comment")*/ + char** itext_langtags; /*language tag for this text's language, ISO/IEC 646 string, e.g. ISO 639 language tag*/ + char** itext_transkeys; /*keyword translated to the international language - UTF-8 string*/ + char** itext_strings; /*the actual international text - UTF-8 string*/ + + /* + Optional exif metadata in exif_size bytes. + Don't allocate this buffer yourself. Use the init/cleanup functions + correctly and use lodepng_set_exif and lodepng_clear_exif. + The exif data is in exif-encoded form but without JPEG markers, starting with the 'II' or 'MM' marker that indicates + endianness. It's up to an exif handling library to encode/decode its information. + */ + unsigned exif_defined; /* Whether exif metadata is present, that is, the PNG image has an eXIf chunk */ + unsigned char* exif; /* The bytes of the exif metadata, if present */ + unsigned exif_size; /* The size of the exif data in bytes */ + + + /*time chunk (tIME)*/ + unsigned time_defined; /*set to 1 to make the encoder generate a tIME chunk*/ + LodePNGTime time; + + /*phys chunk (pHYs)*/ + unsigned phys_defined; /*if 0, there is no pHYs chunk and the values below are undefined, if 1 else there is one*/ + unsigned phys_x; /*pixels per unit in x direction*/ + unsigned phys_y; /*pixels per unit in y direction*/ + unsigned phys_unit; /*may be 0 (unknown unit) or 1 (metre)*/ + + /* + Color profile related chunk types: cICP, iCPP, sRGB, gAMA, cHRM, sBIT + + LodePNG does not apply any color conversions on pixels in the encoder or decoder and does not interpret these color + profile values. It merely passes on the information. If you wish to use color profiles and convert colors, a separate + color management library should be used. There is also a limited library for this in lodepng_util.h. + + There are 4 types of (sets of) chunks providing color information. If multiple are present, each will be decoded by + LodePNG, but only one should be handled by the user, with the following order of priority depending on what the user + supports: + 1: cICP: Coding-independent code points (CICP) + 2: iCCP: ICC profile + 3: sRGB: indicates the image is in the sRGB color profile + 4: gAMA and cHRM: indicates a gamma and chromaticity value to define the color profile + */ + + /* + gAMA chunk: Image gamma + Optional, overridden by cICP, iCCP or sRGB if those are present. + Together with cHRM, this is a primitive way of specifying the image color profile. + */ + unsigned gama_defined; /* Whether a gAMA chunk is present (0 = not present, 1 = present). */ + unsigned gama_gamma; /* Gamma exponent times 100000 */ + + /* + cHRM chunk: Primary chromaticities and white point + Optional, overridden by cICP, iCCP or sRGB if those are present. + Together with gAMA, this is a primitive way of specifying the image color profile. + */ + unsigned chrm_defined; /* Whether a cHRM chunk is present (0 = not present, 1 = present). */ + unsigned chrm_white_x; /* White Point x times 100000 */ + unsigned chrm_white_y; /* White Point y times 100000 */ + unsigned chrm_red_x; /* Red x times 100000 */ + unsigned chrm_red_y; /* Red y times 100000 */ + unsigned chrm_green_x; /* Green x times 100000 */ + unsigned chrm_green_y; /* Green y times 100000 */ + unsigned chrm_blue_x; /* Blue x times 100000 */ + unsigned chrm_blue_y; /* Blue y times 100000 */ + + /* + sRGB chunk: Indicates the image is in the sRGB color space. + Optional. Should not appear at the same time as iCCP. + If gAMA is also present gAMA must contain value 45455. + If cHRM is also present cHRM must contain respectively 31270,32900,64000,33000,30000,60000,15000,6000. + */ + unsigned srgb_defined; /* Whether an sRGB chunk is present (0 = not present, 1 = present). */ + unsigned srgb_intent; /* Rendering intent: 0=perceptual, 1=rel. colorimetric, 2=saturation, 3=abs. colorimetric */ + + /* + iCCP chunk: Embedded ICC profile. + Optional. Should not appear at the same time as sRGB. + + Contains ICC profile, which can use any version of the ICC.1 specification by the International Color Consortium. See + its specification for more details. LodePNG does not parse or use the ICC profile (except its color space header + field for "RGB" or "GRAY", see below), a separate library to handle the ICC data format is needed to use it for color + management and conversions. + + For encoding, if iCCP is present, the PNG specification recommends to also add gAMA and cHRM chunks that approximate + the ICC profile, for compatibility with applications that don't use the ICC chunk. This is not required, and it's up + to the user to compute approximate values and set then in the appropriate gama_ and chrm_ fields, LodePNG does not do + this automatically since it does not interpret the ICC profile. + + For encoding, the ICC profile is required by the PNG specification to be an "RGB" profile for non-gray PNG color + types (types 2, 3 and 6) and a "GRAY" profile for gray PNG color types (types 1 and 4). If you disable auto_convert, + you must ensure the ICC profile type matches your requested color type, else the encoder gives an error. If + auto_convert is enabled (the default), and the ICC profile is not a correct match for the pixel data, this will result + in an encoder error if the pixel data has non-gray pixels for a GRAY profile, or a silent less-optimal compression of + the pixel data if the pixels could be encoded as grayscale but the ICC profile is RGB. + + To avoid this do not set an ICC profile in the image unless there is a good reason for it, and when doing so + make sure you compute it carefully to avoid the above problems. + */ + unsigned iccp_defined; /* Whether an iCCP chunk is present (0 = not present, 1 = present). */ + char* iccp_name; /* Null terminated string with profile name, 1-79 bytes */ + /* + The ICC profile in iccp_profile_size bytes. + Don't allocate this buffer yourself. Use the init/cleanup functions + correctly and use lodepng_set_icc and lodepng_clear_icc. + */ + unsigned char* iccp_profile; + unsigned iccp_profile_size; /* The size of iccp_profile in bytes */ + + /* + cICP chunk: Coding-independent code points for video signal type identification. + Optional. If present, and supported, overrides iCCP, sRGB, gAMA and cHRM. + The meaning of the values are as defined in the specification ITU-T-H.273. LodePNG does not + use these values, only passes on the metadata. The meaning of the values is they are enum + values representing certain color spaces, including HDR color spaces, such as Display P3, + PQ and HLG. The video full range flag value should typically be 1 for the use cases of PNG + images, but can be 0 for narrow-range images in certain video editing workflows. + */ + unsigned cicp_defined; /* Whether an cICP chunk is present (0 = not present, 1 = present). */ + unsigned cicp_color_primaries; /* Colour primaries value */ + unsigned cicp_transfer_function; /* Transfer characteristics value */ + unsigned cicp_matrix_coefficients; /* Matrix coefficients value */ + unsigned cicp_video_full_range_flag; /* Video full range flag value */ + + /* + mDCV chunk: Mastering Display Color Volume. + Optional, typically used in conjunction with certain HDR color spaces that can + be represented by the cICP chunk. + See the PNG specification, third edition, for more information on this chunk. + All the red, green, blue and white x and y values are encoded as 16-bit + integers and therefore must be in range 0-65536. The min and max luminance + values are 32-bit integers. + */ + unsigned mdcv_defined; /* Whether an mDCV chunk is present (0 = not present, 1 = present). */ + /* Mastering display color primary chromaticities (CIE 1931 x,y of R,G,B) */ + unsigned mdcv_red_x; /* Red x times 50000 */ + unsigned mdcv_red_y; /* Red y times 50000 */ + unsigned mdcv_green_x; /* Green x times 50000 */ + unsigned mdcv_green_y; /* Green y times 50000 */ + unsigned mdcv_blue_x; /* Blue x times 50000 */ + unsigned mdcv_blue_y; /* Blue y times 50000 */ + /* Mastering display white point chromaticity (CIE 1931 x,y) */ + unsigned mdcv_white_x; /* White Point x times 50000 */ + unsigned mdcv_white_y; /* White Point y times 50000 */ + /* Mastering display luminance */ + unsigned mdcv_max_luminance; /* Max luminance in cd/m^2 times 10000 */ + unsigned mdcv_min_luminance; /* Min luminance in cd/m^2 times 10000 */ + + /* + cLLI chunk: Content Light Level Information. + Optional, typically used in conjunction with certain HDR color spaces that can + be represented by the cICP chunk. + See the PNG specification, third edition, for more information on this chunk. + The clli_max_cll and clli_max_fall values are 32-bit integers. + */ + unsigned clli_defined; /* Whether a cLLI chunk is present (0 = not present, 1 = present). */ + unsigned clli_max_cll; /* Maximum Content Light Level (MaxCLL) in cd/m^2 times 10000 */ + unsigned clli_max_fall; /* Maximum Frame-Average Light Level (MaxFALL) in cd/m^2 times 10000 */ + + /* + sBIT chunk: significant bits. + Optional metadata, only set this if needed. + + If defined, these values give the bit depth of the original data. Since PNG only stores 1, 2, 4, 8 or 16-bit + per channel data, the significant bits value can be used to indicate the original encoded data has another + sample depth, such as 10 or 12. + + Encoders using this value, when storing the pixel data, should use the most significant bits + of the data to store the original bits, and use a good sample depth scaling method such as + "left bit replication" to fill in the least significant bits, rather than fill zeroes. + + Decoders using this value, if able to work with data that's e.g. 10-bit or 12-bit, should right + shift the data to go back to the original bit depth, but decoders are also allowed to ignore + sbit and work e.g. with the 8-bit or 16-bit data from the PNG directly, since thanks + to the encoder contract, the values encoded in PNG are in valid range for the PNG bit depth. + + For grayscale images, sbit_g and sbit_b are not used, and for images that don't use color + type RGBA or grayscale+alpha, sbit_a is not used (it's not used even for palette images with + translucent palette values, or images with color key). The values that are used must be + greater than zero and smaller than or equal to the PNG bit depth. + + The color type from the header in the PNG image defines these used and unused fields: if + decoding with a color mode conversion, such as always decoding to RGBA, this metadata still + only uses the color type of the original PNG, and may e.g. lack the alpha channel info + if the PNG was RGB. When encoding with auto_convert (as well as without), also always the + color model defined in info_png.color determines this. + + NOTE: enabling sbit can hurt compression, because the encoder can then not always use + auto_convert to choose a more optimal color mode for the data, because the PNG format has + strict requirements for the allowed sbit values in combination with color modes. + For example, setting these fields to 10-bit will force the encoder to keep using a 16-bit per channel + color mode, even if the pixel data would in fact fit in a more efficient 8-bit mode. + */ + unsigned sbit_defined; /*is significant bits given? if not, the values below are unused*/ + unsigned sbit_r; /*red or gray component of significant bits*/ + unsigned sbit_g; /*green component of significant bits*/ + unsigned sbit_b; /*blue component of significant bits*/ + unsigned sbit_a; /*alpha component of significant bits*/ + + /* End of color profile related chunks */ + + + /* + unknown chunks: chunks not known by LodePNG, passed on byte for byte. + + There are 3 buffers, one for each position in the PNG where unknown chunks can appear. + Each buffer contains all unknown chunks for that position consecutively. + The 3 positions are: + 0: between IHDR and PLTE, 1: between PLTE and IDAT, 2: between IDAT and IEND. + + For encoding, do not store critical chunks or known chunks that are enabled with a "_defined" flag + above in here, since the encoder will blindly follow this and could then encode an invalid PNG file + (such as one with two IHDR chunks or the disallowed combination of sRGB with iCCP). But do use + this if you wish to store an ancillary chunk that is not supported by LodePNG (such as sPLT or hIST), + or any non-standard PNG chunk. + + Do not allocate or traverse this data yourself. Use the chunk traversing functions declared + later, such as lodepng_chunk_next and lodepng_chunk_append, to read/write this struct. + */ + unsigned char* unknown_chunks_data[3]; + size_t unknown_chunks_size[3]; /*size in bytes of the unknown chunks, given for protection*/ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} LodePNGInfo; + +/*init, cleanup and copy functions to use with this struct*/ +void lodepng_info_init(LodePNGInfo* info); +/*destructs the LodePNGInfo and brings it to invalid state, requiring lodepng_info_init again before reusing it*/ +void lodepng_info_cleanup(LodePNGInfo* info); +/*return value is error code (0 means no error)*/ +unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source); + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str); /*push back both texts at once*/ +void lodepng_clear_text(LodePNGInfo* info); /*use this to clear the texts again after you filled them in*/ + +unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag, + const char* transkey, const char* str); /*push back the 4 texts of 1 chunk at once*/ +void lodepng_clear_itext(LodePNGInfo* info); /*use this to clear the itexts again after you filled them in*/ + +/*replaces if exists*/ +unsigned lodepng_set_icc(LodePNGInfo* info, const char* name, const unsigned char* profile, unsigned profile_size); +void lodepng_clear_icc(LodePNGInfo* info); /*use this to clear the profile again after you filled it in*/ + +/*replaces if exists*/ +unsigned lodepng_set_exif(LodePNGInfo* info, const unsigned char* exif, unsigned exif_size); +void lodepng_clear_exif(LodePNGInfo* info); /*use this to clear the exif metadata again after you filled it in*/ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +/* +Converts raw buffer from one color type to another color type, based on +LodePNGColorMode structs to describe the input and output color type. +See the reference manual at the end of this header file to see which color conversions are supported. +return value = LodePNG error code (0 if all went ok, an error if the conversion isn't supported) +The out buffer must have size (w * h * bpp + 7) / 8, where bpp is the bits per pixel +of the output color type (lodepng_get_bpp). +For < 8 bpp images, there should not be padding bits at the end of scanlines. +For 16-bit per channel colors, uses big endian format like PNG does. +Return value is LodePNG error code +*/ +unsigned lodepng_convert(unsigned char* out, const unsigned char* in, + const LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, + unsigned w, unsigned h); + +#ifdef LODEPNG_COMPILE_DECODER +/* +Settings for the decoder. This contains settings for the PNG and the Zlib +decoder, but not the Info settings from the Info structs. +*/ +typedef struct LodePNGDecoderSettings { + LodePNGDecompressSettings zlibsettings; /*in here is the setting to ignore Adler32 checksums*/ + + /* Check LodePNGDecompressSettings for more ignorable errors such as ignore_adler32 */ + unsigned ignore_crc; /*ignore CRC checksums*/ + unsigned ignore_critical; /*ignore unknown critical chunks*/ + unsigned ignore_end; /*ignore issues at end of file if possible (missing IEND chunk, too large chunk, ...)*/ + /* TODO: make a system involving warnings with levels and a strict mode instead. Other potentially recoverable + errors: srgb rendering intent value, size of content of ancillary chunks, more than 79 characters for some + strings, placement/combination rules for ancillary chunks, crc of unknown chunks, allowed characters + in string keys, invalid characters in chunk types names, etc... */ + + unsigned color_convert; /*whether to convert the PNG to the color type you want. Default: yes*/ + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + unsigned read_text_chunks; /*if false but remember_unknown_chunks is true, they're stored in the unknown chunks*/ + + /*store all bytes from unknown chunks in the LodePNGInfo (off by default, useful for a png editor)*/ + unsigned remember_unknown_chunks; + + /* maximum size for decompressed text chunks. If a text chunk's text is larger than this, an error is returned, + unless reading text chunks is disabled or this limit is set higher or disabled. Set to 0 to allow any size. + By default it is a value that prevents unreasonably large strings from hogging memory. */ + size_t max_text_size; + + /* maximum size for compressed ICC chunks. If the ICC profile is larger than this, an error will be returned. Set to + 0 to allow any size. By default this is a value that prevents ICC profiles that would be much larger than any + legitimate profile could be to hog memory. */ + size_t max_icc_size; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} LodePNGDecoderSettings; + +void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/*strategy to use to choose the PNG filter per scanline. Strategies 0-4 correspond +to each of the 5 filter types PNG supports, the next values are adaptive strategies*/ +typedef enum LodePNGFilterStrategy { + /*every filter at zero*/ + LFS_ZERO = 0, + /*every filter at 1, 2, 3 or 4 (paeth), unlike LFS_ZERO not a good choice, but for testing*/ + LFS_ONE = 1, + LFS_TWO = 2, + LFS_THREE = 3, + LFS_FOUR = 4, + /*Use the filter out of the 5 above types that gives minimum sum, by trying each one. This is the adaptive filtering + suggested heuristic in the PNG standard chapter 'Filter selection'.*/ + LFS_MINSUM, + /*Use the filter type that gives smallest Shannon entropy for this scanline. Depending + on the image, this is better or worse than minsum.*/ + LFS_ENTROPY, + /* + Brute-force-search PNG filters by compressing each filter for each scanline. + Experimental, very slow, and only rarely gives better compression than MINSUM. + */ + LFS_BRUTE_FORCE, + /*use predefined_filters buffer: you specify the filter type for each scanline*/ + LFS_PREDEFINED +} LodePNGFilterStrategy; + +/*Gives characteristics about the integer RGBA colors of the image (count, alpha channel usage, bit depth, ...), +which helps decide which color model to use for encoding. +Used internally by default if "auto_convert" is enabled. Public because it's useful for custom algorithms.*/ +typedef struct LodePNGColorStats { + unsigned colored; /*not grayscale*/ + unsigned key; /*image is not opaque and color key is possible instead of full alpha*/ + unsigned short key_r; /*key values, always as 16-bit, in 8-bit case the byte is duplicated, e.g. 65535 means 255*/ + unsigned short key_g; + unsigned short key_b; + unsigned alpha; /*image is not opaque and alpha channel or alpha palette required*/ + unsigned numcolors; /*amount of colors, up to 257. Not valid if bits == 16 or allow_palette is disabled.*/ + unsigned char palette[1024]; /*Remembers up to the first 256 RGBA colors, in no particular order, only valid when numcolors is valid*/ + unsigned bits; /*bits per channel (not for palette). 1,2 or 4 for grayscale only. 16 if 16-bit per channel required.*/ + size_t numpixels; + + /*user settings for computing/using the stats*/ + unsigned allow_palette; /*default 1. if 0, disallow choosing palette colortype in auto_choose_color, and don't count numcolors*/ + unsigned allow_greyscale; /*default 1. if 0, choose RGB or RGBA even if the image only has gray colors*/ +} LodePNGColorStats; + +void lodepng_color_stats_init(LodePNGColorStats* stats); + +/*Get a LodePNGColorStats of the image. The stats must already have been inited. +Returns error code (e.g. alloc fail) or 0 if ok.*/ +unsigned lodepng_compute_color_stats(LodePNGColorStats* stats, + const unsigned char* image, unsigned w, unsigned h, + const LodePNGColorMode* mode_in); + +/*Settings for the encoder.*/ +typedef struct LodePNGEncoderSettings { + LodePNGCompressSettings zlibsettings; /*settings for the zlib encoder, such as window size, ...*/ + + /*automatically choose output PNG color type. If false, must explicitly choose the output color + type in state.info_png.color.colortype, info_png.color.bitdepth and optionally its palette. + Default: true*/ + unsigned auto_convert; + + /*If true, follows the suggestion in the PNG standard in chapter 'Filter selection': if the PNG uses + a palette or lower than 8 bit depth, set all filters to zero. + In other cases this will use the heuristic from the chosen filter_strategy. The PNG standard + suggests LFS_MINSUM for those cases.*/ + unsigned filter_palette_zero; + /*Which filter strategy to use when not using zeroes due to filter_palette_zero. + Set filter_palette_zero to 0 to ensure always using your chosen strategy. Default: LFS_MINSUM*/ + LodePNGFilterStrategy filter_strategy; + /*used if filter_strategy is LFS_PREDEFINED. In that case, this must point to a buffer with + the same length as the amount of scanlines in the image, and each value must <= 5. You + have to cleanup this buffer, LodePNG will never free it. Don't forget that filter_palette_zero + must be set to 0 to ensure this is also used on palette or low bitdepth images.*/ + const unsigned char* predefined_filters; + + /*force creating a PLTE chunk if colortype is 2 or 6 (= a suggested palette). + If colortype is 3, PLTE is always created. If color type is explicitly set + to a grayscale type (1 or 4), this is not done and is ignored. If enabling this, + a palette must be present in the info_png. + NOTE: enabling this may worsen compression if auto_convert is used to choose + optimal color mode, because it cannot use grayscale color modes in this case*/ + unsigned force_palette; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*add LodePNG identifier and version as a text chunk, for debugging*/ + unsigned add_id; + /*encode text chunks as zTXt chunks instead of tEXt chunks, and use compression in iTXt chunks*/ + unsigned text_compression; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} LodePNGEncoderSettings; + +void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings); +#endif /*LODEPNG_COMPILE_ENCODER*/ + + +#if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) +/*The settings, state and information for extended encoding and decoding. + +Using this struct requires using lodepng_state_init to initialize it +and using lodepng_state_cleanup to deconstruct it. If using C++, you can +use lodepng::State instead which does those things automatically with RAII. + +While a LodePNGState can be reused once in a chain of lodepng_decode followed by +lodepng_encode, it's not recommended to reuse it for multiple encode, decode +or inspect calls, and if any such function returns an error code, the +LodePNGState should not be reused at all as it can be in an unexpected state.. +*/ +typedef struct LodePNGState { +#ifdef LODEPNG_COMPILE_DECODER + LodePNGDecoderSettings decoder; /*the decoding settings*/ +#endif /*LODEPNG_COMPILE_DECODER*/ +#ifdef LODEPNG_COMPILE_ENCODER + LodePNGEncoderSettings encoder; /*the encoding settings*/ +#endif /*LODEPNG_COMPILE_ENCODER*/ + LodePNGColorMode info_raw; /*specifies the format in which you would like to get the raw pixel buffer*/ + LodePNGInfo info_png; /*info of the PNG image obtained after decoding*/ + unsigned error; /*deprecated, use the return value of the encode/decode functions to check errors instead*/ +} LodePNGState; + +/*init, cleanup and copy functions to use with this struct*/ +void lodepng_state_init(LodePNGState* state); +/*destructs the LodePNGState and brings it to invalid state, requiring lodepng_info_init again before reusing it*/ +void lodepng_state_cleanup(LodePNGState* state); +/*return value is error code (0 means no error)*/ +unsigned lodepng_state_copy(LodePNGState* dest, const LodePNGState* source); +#endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */ + +#ifdef LODEPNG_COMPILE_DECODER +/* +Same as lodepng_decode_memory, but uses a LodePNGState to allow custom settings and +getting much more information about the PNG image and color mode. +*/ +unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize); + +/* +Read the PNG header, but not the actual data. This returns only the information +that is in the IHDR chunk of the PNG, such as width, height and color type. The +information is placed in the info_png field of the LodePNGState. +*/ +unsigned lodepng_inspect(unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize); +#endif /*LODEPNG_COMPILE_DECODER*/ + +/* +Reads one metadata chunk (other than IHDR, which is handled by lodepng_inspect) +of the PNG file and outputs what it read in the state. Returns error code on failure. +Use lodepng_inspect first with a new state, then e.g. lodepng_chunk_find_const +to find the desired chunk type, and if non null use lodepng_inspect_chunk (with +chunk_pointer - start_of_file as pos). +Supports most metadata chunks from the PNG standard (gAMA, bKGD, tEXt, ...). +Ignores unsupported, unknown, non-metadata or IHDR chunks (without error). +Requirements: &in[pos] must point to start of a chunk, must use regular +lodepng_inspect first since format of most other chunks depends on IHDR, and if +there is a PLTE chunk, that one must be inspected before tRNS or bKGD. +*/ +unsigned lodepng_inspect_chunk(LodePNGState* state, size_t pos, + const unsigned char* in, size_t insize); + +#ifdef LODEPNG_COMPILE_ENCODER +/*This function allocates the out buffer with standard malloc and stores the size in *outsize.*/ +unsigned lodepng_encode(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h, + LodePNGState* state); +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/* +The lodepng_chunk functions are normally not needed, except to traverse the +unknown chunks stored in the LodePNGInfo struct, or add new ones to it. +It also allows traversing the chunks of an encoded PNG file yourself. + +The chunk pointer always points to the beginning of the chunk itself, that is +the first byte of the 4 length bytes. + +In the PNG file format, chunks have the following format: +-4 bytes length: length of the data of the chunk in bytes (chunk itself is 12 bytes longer) +-4 bytes chunk type (ASCII a-z,A-Z only, see below) +-length bytes of data (may be 0 bytes if length was 0) +-4 bytes of CRC, computed on chunk name + data + +The first chunk starts at the 8th byte of the PNG file, the entire rest of the file +exists out of concatenated chunks with the above format. + +PNG standard chunk ASCII naming conventions: +-First byte: uppercase = critical, lowercase = ancillary +-Second byte: uppercase = public, lowercase = private +-Third byte: must be uppercase +-Fourth byte: uppercase = unsafe to copy, lowercase = safe to copy +*/ + +/* +Gets the length of the data of the chunk. Total chunk length has 12 bytes more. +There must be at least 4 bytes to read from. If the result value is too large, +it may be corrupt data. +*/ +unsigned lodepng_chunk_length(const unsigned char* chunk); + +/*puts the 4-byte type in null terminated string*/ +void lodepng_chunk_type(char type[5], const unsigned char* chunk); + +/*check if the type is the given type*/ +unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type); + +/*0: it's one of the critical chunk types, 1: it's an ancillary chunk (see PNG standard)*/ +unsigned char lodepng_chunk_ancillary(const unsigned char* chunk); + +/*0: public, 1: private (see PNG standard)*/ +unsigned char lodepng_chunk_private(const unsigned char* chunk); + +/*0: the chunk is unsafe to copy, 1: the chunk is safe to copy (see PNG standard)*/ +unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk); + +/*get pointer to the data of the chunk, where the input points to the header of the chunk*/ +unsigned char* lodepng_chunk_data(unsigned char* chunk); +const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk); + +/*returns 0 if the crc is correct, 1 if it's incorrect (0 for OK as usual!)*/ +unsigned lodepng_chunk_check_crc(const unsigned char* chunk); + +/*generates the correct CRC from the data and puts it in the last 4 bytes of the chunk*/ +void lodepng_chunk_generate_crc(unsigned char* chunk); + +/* +Iterate to next chunks, allows iterating through all chunks of the PNG file. +Input must be at the beginning of a chunk (result of a previous lodepng_chunk_next call, +or the 8th byte of a PNG file which always has the first chunk), or alternatively may +point to the first byte of the PNG file (which is not a chunk but the magic header, the +function will then skip over it and return the first real chunk). +Will output pointer to the start of the next chunk, or at or beyond end of the file if there +is no more chunk after this or possibly if the chunk is corrupt. +Start this process at the 8th byte of the PNG file. +In a non-corrupt PNG file, the last chunk should have name "IEND". +*/ +unsigned char* lodepng_chunk_next(unsigned char* chunk, unsigned char* end); +const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk, const unsigned char* end); + +/*Finds the first chunk with the given type in the range [chunk, end), or returns NULL if not found.*/ +unsigned char* lodepng_chunk_find(unsigned char* chunk, unsigned char* end, const char type[5]); +const unsigned char* lodepng_chunk_find_const(const unsigned char* chunk, const unsigned char* end, const char type[5]); + +/* +Appends chunk to the data in out. The given chunk should already have its chunk header. +The out variable and outsize are updated to reflect the new reallocated buffer. +Returns error code (0 if it went ok) +*/ +unsigned lodepng_chunk_append(unsigned char** out, size_t* outsize, const unsigned char* chunk); + +/* +Appends new chunk to out. The chunk to append is given by giving its length, type +and data separately. The type is a 4-letter string. +The out variable and outsize are updated to reflect the new reallocated buffer. +Returns error code (0 if it went ok) +*/ +unsigned lodepng_chunk_create(unsigned char** out, size_t* outsize, size_t length, + const char* type, const unsigned char* data); + + +/*Calculate CRC32 of buffer*/ +unsigned lodepng_crc32(const unsigned char* buf, size_t len); +#endif /*LODEPNG_COMPILE_PNG*/ + + +#ifdef LODEPNG_COMPILE_ZLIB +/* +This zlib part can be used independently to zlib compress and decompress a +buffer. It cannot be used to create gzip files however, and it only supports the +part of zlib that is required for PNG, it does not support dictionaries. +*/ + +#ifdef LODEPNG_COMPILE_DECODER +/*Inflate a buffer. Inflate is the decompression step of deflate. Out buffer must be freed after use.*/ +unsigned lodepng_inflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings); + +/* +Decompresses Zlib data. Reallocates the out buffer and appends the data. The +data must be according to the zlib specification. +Either, *out must be NULL and *outsize must be 0, or, *out must be a valid +buffer and *outsize its size in bytes. out must be freed by user after usage. +*/ +unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/* +Compresses data with Zlib. Reallocates the out buffer and appends the data. +Zlib adds a small header and trailer around the deflate data. +The data is output in the format of the zlib specification. +Either, *out must be NULL and *outsize must be 0, or, *out must be a valid +buffer and *outsize its size in bytes. out must be freed by user after usage. +*/ +unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings); + +/* +Find length-limited Huffman code for given frequencies. This function is in the +public interface only for tests, it's used internally by lodepng_deflate. +*/ +unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies, + size_t numcodes, unsigned maxbitlen); + +/*Compress a buffer with deflate. See RFC 1951. Out buffer must be freed after use.*/ +unsigned lodepng_deflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings); + +#endif /*LODEPNG_COMPILE_ENCODER*/ +#endif /*LODEPNG_COMPILE_ZLIB*/ + +#ifdef LODEPNG_COMPILE_DISK +/* +Load a file from disk into buffer. The function allocates the out buffer, and +after usage you should free it. +out: output parameter, contains pointer to loaded buffer. +outsize: output parameter, size of the allocated out buffer +filename: the path to the file to load +return value: error code (0 means ok) + +NOTE: Wide-character filenames are not supported, you can use an external method +to handle such files and decode in-memory. +*/ +unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename); + +/* +Save a file from buffer to disk. Warning, if it exists, this function overwrites +the file without warning! +buffer: the buffer to write +buffersize: size of the buffer to write +filename: the path to the file to save to +return value: error code (0 means ok) + +NOTE: Wide-character filenames are not supported, you can use an external method +to handle such files and encode in-memory +*/ +unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename); +#endif /*LODEPNG_COMPILE_DISK*/ + +#ifdef LODEPNG_COMPILE_CPP +/* The LodePNG C++ wrapper uses std::vectors instead of manually allocated memory buffers. */ +namespace lodepng { +#ifdef LODEPNG_COMPILE_PNG +/* Wrapper around LodePNGState, which automatically calls lodepng_state_init in the constructor +and lodepng_state_cleanup in the desctructor.*/ +class State : public LodePNGState { + public: + State(); + State(const State& other); + ~State(); + State& operator=(const State& other); +}; + +#ifdef LODEPNG_COMPILE_DECODER +/* Same as other lodepng::decode, but using a State for more settings and information. */ +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + State& state, + const unsigned char* in, size_t insize); +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + State& state, + const std::vector& in); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/* Same as other lodepng::encode, but using a State for more settings and information. */ +unsigned encode(std::vector& out, + const unsigned char* in, unsigned w, unsigned h, + State& state); +unsigned encode(std::vector& out, + const std::vector& in, unsigned w, unsigned h, + State& state); +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_DISK +/* +Load a file from disk into an std::vector. +return value: error code (0 means ok) + +NOTE: Wide-character filenames are not supported, you can use an external method +to handle such files and decode in-memory +*/ +unsigned load_file(std::vector& buffer, const std::string& filename); + +/* +Save the binary data in an std::vector to a file on disk. The file is overwritten +without warning. + +NOTE: Wide-character filenames are not supported, you can use an external method +to handle such files and encode in-memory +*/ +unsigned save_file(const std::vector& buffer, const std::string& filename); +#endif /* LODEPNG_COMPILE_DISK */ +#endif /* LODEPNG_COMPILE_PNG */ + +#ifdef LODEPNG_COMPILE_ZLIB +#ifdef LODEPNG_COMPILE_DECODER +/* Zlib-decompress an unsigned char buffer */ +unsigned decompress(std::vector& out, const unsigned char* in, size_t insize, + const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings); + +/* Zlib-decompress an std::vector */ +unsigned decompress(std::vector& out, const std::vector& in, + const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings); +#endif /* LODEPNG_COMPILE_DECODER */ + +#ifdef LODEPNG_COMPILE_ENCODER +/* Zlib-compress an unsigned char buffer */ +unsigned compress(std::vector& out, const unsigned char* in, size_t insize, + const LodePNGCompressSettings& settings = lodepng_default_compress_settings); + +/* Zlib-compress an std::vector */ +unsigned compress(std::vector& out, const std::vector& in, + const LodePNGCompressSettings& settings = lodepng_default_compress_settings); +#endif /* LODEPNG_COMPILE_ENCODER */ +#endif /* LODEPNG_COMPILE_ZLIB */ +} /* namespace lodepng */ +#endif /*LODEPNG_COMPILE_CPP*/ + +/* +TODO: +[.] test if there are no memory leaks or security exploits - done a lot but needs to be checked often +[.] check compatibility with various compilers - done but needs to be redone for every newer version +[X] converting color to 16-bit per channel types +[X] support color profile chunk types (but never let them touch RGB values by default) +[ ] support all second edition public PNG chunk types (almost done except sPLT and hIST) +[X] support non-animation third edition public PNG chunk types: eXIf, cICP, mDCV, cLLI +[ ] make sure encoder generates no chunks with size > (2^31)-1 +[ ] partial decoding (stream processing) +[X] let the "isFullyOpaque" function check color keys and transparent palettes too +[X] better name for the variables "codes", "codesD", "codelengthcodes", "clcl" and "lldl" +[ ] allow treating some errors like warnings, when image is recoverable (e.g. 69, 57, 58) +[ ] make warnings like: oob palette, checksum fail, data after iend, wrong/unknown crit chunk, no null terminator in text, ... +[ ] error messages with line numbers (and version) +[ ] errors in state instead of as return code? +[ ] new errors/warnings like suspiciously big decompressed ztxt or iccp chunk +[ ] let the C++ wrapper catch exceptions coming from the standard library and return LodePNG error codes +[ ] allow user to provide custom color conversion functions, e.g. for premultiplied alpha, padding bits or not, ... +[ ] allow user to give data (void*) to custom allocator +[X] provide alternatives for C library functions not present on some platforms (memcpy, ...) +*/ + +#endif /*LODEPNG_H inclusion guard*/ + +/* +LodePNG Documentation +--------------------- + +0. table of contents +-------------------- + + 1. about + 1.1. supported features + 1.2. features not supported + 2. C and C++ version + 3. security + 4. decoding + 5. encoding + 6. color conversions + 6.1. PNG color types + 6.2. color conversions + 6.3. padding bits + 6.4. A note about 16-bits per channel and endianness + 7. error values + 8. chunks and PNG editing + 9. compiler support + 10. examples + 10.1. decoder C++ example + 10.2. decoder C example + 11. state settings reference + 12. changes + 13. contact information + + +1. about +-------- + +PNG is a file format to store raster images losslessly with good compression, +supporting different color types and alpha channel. + +LodePNG is a PNG codec according to the Portable Network Graphics (PNG) +Specification (Second Edition) - W3C Recommendation 10 November 2003. + +The specifications used are: + +*) Portable Network Graphics (PNG) Specification (Second Edition): + http://www.w3.org/TR/2003/REC-PNG-20031110 +*) RFC 1950 ZLIB Compressed Data Format version 3.3: + http://www.gzip.org/zlib/rfc-zlib.html +*) RFC 1951 DEFLATE Compressed Data Format Specification ver 1.3: + http://www.gzip.org/zlib/rfc-deflate.html + +The most recent version of LodePNG can currently be found at +http://lodev.org/lodepng/ + +LodePNG works both in C (ISO C90) and C++, with a C++ wrapper that adds +extra functionality. + +LodePNG exists out of two files: +-lodepng.h: the header file for both C and C++ +-lodepng.c(pp): give it the name lodepng.c or lodepng.cpp (or .cc) depending on your usage + +If you want to start using LodePNG right away without reading this doc, get the +examples from the LodePNG website to see how to use it in code, or check the +smaller examples in chapter 13 here. + +LodePNG is simple but only supports the basic requirements. To achieve +simplicity, the following design choices were made: There are no dependencies +on any external library. There are functions to decode and encode a PNG with +a single function call, and extended versions of these functions taking a +LodePNGState struct allowing to specify or get more information. By default +the colors of the raw image are always RGB or RGBA, no matter what color type +the PNG file uses. To read and write files, there are simple functions to +convert the files to/from buffers in memory. + +This all makes LodePNG suitable for loading textures in games, demos and small +programs, ... It's less suitable for full fledged image editors, loading PNGs +over network (it requires all the image data to be available before decoding can +begin), life-critical systems, ... + +1.1. supported features +----------------------- + +The following features are supported by the decoder: + +*) decoding of PNGs with any color type, bit depth and interlace mode, to a 24- or 32-bit color raw image, + or the same color type as the PNG +*) encoding of PNGs, from any raw image to 24- or 32-bit color, or the same color type as the raw image +*) Adam7 interlace and deinterlace for any color type +*) loading the image from harddisk or decoding it from a buffer from other sources than harddisk +*) support for alpha channels, including RGBA color model, translucent palettes and color keying +*) zlib decompression (inflate) +*) zlib compression (deflate) +*) CRC32 and ADLER32 checksums +*) colorimetric color profile conversions: currently experimentally available in lodepng_util.cpp only, + plus alternatively ability to pass on chroma/gamma/ICC profile information to other color management system. +*) handling of unknown chunks, allowing making a PNG editor that stores custom and unknown chunks. +*) the following chunks are supported by both encoder and decoder: + IHDR: header information + PLTE: color palette + IDAT: pixel data + IEND: the final chunk + tRNS: transparency for palettized images + tEXt: textual information + zTXt: compressed textual information + iTXt: international textual information + bKGD: suggested background color + pHYs: physical dimensions + tIME: modification time + cHRM: RGB chromaticities + gAMA: RGB gamma correction + iCCP: ICC color profile + sRGB: rendering intent + sBIT: significant bits + +1.2. features not supported +--------------------------- + +The following features are not (yet) supported: + +*) some features needed to make a conformant PNG-Editor might be still missing. +*) partial loading/stream processing. All data must be available and is processed in one call. +*) The hIST and sPLT public chunks are not (yet) supported but treated as unknown chunks + + +2. C and C++ version +-------------------- + +The C version uses buffers allocated with alloc that you need to free() +yourself. You need to use init and cleanup functions for each struct whenever +using a struct from the C version to avoid exploits and memory leaks. + +The C++ version has extra functions with std::vectors in the interface and the +lodepng::State class which is a LodePNGState with constructor and destructor. + +These files work without modification for both C and C++ compilers because all +the additional C++ code is in "#ifdef __cplusplus" blocks that make C-compilers +ignore it, and the C code is made to compile both with strict ISO C90 and C++. + +To use the C++ version, you need to rename the source file to lodepng.cpp +(instead of lodepng.c), and compile it with a C++ compiler. + +To use the C version, you need to rename the source file to lodepng.c (instead +of lodepng.cpp), and compile it with a C compiler. + + +3. Security +----------- + +Even if carefully designed, it's always possible that LodePNG contains possible +exploits. If you discover one, please let me know, and it will be fixed. + +When using LodePNG, care has to be taken with the C version of LodePNG, as well +as the C-style structs when working with C++. The following conventions are used +for all C-style structs: + +-if a struct has a corresponding init function, always call the init function when making a new one +-if a struct has a corresponding cleanup function, call it before the struct disappears to avoid memory leaks +-if a struct has a corresponding copy function, use the copy function instead of "=". + The destination must also be inited already. + + +4. Decoding +----------- + +Decoding converts a PNG compressed image to a raw pixel buffer. + +Most documentation on using the decoder is at its declarations in the header +above. For C, simple decoding can be done with functions such as +lodepng_decode32, and more advanced decoding can be done with the struct +LodePNGState and lodepng_decode. For C++, all decoding can be done with the +various lodepng::decode functions, and lodepng::State can be used for advanced +features. + +When using the LodePNGState, it uses the following fields for decoding: +*) LodePNGInfo info_png: it stores extra information about the PNG (the input) in here +*) LodePNGColorMode info_raw: here you can say what color mode of the raw image (the output) you want to get +*) LodePNGDecoderSettings decoder: you can specify a few extra settings for the decoder to use + +LodePNGInfo info_png +-------------------- + +After decoding, this contains extra information of the PNG image, except the actual +pixels, width and height because these are already gotten directly from the decoder +functions. + +It contains for example the original color type of the PNG image, text comments, +suggested background color, etc... More details about the LodePNGInfo struct are +at its declaration documentation. + +LodePNGColorMode info_raw +------------------------- + +When decoding, here you can specify which color type you want +the resulting raw image to be. If this is different from the colortype of the +PNG, then the decoder will automatically convert the result. This conversion +always works, except if you want it to convert a color PNG to grayscale or to +a palette with missing colors. + +By default, 32-bit color is used for the result. + +LodePNGDecoderSettings decoder +------------------------------ + +The settings can be used to ignore the errors created by invalid CRC and Adler32 +chunks, and to disable the decoding of tEXt chunks. + +There's also a setting color_convert, true by default. If false, no conversion +is done, the resulting data will be as it was in the PNG (after decompression) +and you'll have to puzzle the colors of the pixels together yourself using the +color type information in the LodePNGInfo. + + +5. Encoding +----------- + +Encoding converts a raw pixel buffer to a PNG compressed image. + +Most documentation on using the encoder is at its declarations in the header +above. For C, simple encoding can be done with functions such as +lodepng_encode32, and more advanced decoding can be done with the struct +LodePNGState and lodepng_encode. For C++, all encoding can be done with the +various lodepng::encode functions, and lodepng::State can be used for advanced +features. + +Like the decoder, the encoder can also give errors. However it gives less errors +since the encoder input is trusted, the decoder input (a PNG image that could +be forged by anyone) is not trusted. + +When using the LodePNGState, it uses the following fields for encoding: +*) LodePNGInfo info_png: here you specify how you want the PNG (the output) to be. +*) LodePNGColorMode info_raw: here you say what color type of the raw image (the input) has +*) LodePNGEncoderSettings encoder: you can specify a few settings for the encoder to use + +LodePNGInfo info_png +-------------------- + +When encoding, you use this the opposite way as when decoding: for encoding, +you fill in the values you want the PNG to have before encoding. By default it's +not needed to specify a color type for the PNG since it's automatically chosen, +but it's possible to choose it yourself given the right settings. + +The encoder will not always exactly match the LodePNGInfo struct you give, +it tries as close as possible. Some things are ignored by the encoder. The +encoder uses, for example, the following settings from it when applicable: +colortype and bitdepth, text chunks, time chunk, the color key, the palette, the +background color, the interlace method, unknown chunks, ... + +When encoding to a PNG with colortype 3, the encoder will generate a PLTE chunk. +If the palette contains any colors for which the alpha channel is not 255 (so +there are translucent colors in the palette), it'll add a tRNS chunk. + +LodePNGColorMode info_raw +------------------------- + +You specify the color type of the raw image that you give to the input here, +including a possible transparent color key and palette you happen to be using in +your raw image data. + +By default, 32-bit color is assumed, meaning your input has to be in RGBA +format with 4 bytes (unsigned chars) per pixel. + +LodePNGEncoderSettings encoder +------------------------------ + +The following settings are supported (some are in sub-structs): +*) auto_convert: when this option is enabled, the encoder will +automatically choose the smallest possible color mode (including color key) that +can encode the colors of all pixels without information loss. +*) btype: the block type for LZ77. 0 = uncompressed, 1 = fixed huffman tree, + 2 = dynamic huffman tree (best compression). Should be 2 for proper + compression. +*) use_lz77: whether or not to use LZ77 for compressed block types. Should be + true for proper compression. +*) windowsize: the window size used by the LZ77 encoder (1 - 32768). Has value + 2048 by default, but can be set to 32768 for better, but slow, compression. +*) force_palette: if colortype is 2 or 6, you can make the encoder write a PLTE + chunk if force_palette is true. This can used as suggested palette to convert + to by viewers that don't support more than 256 colors (if those still exist) +*) add_id: add text chunk "Encoder: LodePNG " to the image. +*) text_compression: default 1. If 1, it'll store texts as zTXt instead of tEXt chunks. + zTXt chunks use zlib compression on the text. This gives a smaller result on + large texts but a larger result on small texts (such as a single program name). + It's all tEXt or all zTXt though, there's no separate setting per text yet. + + +6. color conversions +-------------------- + +An important thing to note about LodePNG, is that the color type of the PNG, and +the color type of the raw image, are completely independent. By default, when +you decode a PNG, you get the result as a raw image in the color type you want, +no matter whether the PNG was encoded with a palette, grayscale or RGBA color. +And if you encode an image, by default LodePNG will automatically choose the PNG +color type that gives good compression based on the values of colors and amount +of colors in the image. It can be configured to let you control it instead as +well, though. + +To be able to do this, LodePNG does conversions from one color mode to another. +It can convert from almost any color type to any other color type, except the +following conversions: RGB to grayscale is not supported, and converting to a +palette when the palette doesn't have a required color is not supported. This is +not supported on purpose: this is information loss which requires a color +reduction algorithm that is beyond the scope of a PNG encoder (yes, RGB to gray +is easy, but there are multiple ways if you want to give some channels more +weight). + +By default, when decoding, you get the raw image in 32-bit RGBA or 24-bit RGB +color, no matter what color type the PNG has. And by default when encoding, +LodePNG automatically picks the best color model for the output PNG, and expects +the input image to be 32-bit RGBA or 24-bit RGB. So, unless you want to control +the color format of the images yourself, you can skip this chapter. + +6.1. PNG color types +-------------------- + +A PNG image can have many color types, ranging from 1-bit color to 64-bit color, +as well as palettized color modes. After the zlib decompression and unfiltering +in the PNG image is done, the raw pixel data will have that color type and thus +a certain amount of bits per pixel. If you want the output raw image after +decoding to have another color type, a conversion is done by LodePNG. + +The PNG specification gives the following color types: + +0: grayscale, bit depths 1, 2, 4, 8, 16 +2: RGB, bit depths 8 and 16 +3: palette, bit depths 1, 2, 4 and 8 +4: grayscale with alpha, bit depths 8 and 16 +6: RGBA, bit depths 8 and 16 + +Bit depth is the amount of bits per pixel per color channel. So the total amount +of bits per pixel is: amount of channels * bitdepth. + +6.2. color conversions +---------------------- + +As explained in the sections about the encoder and decoder, you can specify +color types and bit depths in info_png and info_raw to change the default +behaviour. + +If, when decoding, you want the raw image to be something else than the default, +you need to set the color type and bit depth you want in the LodePNGColorMode, +or the parameters colortype and bitdepth of the simple decoding function. + +If, when encoding, you use another color type than the default in the raw input +image, you need to specify its color type and bit depth in the LodePNGColorMode +of the raw image, or use the parameters colortype and bitdepth of the simple +encoding function. + +If, when encoding, you don't want LodePNG to choose the output PNG color type +but control it yourself, you need to set auto_convert in the encoder settings +to false, and specify the color type you want in the LodePNGInfo of the +encoder (including palette: it can generate a palette if auto_convert is true, +otherwise not). + +If the input and output color type differ (whether user chosen or auto chosen), +LodePNG will do a color conversion, which follows the rules below, and may +sometimes result in an error. + +To avoid some confusion: +-the decoder converts from PNG to raw image +-the encoder converts from raw image to PNG +-the colortype and bitdepth in LodePNGColorMode info_raw, are those of the raw image +-the colortype and bitdepth in the color field of LodePNGInfo info_png, are those of the PNG +-when encoding, the color type in LodePNGInfo is ignored if auto_convert + is enabled, it is automatically generated instead +-when decoding, the color type in LodePNGInfo is set by the decoder to that of the original + PNG image, but it can be ignored since the raw image has the color type you requested instead +-if the color type of the LodePNGColorMode and PNG image aren't the same, a conversion + between the color types is done if the color types are supported. If it is not + supported, an error is returned. If the types are the same, no conversion is done. +-even though some conversions aren't supported, LodePNG supports loading PNGs from any + colortype and saving PNGs to any colortype, sometimes it just requires preparing + the raw image correctly before encoding. +-both encoder and decoder use the same color converter. + +The function lodepng_convert does the color conversion. It is available in the +interface but normally isn't needed since the encoder and decoder already call +it. + +Non supported color conversions: +-color to grayscale when non-gray pixels are present: no error is thrown, but +the result will look ugly because only the red channel is taken (it assumes all +three channels are the same in this case so ignores green and blue). The reason +no error is given is to allow converting from three-channel grayscale images to +one-channel even if there are numerical imprecisions. +-anything to palette when the palette does not have an exact match for a from-color +in it: in this case an error is thrown + +Supported color conversions: +-anything to 8-bit RGB, 8-bit RGBA, 16-bit RGB, 16-bit RGBA +-any gray or gray+alpha, to gray or gray+alpha +-anything to a palette, as long as the palette has the requested colors in it +-removing alpha channel +-higher to smaller bitdepth, and vice versa + +If you want no color conversion to be done (e.g. for speed or control): +-In the encoder, you can make it save a PNG with any color type by giving the +raw color mode and LodePNGInfo the same color mode, and setting auto_convert to +false. +-In the decoder, you can make it store the pixel data in the same color type +as the PNG has, by setting the color_convert setting to false. Settings in +info_raw are then ignored. + +6.3. padding bits +----------------- + +In the PNG file format, if a less than 8-bit per pixel color type is used and the scanlines +have a bit amount that isn't a multiple of 8, then padding bits are used so that each +scanline starts at a fresh byte. But that is NOT true for the LodePNG raw input and output. +The raw input image you give to the encoder, and the raw output image you get from the decoder +will NOT have these padding bits, e.g. in the case of a 1-bit image with a width +of 7 pixels, the first pixel of the second scanline will the 8th bit of the first byte, +not the first bit of a new byte. + +6.4. A note about 16-bits per channel and endianness +---------------------------------------------------- + +LodePNG uses unsigned char arrays for 16-bit per channel colors too, just like +for any other color format. The 16-bit values are stored in big endian (most +significant byte first) in these arrays. This is the opposite order of the +little endian used by x86 CPU's. + +LodePNG always uses big endian because the PNG file format does so internally. +Conversions to other formats than PNG uses internally are not supported by +LodePNG on purpose, there are myriads of formats, including endianness of 16-bit +colors, the order in which you store R, G, B and A, and so on. Supporting and +converting to/from all that is outside the scope of LodePNG. + +This may mean that, depending on your use case, you may want to convert the big +endian output of LodePNG to little endian with a for loop. This is certainly not +always needed, many applications and libraries support big endian 16-bit colors +anyway, but it means you cannot simply cast the unsigned char* buffer to an +unsigned short* buffer on x86 CPUs. + + +7. error values +--------------- + +All functions in LodePNG that return an error code, return 0 if everything went +OK, or a non-zero code if there was an error. + +The meaning of the LodePNG error values can be retrieved with the function +lodepng_error_text: given the numerical error code, it returns a description +of the error in English as a string. + +Check the implementation of lodepng_error_text to see the meaning of each code. + +It is not recommended to use the numerical values to programmatically make +different decisions based on error types as the numbers are not guaranteed to +stay backwards compatible. They are for human consumption only. Programmatically +only 0 or non-0 matter. + + +8. chunks and PNG editing +------------------------- + +If you want to add extra chunks to a PNG you encode, or use LodePNG for a PNG +editor that should follow the rules about handling of unknown chunks, or if your +program is able to read other types of chunks than the ones handled by LodePNG, +then that's possible with the chunk functions of LodePNG. + +A PNG chunk has the following layout: + +4 bytes length +4 bytes type name +length bytes data +4 bytes CRC + +8.1. iterating through chunks +----------------------------- + +If you have a buffer containing the PNG image data, then the first chunk (the +IHDR chunk) starts at byte number 8 of that buffer. The first 8 bytes are the +signature of the PNG and are not part of a chunk. But if you start at byte 8 +then you have a chunk, and can check the following things of it. + +NOTE: none of these functions check for memory buffer boundaries. To avoid +exploits, always make sure the buffer contains all the data of the chunks. +When using lodepng_chunk_next, make sure the returned value is within the +allocated memory. + +unsigned lodepng_chunk_length(const unsigned char* chunk): + +Get the length of the chunk's data. The total chunk length is this length + 12. + +void lodepng_chunk_type(char type[5], const unsigned char* chunk): +unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type): + +Get the type of the chunk or compare if it's a certain type + +unsigned char lodepng_chunk_critical(const unsigned char* chunk): +unsigned char lodepng_chunk_private(const unsigned char* chunk): +unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk): + +Check if the chunk is critical in the PNG standard (only IHDR, PLTE, IDAT and IEND are). +Check if the chunk is private (public chunks are part of the standard, private ones not). +Check if the chunk is safe to copy. If it's not, then, when modifying data in a critical +chunk, unsafe to copy chunks of the old image may NOT be saved in the new one if your +program doesn't handle that type of unknown chunk. + +unsigned char* lodepng_chunk_data(unsigned char* chunk): +const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk): + +Get a pointer to the start of the data of the chunk. + +unsigned lodepng_chunk_check_crc(const unsigned char* chunk): +void lodepng_chunk_generate_crc(unsigned char* chunk): + +Check if the crc is correct or generate a correct one. + +unsigned char* lodepng_chunk_next(unsigned char* chunk): +const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk): + +Iterate to the next chunk. This works if you have a buffer with consecutive chunks. Note that these +functions do no boundary checking of the allocated data whatsoever, so make sure there is enough +data available in the buffer to be able to go to the next chunk. + +unsigned lodepng_chunk_append(unsigned char** out, size_t* outsize, const unsigned char* chunk): +unsigned lodepng_chunk_create(unsigned char** out, size_t* outsize, unsigned length, + const char* type, const unsigned char* data): + +These functions are used to create new chunks that are appended to the data in *out that has +length *outsize. The append function appends an existing chunk to the new data. The create +function creates a new chunk with the given parameters and appends it. Type is the 4-letter +name of the chunk. + +8.2. chunks in info_png +----------------------- + +The LodePNGInfo struct contains fields with the unknown chunk in it. It has 3 +buffers (each with size) to contain 3 types of unknown chunks: +the ones that come before the PLTE chunk, the ones that come between the PLTE +and the IDAT chunks, and the ones that come after the IDAT chunks. +It's necessary to make the distinction between these 3 cases because the PNG +standard forces to keep the ordering of unknown chunks compared to the critical +chunks, but does not force any other ordering rules. + +info_png.unknown_chunks_data[0] is the chunks before PLTE +info_png.unknown_chunks_data[1] is the chunks after PLTE, before IDAT +info_png.unknown_chunks_data[2] is the chunks after IDAT + +The chunks in these 3 buffers can be iterated through and read by using the same +way described in the previous subchapter. + +When using the decoder to decode a PNG, you can make it store all unknown chunks +if you set the option settings.remember_unknown_chunks to 1. By default, this +option is off (0). + +The encoder will always encode unknown chunks that are stored in the info_png. +If you need it to add a particular chunk that isn't known by LodePNG, you can +use lodepng_chunk_append or lodepng_chunk_create to the chunk data in +info_png.unknown_chunks_data[x]. + +Chunks that are known by LodePNG should not be added in that way. E.g. to make +LodePNG add a bKGD chunk, set background_defined to true and add the correct +parameters there instead. + + +9. compiler support +------------------- + +No libraries other than the current standard C library are needed to compile +LodePNG. For the C++ version, only the standard C++ library is needed on top. +Add the files lodepng.c(pp) and lodepng.h to your project, include +lodepng.h where needed, and your program can read/write PNG files. + +It is compatible with C90 and up, and C++03 and up. + +If performance is important, use optimization when compiling! For both the +encoder and decoder, this makes a large difference. + +Make sure that LodePNG is compiled with the same compiler of the same version +and with the same settings as the rest of the program, or the interfaces with +std::vectors and std::strings in C++ can be incompatible. + +CHAR_BITS must be 8 or higher, because LodePNG uses unsigned chars for octets. + +*) gcc and g++ + +LodePNG is developed in gcc so this compiler is natively supported. It gives no +warnings with compiler options "-Wall -Wextra -pedantic -ansi", with gcc and g++ +version 4.7.1 on Linux, 32-bit and 64-bit. + +*) Clang + +Fully supported and warning-free. + +*) Mingw + +The Mingw compiler (a port of gcc for Windows) should be fully supported by +LodePNG. + +*) Visual Studio and Visual C++ Express Edition + +LodePNG should be warning-free with warning level W4. Two warnings were disabled +with pragmas though: warning 4244 about implicit conversions, and warning 4996 +where it wants to use a non-standard function fopen_s instead of the standard C +fopen. + +Visual Studio may want "stdafx.h" files to be included in each source file and +give an error "unexpected end of file while looking for precompiled header". +This is not standard C++ and will not be added to the stock LodePNG. You can +disable it for lodepng.cpp only by right clicking it, Properties, C/C++, +Precompiled Headers, and set it to Not Using Precompiled Headers there. + +NOTE: Modern versions of VS should be fully supported, but old versions, e.g. +VS6, are not guaranteed to work. + +*) Compilers on Macintosh + +LodePNG has been reported to work both with gcc and LLVM for Macintosh, both for +C and C++. + +*) Other Compilers + +If you encounter problems on any compilers, feel free to let me know and I may +try to fix it if the compiler is modern and standards compliant. + + +10. examples +------------ + +This decoder example shows the most basic usage of LodePNG. More complex +examples can be found on the LodePNG website. + +NOTE: these examples do not support wide-character filenames, you can use an +external method to handle such files and encode or decode in-memory + +10.1. decoder C++ example +------------------------- + +#include "lodepng.h" +#include + +int main(int argc, char *argv[]) { + const char* filename = argc > 1 ? argv[1] : "test.png"; + + //load and decode + std::vector image; + unsigned width, height; + unsigned error = lodepng::decode(image, width, height, filename); + + //if there's an error, display it + if(error) std::cout << "decoder error " << error << ": " << lodepng_error_text(error) << std::endl; + + //the pixels are now in the vector "image", 4 bytes per pixel, ordered RGBARGBA..., use it as texture, draw it, ... +} + +10.2. decoder C example +----------------------- + +#include "lodepng.h" + +int main(int argc, char *argv[]) { + unsigned error; + unsigned char* image; + size_t width, height; + const char* filename = argc > 1 ? argv[1] : "test.png"; + + error = lodepng_decode32_file(&image, &width, &height, filename); + + if(error) printf("decoder error %u: %s\n", error, lodepng_error_text(error)); + + / * use image here * / + + free(image); + return 0; +} + +11. state settings reference +---------------------------- + +A quick reference of some settings to set on the LodePNGState + +For decoding: + +state.decoder.zlibsettings.ignore_adler32: ignore ADLER32 checksums +state.decoder.zlibsettings.custom_...: use custom inflate function +state.decoder.ignore_crc: ignore CRC checksums +state.decoder.ignore_critical: ignore unknown critical chunks +state.decoder.ignore_end: ignore missing IEND chunk. May fail if this corruption causes other errors +state.decoder.color_convert: convert internal PNG color to chosen one +state.decoder.read_text_chunks: whether to read in text metadata chunks +state.decoder.remember_unknown_chunks: whether to read in unknown chunks +state.info_raw.colortype: desired color type for decoded image +state.info_raw.bitdepth: desired bit depth for decoded image +state.info_raw....: more color settings, see struct LodePNGColorMode +state.info_png....: no settings for decoder but output, see struct LodePNGInfo + +For encoding: + +state.encoder.zlibsettings.btype: disable compression by setting it to 0 +state.encoder.zlibsettings.use_lz77: use LZ77 in compression +state.encoder.zlibsettings.windowsize: tweak LZ77 windowsize +state.encoder.zlibsettings.minmatch: tweak min LZ77 length to match +state.encoder.zlibsettings.nicematch: tweak LZ77 match where to stop searching +state.encoder.zlibsettings.lazymatching: try one more LZ77 matching +state.encoder.zlibsettings.custom_...: use custom deflate function +state.encoder.auto_convert: choose optimal PNG color type, if 0 uses info_png +state.encoder.filter_palette_zero: PNG filter strategy for palette +state.encoder.filter_strategy: PNG filter strategy to encode with +state.encoder.force_palette: add palette even if not encoding to one +state.encoder.add_id: add LodePNG identifier and version as a text chunk +state.encoder.text_compression: use compressed text chunks for metadata +state.info_raw.colortype: color type of raw input image you provide +state.info_raw.bitdepth: bit depth of raw input image you provide +state.info_raw: more color settings, see struct LodePNGColorMode +state.info_png.color.colortype: desired color type if auto_convert is false +state.info_png.color.bitdepth: desired bit depth if auto_convert is false +state.info_png.color....: more color settings, see struct LodePNGColorMode +state.info_png....: more PNG related settings, see struct LodePNGInfo + + +12. changes +----------- + +The version number of LodePNG is the date of the change given in the format +yyyymmdd. + +Some changes aren't backwards compatible. Those are indicated with a (!) +symbol. + +Not all changes are listed here, the commit history in github lists more: +https://github.com/lvandeve/lodepng + +*) 6 may 2025 (!): renamed mDCv to mDCV and cLLi to cLLI as per the recent + rename in the draft png third edition spec. Please note that as long as the + third edition is not finalized, backwards-incompatible changes to its + features are possible. +*) 23 dec 2024: added support for the mDCv and cLLi chunks (for png third + edition spec) +*) 22 dec 2024: added support for the cICP chunk (for png third edition spec) +*) 15 dec 2024: added support for the eXIf chunk (for png third edition spec) +*) 10 apr 2023: faster CRC32 implementation, but with larger lookup table. +*) 13 jun 2022: added support for the sBIT chunk. +*) 09 jan 2022: minor decoder speed improvements. +*) 27 jun 2021: added warnings that file reading/writing functions don't support + wide-character filenames (support for this is not planned, opening files is + not the core part of PNG decoding/decoding and is platform dependent). +*) 17 oct 2020: prevent decoding too large text/icc chunks by default. +*) 06 mar 2020: simplified some of the dynamic memory allocations. +*) 12 jan 2020: (!) added 'end' argument to lodepng_chunk_next to allow correct + overflow checks. +*) 14 aug 2019: around 25% faster decoding thanks to huffman lookup tables. +*) 15 jun 2019: (!) auto_choose_color API changed (for bugfix: don't use palette + if gray ICC profile) and non-ICC LodePNGColorProfile renamed to + LodePNGColorStats. +*) 30 dec 2018: code style changes only: removed newlines before opening braces. +*) 10 sep 2018: added way to inspect metadata chunks without full decoding. +*) 19 aug 2018: (!) fixed color mode bKGD is encoded with and made it use + palette index in case of palette. +*) 10 aug 2018: (!) added support for gAMA, cHRM, sRGB and iCCP chunks. This + change is backwards compatible unless you relied on unknown_chunks for those. +*) 11 jun 2018: less restrictive check for pixel size integer overflow +*) 14 jan 2018: allow optionally ignoring a few more recoverable errors +*) 17 sep 2017: fix memory leak for some encoder input error cases +*) 27 nov 2016: grey+alpha auto color model detection bugfix +*) 18 apr 2016: Changed qsort to custom stable sort (for platforms w/o qsort). +*) 09 apr 2016: Fixed colorkey usage detection, and better file loading (within + the limits of pure C90). +*) 08 dec 2015: Made load_file function return error if file can't be opened. +*) 24 oct 2015: Bugfix with decoding to palette output. +*) 18 apr 2015: Boundary PM instead of just package-merge for faster encoding. +*) 24 aug 2014: Moved to github +*) 23 aug 2014: Reduced needless memory usage of decoder. +*) 28 jun 2014: Removed fix_png setting, always support palette OOB for + simplicity. Made ColorProfile public. +*) 09 jun 2014: Faster encoder by fixing hash bug and more zeros optimization. +*) 22 dec 2013: Power of two windowsize required for optimization. +*) 15 apr 2013: Fixed bug with LAC_ALPHA and color key. +*) 25 mar 2013: Added an optional feature to ignore some PNG errors (fix_png). +*) 11 mar 2013: (!) Bugfix with custom free. Changed from "my" to "lodepng_" + prefix for the custom allocators and made it possible with a new #define to + use custom ones in your project without needing to change lodepng's code. +*) 28 jan 2013: Bugfix with color key. +*) 27 oct 2012: Tweaks in text chunk keyword length error handling. +*) 8 oct 2012: (!) Added new filter strategy (entropy) and new auto color mode. + (no palette). Better deflate tree encoding. New compression tweak settings. + Faster color conversions while decoding. Some internal cleanups. +*) 23 sep 2012: Reduced warnings in Visual Studio a little bit. +*) 1 sep 2012: (!) Removed #define's for giving custom (de)compression functions + and made it work with function pointers instead. +*) 23 jun 2012: Added more filter strategies. Made it easier to use custom alloc + and free functions and toggle #defines from compiler flags. Small fixes. +*) 6 may 2012: (!) Made plugging in custom zlib/deflate functions more flexible. +*) 22 apr 2012: (!) Made interface more consistent, renaming a lot. Removed + redundant C++ codec classes. Reduced amount of structs. Everything changed, + but it is cleaner now imho and functionality remains the same. Also fixed + several bugs and shrunk the implementation code. Made new samples. +*) 6 nov 2011: (!) By default, the encoder now automatically chooses the best + PNG color model and bit depth, based on the amount and type of colors of the + raw image. For this, autoLeaveOutAlphaChannel replaced by auto_choose_color. +*) 9 oct 2011: simpler hash chain implementation for the encoder. +*) 8 sep 2011: lz77 encoder lazy matching instead of greedy matching. +*) 23 aug 2011: tweaked the zlib compression parameters after benchmarking. + A bug with the PNG filtertype heuristic was fixed, so that it chooses much + better ones (it's quite significant). A setting to do an experimental, slow, + brute force search for PNG filter types is added. +*) 17 aug 2011: (!) changed some C zlib related function names. +*) 16 aug 2011: made the code less wide (max 120 characters per line). +*) 17 apr 2011: code cleanup. Bugfixes. Convert low to 16-bit per sample colors. +*) 21 feb 2011: fixed compiling for C90. Fixed compiling with sections disabled. +*) 11 dec 2010: encoding is made faster, based on suggestion by Peter Eastman + to optimize long sequences of zeros. +*) 13 nov 2010: added LodePNG_InfoColor_hasPaletteAlpha and + LodePNG_InfoColor_canHaveAlpha functions for convenience. +*) 7 nov 2010: added LodePNG_error_text function to get error code description. +*) 30 oct 2010: made decoding slightly faster +*) 26 oct 2010: (!) changed some C function and struct names (more consistent). + Reorganized the documentation and the declaration order in the header. +*) 08 aug 2010: only changed some comments and external samples. +*) 05 jul 2010: fixed bug thanks to warnings in the new gcc version. +*) 14 mar 2010: fixed bug where too much memory was allocated for char buffers. +*) 02 sep 2008: fixed bug where it could create empty tree that linux apps could + read by ignoring the problem but windows apps couldn't. +*) 06 jun 2008: added more error checks for out of memory cases. +*) 26 apr 2008: added a few more checks here and there to ensure more safety. +*) 06 mar 2008: crash with encoding of strings fixed +*) 02 feb 2008: support for international text chunks added (iTXt) +*) 23 jan 2008: small cleanups, and #defines to divide code in sections +*) 20 jan 2008: support for unknown chunks allowing using LodePNG for an editor. +*) 18 jan 2008: support for tIME and pHYs chunks added to encoder and decoder. +*) 17 jan 2008: ability to encode and decode compressed zTXt chunks added + Also various fixes, such as in the deflate and the padding bits code. +*) 13 jan 2008: Added ability to encode Adam7-interlaced images. Improved + filtering code of encoder. +*) 07 jan 2008: (!) changed LodePNG to use ISO C90 instead of C++. A + C++ wrapper around this provides an interface almost identical to before. + Having LodePNG be pure ISO C90 makes it more portable. The C and C++ code + are together in these files but it works both for C and C++ compilers. +*) 29 dec 2007: (!) changed most integer types to unsigned int + other tweaks +*) 30 aug 2007: bug fixed which makes this Borland C++ compatible +*) 09 aug 2007: some VS2005 warnings removed again +*) 21 jul 2007: deflate code placed in new namespace separate from zlib code +*) 08 jun 2007: fixed bug with 2- and 4-bit color, and small interlaced images +*) 04 jun 2007: improved support for Visual Studio 2005: crash with accessing + invalid std::vector element [0] fixed, and level 3 and 4 warnings removed +*) 02 jun 2007: made the encoder add a tag with version by default +*) 27 may 2007: zlib and png code separated (but still in the same file), + simple encoder/decoder functions added for more simple usage cases +*) 19 may 2007: minor fixes, some code cleaning, new error added (error 69), + moved some examples from here to lodepng_examples.cpp +*) 12 may 2007: palette decoding bug fixed +*) 24 apr 2007: changed the license from BSD to the zlib license +*) 11 mar 2007: very simple addition: ability to encode bKGD chunks. +*) 04 mar 2007: (!) tEXt chunk related fixes, and support for encoding + palettized PNG images. Plus little interface change with palette and texts. +*) 03 mar 2007: Made it encode dynamic Huffman shorter with repeat codes. + Fixed a bug where the end code of a block had length 0 in the Huffman tree. +*) 26 feb 2007: Huffman compression with dynamic trees (BTYPE 2) now implemented + and supported by the encoder, resulting in smaller PNGs at the output. +*) 27 jan 2007: Made the Adler-32 test faster so that a timewaste is gone. +*) 24 jan 2007: gave encoder an error interface. Added color conversion from any + greyscale type to 8-bit greyscale with or without alpha. +*) 21 jan 2007: (!) Totally changed the interface. It allows more color types + to convert to and is more uniform. See the manual for how it works now. +*) 07 jan 2007: Some cleanup & fixes, and a few changes over the last days: + encode/decode custom tEXt chunks, separate classes for zlib & deflate, and + at last made the decoder give errors for incorrect Adler32 or Crc. +*) 01 jan 2007: Fixed bug with encoding PNGs with less than 8 bits per channel. +*) 29 dec 2006: Added support for encoding images without alpha channel, and + cleaned out code as well as making certain parts faster. +*) 28 dec 2006: Added "Settings" to the encoder. +*) 26 dec 2006: The encoder now does LZ77 encoding and produces much smaller files now. + Removed some code duplication in the decoder. Fixed little bug in an example. +*) 09 dec 2006: (!) Placed output parameters of public functions as first parameter. + Fixed a bug of the decoder with 16-bit per color. +*) 15 oct 2006: Changed documentation structure +*) 09 oct 2006: Encoder class added. It encodes a valid PNG image from the + given image buffer, however for now it's not compressed. +*) 08 sep 2006: (!) Changed to interface with a Decoder class +*) 30 jul 2006: (!) LodePNG_InfoPng , width and height are now retrieved in different + way. Renamed decodePNG to decodePNGGeneric. +*) 29 jul 2006: (!) Changed the interface: image info is now returned as a + struct of type LodePNG::LodePNG_Info, instead of a vector, which was a bit clumsy. +*) 28 jul 2006: Cleaned the code and added new error checks. + Corrected terminology "deflate" into "inflate". +*) 23 jun 2006: Added SDL example in the documentation in the header, this + example allows easy debugging by displaying the PNG and its transparency. +*) 22 jun 2006: (!) Changed way to obtain error value. Added + loadFile function for convenience. Made decodePNG32 faster. +*) 21 jun 2006: (!) Changed type of info vector to unsigned. + Changed position of palette in info vector. Fixed an important bug that + happened on PNGs with an uncompressed block. +*) 16 jun 2006: Internally changed unsigned into unsigned where + needed, and performed some optimizations. +*) 07 jun 2006: (!) Renamed functions to decodePNG and placed them + in LodePNG namespace. Changed the order of the parameters. Rewrote the + documentation in the header. Renamed files to lodepng.cpp and lodepng.h +*) 22 apr 2006: Optimized and improved some code +*) 07 sep 2005: (!) Changed to std::vector interface +*) 12 aug 2005: Initial release (C++, decoder only) +*/ diff --git a/Modules/lodepng-module/include/lodepng/module.h b/Modules/lodepng-module/include/lodepng/module.h new file mode 100644 index 000000000..7d35a208e --- /dev/null +++ b/Modules/lodepng-module/include/lodepng/module.h @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct Module lodepng_module; + +#ifdef __cplusplus +} +#endif diff --git a/Modules/lodepng-module/source/allocators.c b/Modules/lodepng-module/source/allocators.c new file mode 100644 index 000000000..3c334581a --- /dev/null +++ b/Modules/lodepng-module/source/allocators.c @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: Apache-2.0 +#include + +#include + +static const struct MemoryPolicy EXTERNAL_PREFERRED = { + .required = 0, + .desired = MEMORY_CAPABILITY_EXTERNAL, + .alignment = 0, +}; + +void* lodepng_malloc(size_t size) { + return memory_alloc_with_policy(size, &EXTERNAL_PREFERRED); +} + +void* lodepng_realloc(void* ptr, size_t new_size) { + return memory_realloc_with_policy(ptr, new_size, &EXTERNAL_PREFERRED); +} + +void lodepng_free(void* ptr) { + memory_free(ptr); +} diff --git a/Modules/lodepng-module/source/lodepng.c b/Modules/lodepng-module/source/lodepng.c new file mode 100644 index 000000000..692596f8b --- /dev/null +++ b/Modules/lodepng-module/source/lodepng.c @@ -0,0 +1,7249 @@ +/* +LodePNG version 20261001 + +Copyright (c) 2005-2026 Lode Vandevenne + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +/* +The manual and changelog are in the header file "lodepng.h" +Rename this file to lodepng.cpp to use it for C++, or to lodepng.c to use it for C. +*/ + +/* +Modified for Tactility: renamed from lodepng.cpp and includes (a wrapper +around the original lodepng.h, which is renamed to lodepng_upstream.h). +*/ + +#include + +#ifdef LODEPNG_COMPILE_DISK +#include /* LONG_MAX */ +#include /* file handling */ +#endif /* LODEPNG_COMPILE_DISK */ + +#ifdef LODEPNG_COMPILE_ALLOCATORS +#include /* allocations */ +#endif /* LODEPNG_COMPILE_ALLOCATORS */ + +#if defined(_MSC_VER) && (_MSC_VER >= 1310) /*Visual Studio: A few warning types are not desired here.*/ +#pragma warning( disable : 4244 ) /*implicit conversions: not warned by gcc -Wall -Wextra and requires too much casts*/ +#pragma warning( disable : 4996 ) /*VS does not like fopen, but fopen_s is not standard C so unusable here*/ +#endif /*_MSC_VER */ + +const char* LODEPNG_VERSION_STRING = "20261001"; + +/* +This source file is divided into the following large parts. The code sections +with the "LODEPNG_COMPILE_" #defines divide this up further in an intermixed way. +-Tools for C and common code for PNG and Zlib +-C Code for Zlib (huffman, deflate, ...) +-C Code for PNG (file format chunks, adam7, PNG filters, color conversions, ...) +-The C++ wrapper around all of the above +*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* // Tools for C, and common code for PNG and Zlib. // */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*The malloc, realloc and free functions defined here with "lodepng_" in front +of the name, so that you can easily change them to others related to your +platform if needed. Everything else in the code calls these. Pass +-DLODEPNG_NO_COMPILE_ALLOCATORS to the compiler, or comment out +#define LODEPNG_COMPILE_ALLOCATORS in the header, to disable the ones here and +define them in your own project's source files without needing to change +lodepng source code. Don't forget to remove "static" if you copypaste them +from here.*/ + +#ifdef LODEPNG_COMPILE_ALLOCATORS +static void* lodepng_malloc(size_t size) { +#ifdef LODEPNG_MAX_ALLOC + if(size > LODEPNG_MAX_ALLOC) return 0; +#endif + return malloc(size); +} + +/* NOTE: when realloc returns NULL, it leaves the original memory untouched */ +static void* lodepng_realloc(void* ptr, size_t new_size) { +#ifdef LODEPNG_MAX_ALLOC + if(new_size > LODEPNG_MAX_ALLOC) return 0; +#endif + return realloc(ptr, new_size); +} + +static void lodepng_free(void* ptr) { + free(ptr); +} +#else /*LODEPNG_COMPILE_ALLOCATORS*/ +/* TODO: support giving additional void* payload to the custom allocators */ +void* lodepng_malloc(size_t size); +void* lodepng_realloc(void* ptr, size_t new_size); +void lodepng_free(void* ptr); +#endif /*LODEPNG_COMPILE_ALLOCATORS*/ + +/* convince the compiler to inline a function, for use when this measurably improves performance */ +/* inline is not available in C90, but use it when supported by the compiler */ +#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || (defined(__cplusplus) && (__cplusplus >= 199711L)) +#define LODEPNG_INLINE inline +#else +#define LODEPNG_INLINE /* not available */ +#endif + +/* restrict is not available in C90, but use it when supported by the compiler */ +#if (defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))) ||\ + (defined(_MSC_VER) && (_MSC_VER >= 1400)) || \ + (defined(__WATCOMC__) && (__WATCOMC__ >= 1250) && !defined(__cplusplus)) +#define LODEPNG_RESTRICT __restrict +#else +#define LODEPNG_RESTRICT /* not available */ +#endif + +/* Replacements for C library functions such as memcpy and strlen, to support platforms +where a full C library is not available. The compiler can recognize them and compile +to something as fast. */ + +static void lodepng_memcpy(void* LODEPNG_RESTRICT dst, + const void* LODEPNG_RESTRICT src, size_t size) { + size_t i; + for(i = 0; i < size; i++) ((char*)dst)[i] = ((const char*)src)[i]; +} + +static void lodepng_memset(void* LODEPNG_RESTRICT dst, + int value, size_t num) { + size_t i; + for(i = 0; i < num; i++) ((char*)dst)[i] = (char)value; +} + +/* does not check memory out of bounds, do not use on untrusted data */ +static size_t lodepng_strlen(const char* a) { + const char* orig = a; + /* avoid warning about unused function in case of disabled COMPILE... macros */ + (void)(&lodepng_strlen); + while(*a) a++; + return (size_t)(a - orig); +} + +#define LODEPNG_MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define LODEPNG_MIN(a, b) (((a) < (b)) ? (a) : (b)) + +#if defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_DECODER) +/* Safely check if adding two integers will overflow (no undefined +behavior, compiler removing the code, etc...) and output result. */ +static int lodepng_addofl(size_t a, size_t b, size_t* result) { + *result = a + b; /* Unsigned addition is well defined and safe in C90 */ + return *result < a; +} +#endif /*defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_DECODER)*/ + +#ifdef LODEPNG_COMPILE_DECODER +/* Safely check if multiplying two integers will overflow (no undefined +behavior, compiler removing the code, etc...) and output result. */ +static int lodepng_mulofl(size_t a, size_t b, size_t* result) { + *result = a * b; /* Unsigned multiplication is well defined and safe in C90 */ + return (a != 0 && *result / a != b); +} + +#ifdef LODEPNG_COMPILE_ZLIB +/* Safely check if a + b > c, even if overflow could happen. */ +static int lodepng_gtofl(size_t a, size_t b, size_t c) { + size_t d; + if(lodepng_addofl(a, b, &d)) return 1; + return d > c; +} +#endif /*LODEPNG_COMPILE_ZLIB*/ +#endif /*LODEPNG_COMPILE_DECODER*/ + + +/* +Often in case of an error a value is assigned to a variable and then it breaks +out of a loop (to go to the cleanup phase of a function). This macro does that. +It makes the error handling code shorter and more readable. + +Example: if(!uivector_resize(&lz77_encoded, datasize)) ERROR_BREAK(83); +*/ +#define CERROR_BREAK(errorvar, code){\ + errorvar = code;\ + break;\ +} + +/*version of CERROR_BREAK that assumes the common case where the error variable is named "error"*/ +#define ERROR_BREAK(code) CERROR_BREAK(error, code) + +/*Set error var to the error code, and return it.*/ +#define CERROR_RETURN_ERROR(errorvar, code){\ + errorvar = code;\ + return code;\ +} + +/*Try the code, if it returns error, also return the error.*/ +#define CERROR_TRY_RETURN(call){\ + unsigned error_ = call;\ + if(error_) return error_;\ +} + +/*Set error var to the error code, and return from the void function.*/ +#define CERROR_RETURN(errorvar, code){\ + errorvar = code;\ + return;\ +} + +/* +About uivector, ucvector and string: +-All of them wrap dynamic arrays or text strings in a similar way. +-LodePNG was originally written in C++. The vectors replace the std::vectors that were used in the C++ version. +-The string tools are made to avoid problems with compilers that declare things like strncat as deprecated. +-They're not used in the interface, only internally in this file as static functions. +-As with many other structs in this file, the init and cleanup functions serve as ctor and dtor. +*/ + +#ifdef LODEPNG_COMPILE_ZLIB +#ifdef LODEPNG_COMPILE_ENCODER +/*dynamic vector of unsigned ints*/ +typedef struct uivector { + unsigned* data; + size_t size; /*size in number of unsigned longs*/ + size_t allocsize; /*allocated size in bytes*/ +} uivector; + +static void uivector_cleanup(void* p) { + ((uivector*)p)->size = ((uivector*)p)->allocsize = 0; + lodepng_free(((uivector*)p)->data); + ((uivector*)p)->data = NULL; +} + +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned uivector_resize(uivector* p, size_t size) { + size_t allocsize = size * sizeof(unsigned); + if(allocsize > p->allocsize) { + size_t newsize = allocsize + (p->allocsize >> 1u); + void* data = lodepng_realloc(p->data, newsize); + if(data) { + p->allocsize = newsize; + p->data = (unsigned*)data; + } + else return 0; /*error: not enough memory*/ + } + p->size = size; + return 1; /*success*/ +} + +static void uivector_init(uivector* p) { + p->data = NULL; + p->size = p->allocsize = 0; +} + +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned uivector_push_back(uivector* p, unsigned c) { + if(!uivector_resize(p, p->size + 1)) return 0; + p->data[p->size - 1] = c; + return 1; +} +#endif /*LODEPNG_COMPILE_ENCODER*/ +#endif /*LODEPNG_COMPILE_ZLIB*/ + +/* /////////////////////////////////////////////////////////////////////////// */ + +/*dynamic vector of unsigned chars*/ +typedef struct ucvector { + unsigned char* data; + size_t size; /*used size*/ + size_t allocsize; /*allocated size*/ +} ucvector; + +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned ucvector_reserve(ucvector* p, size_t size) { + if(size > p->allocsize) { + size_t newsize = size + (p->allocsize >> 1u); + void* data = lodepng_realloc(p->data, newsize); + if(data) { + p->allocsize = newsize; + p->data = (unsigned char*)data; + } + else return 0; /*error: not enough memory*/ + } + return 1; /*success*/ +} + +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned ucvector_resize(ucvector* p, size_t size) { + p->size = size; + return ucvector_reserve(p, size); +} + +static ucvector ucvector_init(unsigned char* buffer, size_t size) { + ucvector v; + v.data = buffer; + v.allocsize = v.size = size; + return v; +} + +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_PNG +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + +/*also appends null termination character*/ +static char* alloc_string_sized(const char* in, size_t insize) { + char* out = (char*)lodepng_malloc(insize + 1); + if(out) { + lodepng_memcpy(out, in, insize); + out[insize] = 0; + } + return out; +} + +/* dynamically allocates a new string with a copy of the null terminated input text */ +static char* alloc_string(const char* in) { + return alloc_string_sized(in, lodepng_strlen(in)); +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +/* ////////////////////////////////////////////////////////////////////////// */ + +#if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_PNG) +static unsigned lodepng_read32bitInt(const unsigned char* buffer) { + return (((unsigned)buffer[0] << 24u) | ((unsigned)buffer[1] << 16u) | + ((unsigned)buffer[2] << 8u) | (unsigned)buffer[3]); +} +#endif /*defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_PNG)*/ + +#if defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER) +/*buffer must have at least 4 allocated bytes available*/ +static void lodepng_set32bitInt(unsigned char* buffer, unsigned value) { + buffer[0] = (unsigned char)((value >> 24) & 0xff); + buffer[1] = (unsigned char)((value >> 16) & 0xff); + buffer[2] = (unsigned char)((value >> 8) & 0xff); + buffer[3] = (unsigned char)((value ) & 0xff); +} +#endif /*defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / File IO / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_DISK + +/* returns negative value on error. This should be pure C compatible, so no fstat. */ +static long lodepng_filesize(FILE* file) { + long size; + if(fseek(file, 0, SEEK_END) != 0) return -1; + size = ftell(file); + /* It may give LONG_MAX as directory size, this is invalid for us. */ + if(size == LONG_MAX) return -1; + if(fseek(file, 0, SEEK_SET) != 0) return -1; + return size; +} + +/* Allocates the output buffer to the file size and reads the file into it. Returns error code.*/ +static unsigned lodepng_load_file_(unsigned char** out, size_t* outsize, FILE* file) { + long size = lodepng_filesize(file); + if(size < 0) return 78; + *outsize = (size_t)size; + *out = (unsigned char*)lodepng_malloc((size_t)size); + if(!(*out) && size > 0) return 83; /*the above malloc failed*/ + if(fread(*out, 1, *outsize, file) != *outsize) return 78; + return 0; /*ok*/ +} + +unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename) { + unsigned error; + FILE* file = fopen(filename, "rb"); + if(!file) return 78; + error = lodepng_load_file_(out, outsize, file); + fclose(file); + return error; +} + +/*write given buffer to the file, overwriting the file, it doesn't append to it.*/ +unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename) { + FILE* file = fopen(filename, "wb" ); + if(!file) return 79; + fwrite(buffer, 1, buffersize, file); + fclose(file); + return 0; +} + +#endif /*LODEPNG_COMPILE_DISK*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* // End of common code and tools. Begin of Zlib related code. // */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_ZLIB +#ifdef LODEPNG_COMPILE_ENCODER + +typedef struct { + ucvector* data; + unsigned char bp; /*ok to overflow, indicates bit pos inside byte*/ +} LodePNGBitWriter; + +static void LodePNGBitWriter_init(LodePNGBitWriter* writer, ucvector* data) { + writer->data = data; + writer->bp = 0; +} + +/*TODO: this ignores potential out of memory errors*/ +#define WRITEBIT(writer, bit){\ + /* append new byte */\ + if(((writer->bp) & 7u) == 0) {\ + if(!ucvector_resize(writer->data, writer->data->size + 1)) return;\ + writer->data->data[writer->data->size - 1] = 0;\ + }\ + (writer->data->data[writer->data->size - 1]) |= (bit << ((writer->bp) & 7u));\ + ++writer->bp;\ +} + +/* LSB of value is written first, and LSB of bytes is used first */ +static void writeBits(LodePNGBitWriter* writer, unsigned value, size_t nbits) { + if(nbits == 1) { /* compiler should statically compile this case if nbits == 1 */ + WRITEBIT(writer, value); + } else { + /* TODO: increase output size only once here rather than in each WRITEBIT */ + size_t i; + for(i = 0; i != nbits; ++i) { + WRITEBIT(writer, (unsigned char)((value >> i) & 1)); + } + } +} + +/* This one is to use for adding huffman symbol, the value bits are written MSB first */ +static void writeBitsReversed(LodePNGBitWriter* writer, unsigned value, size_t nbits) { + size_t i; + for(i = 0; i != nbits; ++i) { + /* TODO: increase output size only once here rather than in each WRITEBIT */ + WRITEBIT(writer, (unsigned char)((value >> (nbits - 1u - i)) & 1u)); + } +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_DECODER + +typedef struct { + const unsigned char* data; + size_t size; /*size of data in bytes*/ + size_t bitsize; /*size of data in bits, end of valid bp values, should be 8*size*/ + size_t bp; + unsigned buffer; /*buffer for reading bits. NOTE: 'unsigned' must support at least 32 bits*/ +} LodePNGBitReader; + +/* data size argument is in bytes. Returns error if size too large causing overflow */ +static unsigned LodePNGBitReader_init(LodePNGBitReader* reader, const unsigned char* data, size_t size) { + size_t temp; + reader->data = data; + reader->size = size; + /* size in bits, return error if overflow (if size_t is 32 bit this supports up to 500MB) */ + if(lodepng_mulofl(size, 8u, &reader->bitsize)) return 105; + /*ensure incremented bp can be compared to bitsize without overflow even when it would be incremented 32 too much and + trying to ensure 32 more bits*/ + if(lodepng_addofl(reader->bitsize, 64u, &temp)) return 105; + reader->bp = 0; + reader->buffer = 0; + return 0; /*ok*/ +} + +/* +ensureBits functions: +Ensures the reader can at least read nbits bits in one or more readBits calls, +safely even if not enough bits are available. +The nbits parameter is unused but is given for documentation purposes, error +checking for amount of bits must be done beforehand. +*/ + +/*See ensureBits documentation above. This one ensures up to 9 bits */ +static LODEPNG_INLINE void ensureBits9(LodePNGBitReader* reader, size_t nbits) { + size_t start = reader->bp >> 3u; + size_t size = reader->size; + if(start + 1u < size) { + reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u); + reader->buffer >>= (reader->bp & 7u); + } else { + reader->buffer = 0; + if(start + 0u < size) reader->buffer = reader->data[start + 0]; + reader->buffer >>= (reader->bp & 7u); + } + (void)nbits; +} + +/*See ensureBits documentation above. This one ensures up to 17 bits */ +static LODEPNG_INLINE void ensureBits17(LodePNGBitReader* reader, size_t nbits) { + size_t start = reader->bp >> 3u; + size_t size = reader->size; + if(start + 2u < size) { + reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u) | + ((unsigned)reader->data[start + 2] << 16u); + reader->buffer >>= (reader->bp & 7u); + } else { + reader->buffer = 0; + if(start + 0u < size) reader->buffer |= reader->data[start + 0]; + if(start + 1u < size) reader->buffer |= ((unsigned)reader->data[start + 1] << 8u); + reader->buffer >>= (reader->bp & 7u); + } + (void)nbits; +} + +/*See ensureBits documentation above. This one ensures up to 25 bits */ +static LODEPNG_INLINE void ensureBits25(LodePNGBitReader* reader, size_t nbits) { + size_t start = reader->bp >> 3u; + size_t size = reader->size; + if(start + 3u < size) { + reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u) | + ((unsigned)reader->data[start + 2] << 16u) | ((unsigned)reader->data[start + 3] << 24u); + reader->buffer >>= (reader->bp & 7u); + } else { + reader->buffer = 0; + if(start + 0u < size) reader->buffer |= reader->data[start + 0]; + if(start + 1u < size) reader->buffer |= ((unsigned)reader->data[start + 1] << 8u); + if(start + 2u < size) reader->buffer |= ((unsigned)reader->data[start + 2] << 16u); + reader->buffer >>= (reader->bp & 7u); + } + (void)nbits; +} + +/*See ensureBits documentation above. This one ensures up to 32 bits */ +static LODEPNG_INLINE void ensureBits32(LodePNGBitReader* reader, size_t nbits) { + size_t start = reader->bp >> 3u; + size_t size = reader->size; + if(start + 4u < size) { + reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u) | + ((unsigned)reader->data[start + 2] << 16u) | ((unsigned)reader->data[start + 3] << 24u); + reader->buffer >>= (reader->bp & 7u); + reader->buffer |= (((unsigned)reader->data[start + 4] << 24u) << (8u - (reader->bp & 7u))); + } else { + reader->buffer = 0; + if(start + 0u < size) reader->buffer |= reader->data[start + 0]; + if(start + 1u < size) reader->buffer |= ((unsigned)reader->data[start + 1] << 8u); + if(start + 2u < size) reader->buffer |= ((unsigned)reader->data[start + 2] << 16u); + if(start + 3u < size) reader->buffer |= ((unsigned)reader->data[start + 3] << 24u); + reader->buffer >>= (reader->bp & 7u); + } + (void)nbits; +} + +/* Get bits without advancing the bit pointer. Must have enough bits available with ensureBits. Max nbits is 31. */ +static LODEPNG_INLINE unsigned peekBits(LodePNGBitReader* reader, size_t nbits) { + /* The shift allows nbits to be only up to 31. */ + return reader->buffer & ((1u << nbits) - 1u); +} + +/* Must have enough bits available with ensureBits */ +static LODEPNG_INLINE void advanceBits(LodePNGBitReader* reader, size_t nbits) { + reader->buffer >>= nbits; + reader->bp += nbits; +} + +/* Must have enough bits available with ensureBits */ +static LODEPNG_INLINE unsigned readBits(LodePNGBitReader* reader, size_t nbits) { + unsigned result = peekBits(reader, nbits); + advanceBits(reader, nbits); + return result; +} +#endif /*LODEPNG_COMPILE_DECODER*/ + +static unsigned reverseBits(unsigned bits, unsigned num) { + /*TODO: implement faster lookup table based version when needed*/ + unsigned i, result = 0; + for(i = 0; i < num; i++) result |= ((bits >> (num - i - 1u)) & 1u) << i; + return result; +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Deflate - Huffman / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#define FIRST_LENGTH_CODE_INDEX 257 +#define LAST_LENGTH_CODE_INDEX 285 +/*256 literals, the end code, some length codes, and 2 unused codes*/ +#define NUM_DEFLATE_CODE_SYMBOLS 288 +/*the distance codes have their own symbols, 30 used, 2 unused*/ +#define NUM_DISTANCE_SYMBOLS 32 +/*the code length codes. 0-15: code lengths, 16: copy previous 3-6 times, 17: 3-10 zeros, 18: 11-138 zeros*/ +#define NUM_CODE_LENGTH_CODES 19 + +/*the base lengths represented by codes 257-285*/ +static const unsigned LENGTHBASE[29] + = {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, + 67, 83, 99, 115, 131, 163, 195, 227, 258}; + +/*the extra bits used by codes 257-285 (added to base length)*/ +static const unsigned LENGTHEXTRA[29] + = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + 4, 4, 4, 4, 5, 5, 5, 5, 0}; + +/*the base backwards distances (the bits of distance codes appear after length codes and use their own huffman tree)*/ +static const unsigned DISTANCEBASE[30] + = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, + 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577}; + +/*the extra bits of backwards distances (added to base)*/ +static const unsigned DISTANCEEXTRA[30] + = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; + +/*the order in which "code length alphabet code lengths" are stored as specified by deflate, out of this the huffman +tree of the dynamic huffman tree lengths is generated*/ +static const unsigned CLCL_ORDER[NUM_CODE_LENGTH_CODES] + = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +/* ////////////////////////////////////////////////////////////////////////// */ + +/* +Huffman tree struct, containing multiple representations of the tree +*/ +typedef struct HuffmanTree { + unsigned* codes; /*the huffman codes (bit patterns representing the symbols)*/ + unsigned* lengths; /*the lengths of the huffman codes*/ + unsigned maxbitlen; /*maximum number of bits a single code can get*/ + unsigned numcodes; /*number of symbols in the alphabet = number of codes*/ + /* for reading only */ + unsigned char* table_len; /*length of symbol from lookup table, or max length if secondary lookup needed*/ + unsigned short* table_value; /*value of symbol from lookup table, or pointer to secondary table if needed*/ +} HuffmanTree; + +static void HuffmanTree_init(HuffmanTree* tree) { + tree->codes = 0; + tree->lengths = 0; + tree->table_len = 0; + tree->table_value = 0; +} + +static void HuffmanTree_cleanup(HuffmanTree* tree) { + lodepng_free(tree->codes); + lodepng_free(tree->lengths); + lodepng_free(tree->table_len); + lodepng_free(tree->table_value); +} + +/* amount of bits for first huffman table lookup (aka root bits), see HuffmanTree_makeTable and huffmanDecodeSymbol.*/ +/* values 8u and 9u work the fastest */ +#define FIRSTBITS 9u + +/* a symbol value too big to represent any valid symbol, to indicate reading disallowed huffman bits combination, +which is possible in case of only 0 or 1 present symbols. */ +#define INVALIDSYMBOL 65535u + +/* make table for huffman decoding */ +static unsigned HuffmanTree_makeTable(HuffmanTree* tree) { + static const unsigned headsize = 1u << FIRSTBITS; /*size of the first table*/ + static const unsigned mask = (1u << FIRSTBITS) /*headsize*/ - 1u; + size_t i, numpresent, pointer, size; /*total table size*/ + unsigned* maxlens = (unsigned*)lodepng_malloc(headsize * sizeof(unsigned)); + if(!maxlens) return 83; /*alloc fail*/ + + /* compute maxlens: max total bit length of symbols sharing prefix in the first table*/ + lodepng_memset(maxlens, 0, headsize * sizeof(*maxlens)); + for(i = 0; i < tree->numcodes; i++) { + unsigned symbol = tree->codes[i]; + unsigned l = tree->lengths[i]; + unsigned index; + if(l <= FIRSTBITS) continue; /*symbols that fit in first table don't increase secondary table size*/ + /*get the FIRSTBITS MSBs, the MSBs of the symbol are encoded first. See later comment about the reversing*/ + index = reverseBits(symbol >> (l - FIRSTBITS), FIRSTBITS); + maxlens[index] = LODEPNG_MAX(maxlens[index], l); + } + /* compute total table size: size of first table plus all secondary tables for symbols longer than FIRSTBITS */ + size = headsize; + for(i = 0; i < headsize; ++i) { + unsigned l = maxlens[i]; + if(l > FIRSTBITS) size += (((size_t)1) << (l - FIRSTBITS)); + } + tree->table_len = (unsigned char*)lodepng_malloc(size * sizeof(*tree->table_len)); + tree->table_value = (unsigned short*)lodepng_malloc(size * sizeof(*tree->table_value)); + if(!tree->table_len || !tree->table_value) { + lodepng_free(maxlens); + /* freeing tree->table values is done at a higher scope */ + return 83; /*alloc fail*/ + } + /*initialize with an invalid length to indicate unused entries*/ + for(i = 0; i < size; ++i) tree->table_len[i] = 16; + + /*fill in the first table for long symbols: max prefix size and pointer to secondary tables*/ + pointer = headsize; + for(i = 0; i < headsize; ++i) { + unsigned l = maxlens[i]; + if(l <= FIRSTBITS) continue; + tree->table_len[i] = l; + tree->table_value[i] = (unsigned short)pointer; + pointer += (((size_t)1) << (l - FIRSTBITS)); + } + lodepng_free(maxlens); + + /*fill in the first table for short symbols, or secondary table for long symbols*/ + numpresent = 0; + for(i = 0; i < tree->numcodes; ++i) { + unsigned l = tree->lengths[i]; + unsigned symbol, reverse; + if(l == 0) continue; + symbol = tree->codes[i]; /*the huffman bit pattern. i itself is the value.*/ + /*reverse bits, because the huffman bits are given in MSB first order but the bit reader reads LSB first*/ + reverse = reverseBits(symbol, l); + numpresent++; + + if(l <= FIRSTBITS) { + /*short symbol, fully in first table, replicated num times if l < FIRSTBITS*/ + unsigned num = 1u << (FIRSTBITS - l); + unsigned j; + for(j = 0; j < num; ++j) { + /*bit reader will read the l bits of symbol first, the remaining FIRSTBITS - l bits go to the MSB's*/ + unsigned index = reverse | (j << l); + if(tree->table_len[index] != 16) return 55; /*invalid tree: long symbol shares prefix with short symbol*/ + tree->table_len[index] = l; + tree->table_value[index] = (unsigned short)i; + } + } else { + /*long symbol, shares prefix with other long symbols in first lookup table, needs second lookup*/ + /*the FIRSTBITS MSBs of the symbol are the first table index*/ + unsigned index = reverse & mask; + unsigned maxlen = tree->table_len[index]; + /*log2 of secondary table length, should be >= l - FIRSTBITS*/ + unsigned tablelen = maxlen - FIRSTBITS; + unsigned start = tree->table_value[index]; /*starting index in secondary table*/ + unsigned num = 1u << (tablelen - (l - FIRSTBITS)); /*amount of entries of this symbol in secondary table*/ + unsigned j; + if(maxlen < l) return 55; /*invalid tree: long symbol shares prefix with short symbol*/ + for(j = 0; j < num; ++j) { + unsigned reverse2 = reverse >> FIRSTBITS; /* l - FIRSTBITS bits */ + unsigned index2 = start + (reverse2 | (j << (l - FIRSTBITS))); + tree->table_len[index2] = l; + tree->table_value[index2] = (unsigned short)i; + } + } + } + + if(numpresent < 2) { + /* In case of exactly 1 symbol, in theory the huffman symbol needs 0 bits, + but deflate uses 1 bit instead. In case of 0 symbols, no symbols can + appear at all, but such huffman tree could still exist (e.g. if distance + codes are never used). In both cases, not all symbols of the table will be + filled in. Fill them in with an invalid symbol value so returning them from + huffmanDecodeSymbol will cause error. */ + for(i = 0; i < size; ++i) { + if(tree->table_len[i] == 16) { + /* As length, use a value smaller than FIRSTBITS for the head table, + and a value larger than FIRSTBITS for the secondary table, to ensure + valid behavior for advanceBits when reading this symbol. */ + tree->table_len[i] = (i < headsize) ? 1 : (FIRSTBITS + 1); + tree->table_value[i] = INVALIDSYMBOL; + } + } + } else { + /* A good huffman tree has N * 2 - 1 nodes, of which N - 1 are internal nodes. + If that is not the case (due to too long length codes), the table will not + have been fully used, and this is an error (not all bit combinations can be + decoded): an oversubscribed huffman tree, indicated by error 55. */ + for(i = 0; i < size; ++i) { + if(tree->table_len[i] == 16) return 55; + } + } + + return 0; +} + +/* +Second step for the ...makeFromLengths and ...makeFromFrequencies functions. +numcodes, lengths and maxbitlen must already be filled in correctly. return +value is error. +*/ +static unsigned HuffmanTree_makeFromLengths2(HuffmanTree* tree) { + unsigned* blcount; + unsigned* nextcode; + unsigned error = 0; + unsigned bits, n; + + tree->codes = (unsigned*)lodepng_malloc(tree->numcodes * sizeof(unsigned)); + blcount = (unsigned*)lodepng_malloc((tree->maxbitlen + 1) * sizeof(unsigned)); + nextcode = (unsigned*)lodepng_malloc((tree->maxbitlen + 1) * sizeof(unsigned)); + if(!tree->codes || !blcount || !nextcode) error = 83; /*alloc fail*/ + + if(!error) { + for(n = 0; n != tree->maxbitlen + 1; n++) blcount[n] = nextcode[n] = 0; + /*step 1: count number of instances of each code length*/ + for(bits = 0; bits != tree->numcodes; ++bits) ++blcount[tree->lengths[bits]]; + /*step 2: generate the nextcode values*/ + for(bits = 1; bits <= tree->maxbitlen; ++bits) { + nextcode[bits] = (nextcode[bits - 1] + blcount[bits - 1]) << 1u; + } + /*step 3: generate all the codes*/ + for(n = 0; n != tree->numcodes; ++n) { + if(tree->lengths[n] != 0) { + tree->codes[n] = nextcode[tree->lengths[n]]++; + /*remove superfluous bits from the code*/ + tree->codes[n] &= ((1u << tree->lengths[n]) - 1u); + } + } + } + + lodepng_free(blcount); + lodepng_free(nextcode); + + if(!error) error = HuffmanTree_makeTable(tree); + return error; +} + +/* +given the code lengths (as stored in the PNG file), generate the tree as defined +by Deflate. maxbitlen is the maximum bits that a code in the tree can have. +return value is error. +*/ +static unsigned HuffmanTree_makeFromLengths(HuffmanTree* tree, const unsigned* bitlen, + size_t numcodes, unsigned maxbitlen) { + unsigned i; + tree->lengths = (unsigned*)lodepng_malloc(numcodes * sizeof(unsigned)); + if(!tree->lengths) return 83; /*alloc fail*/ + for(i = 0; i != numcodes; ++i) tree->lengths[i] = bitlen[i]; + tree->numcodes = (unsigned)numcodes; /*number of symbols*/ + tree->maxbitlen = maxbitlen; + return HuffmanTree_makeFromLengths2(tree); +} + +#ifdef LODEPNG_COMPILE_ENCODER + +/*BPM: Boundary Package Merge, see "A Fast and Space-Economical Algorithm for Length-Limited Coding", +Jyrki Katajainen, Alistair Moffat, Andrew Turpin, 1995.*/ + +/*chain node for boundary package merge*/ +typedef struct BPMNode { + int weight; /*the sum of all weights in this chain*/ + unsigned index; /*index of this leaf node (called "count" in the paper)*/ + struct BPMNode* tail; /*the next nodes in this chain (null if last)*/ + int in_use; +} BPMNode; + +/*lists of chains*/ +typedef struct BPMLists { + /*memory pool*/ + unsigned memsize; + BPMNode* memory; + unsigned numfree; + unsigned nextfree; + BPMNode** freelist; + /*two heads of lookahead chains per list*/ + unsigned listsize; + BPMNode** chains0; + BPMNode** chains1; +} BPMLists; + +/*creates a new chain node with the given parameters, from the memory in the lists */ +static BPMNode* bpmnode_create(BPMLists* lists, int weight, unsigned index, BPMNode* tail) { + unsigned i; + BPMNode* result; + + /*memory full, so garbage collect*/ + if(lists->nextfree >= lists->numfree) { + /*mark only those that are in use*/ + for(i = 0; i != lists->memsize; ++i) lists->memory[i].in_use = 0; + for(i = 0; i != lists->listsize; ++i) { + BPMNode* node; + for(node = lists->chains0[i]; node != 0; node = node->tail) node->in_use = 1; + for(node = lists->chains1[i]; node != 0; node = node->tail) node->in_use = 1; + } + /*collect those that are free*/ + lists->numfree = 0; + for(i = 0; i != lists->memsize; ++i) { + if(!lists->memory[i].in_use) lists->freelist[lists->numfree++] = &lists->memory[i]; + } + lists->nextfree = 0; + } + + result = lists->freelist[lists->nextfree++]; + result->weight = weight; + result->index = index; + result->tail = tail; + return result; +} + +/*sort the leaves with stable mergesort*/ +static void bpmnode_sort(BPMNode* leaves, size_t num) { + BPMNode* mem = (BPMNode*)lodepng_malloc(sizeof(*leaves) * num); + size_t width, counter = 0; + for(width = 1; width < num; width *= 2) { + BPMNode* a = (counter & 1) ? mem : leaves; + BPMNode* b = (counter & 1) ? leaves : mem; + size_t p; + for(p = 0; p < num; p += 2 * width) { + size_t q = (p + width > num) ? num : (p + width); + size_t r = (p + 2 * width > num) ? num : (p + 2 * width); + size_t i = p, j = q, k; + for(k = p; k < r; k++) { + if(i < q && (j >= r || a[i].weight <= a[j].weight)) b[k] = a[i++]; + else b[k] = a[j++]; + } + } + counter++; + } + if(counter & 1) lodepng_memcpy(leaves, mem, sizeof(*leaves) * num); + lodepng_free(mem); +} + +/*Boundary Package Merge step, numpresent is the amount of leaves, and c is the current chain.*/ +static void boundaryPM(BPMLists* lists, BPMNode* leaves, size_t numpresent, int c, int num) { + unsigned lastindex = lists->chains1[c]->index; + + if(c == 0) { + if(lastindex >= numpresent) return; + lists->chains0[c] = lists->chains1[c]; + lists->chains1[c] = bpmnode_create(lists, leaves[lastindex].weight, lastindex + 1, 0); + } else { + /*sum of the weights of the head nodes of the previous lookahead chains.*/ + int sum = lists->chains0[c - 1]->weight + lists->chains1[c - 1]->weight; + lists->chains0[c] = lists->chains1[c]; + if(lastindex < numpresent && sum > leaves[lastindex].weight) { + lists->chains1[c] = bpmnode_create(lists, leaves[lastindex].weight, lastindex + 1, lists->chains1[c]->tail); + return; + } + lists->chains1[c] = bpmnode_create(lists, sum, lastindex, lists->chains1[c - 1]); + /*in the end we are only interested in the chain of the last list, so no + need to recurse if we're at the last one (this gives measurable speedup)*/ + if(num + 1 < (int)(2 * numpresent - 2)) { + boundaryPM(lists, leaves, numpresent, c - 1, num); + boundaryPM(lists, leaves, numpresent, c - 1, num); + } + } +} + +unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies, + size_t numcodes, unsigned maxbitlen) { + unsigned error = 0; + unsigned i; + size_t numpresent = 0; /*number of symbols with non-zero frequency*/ + BPMNode* leaves; /*the symbols, only those with > 0 frequency*/ + + if(numcodes == 0) return 80; /*error: a tree of 0 symbols is not supposed to be made*/ + if((1u << maxbitlen) < (unsigned)numcodes) return 80; /*error: represent all symbols*/ + + leaves = (BPMNode*)lodepng_malloc(numcodes * sizeof(*leaves)); + if(!leaves) return 83; /*alloc fail*/ + + for(i = 0; i != numcodes; ++i) { + if(frequencies[i] > 0) { + leaves[numpresent].weight = (int)frequencies[i]; + leaves[numpresent].index = i; + ++numpresent; + } + } + + lodepng_memset(lengths, 0, numcodes * sizeof(*lengths)); + + /*ensure at least two present symbols. There should be at least one symbol + according to RFC 1951 section 3.2.7. Some decoders incorrectly require two. To + make these work as well ensure there are at least two symbols. The + Package-Merge code below also doesn't work correctly if there's only one + symbol, it'd give it the theoretical 0 bits but in practice zlib wants 1 bit*/ + if(numpresent == 0) { + lengths[0] = lengths[1] = 1; /*note that for RFC 1951 section 3.2.7, only lengths[0] = 1 is needed*/ + } else if(numpresent == 1) { + lengths[leaves[0].index] = 1; + lengths[leaves[0].index == 0 ? 1 : 0] = 1; + } else { + BPMLists lists; + BPMNode* node; + + bpmnode_sort(leaves, numpresent); + + lists.listsize = maxbitlen; + lists.memsize = 2 * maxbitlen * (maxbitlen + 1); + lists.nextfree = 0; + lists.numfree = lists.memsize; + lists.memory = (BPMNode*)lodepng_malloc(lists.memsize * sizeof(*lists.memory)); + lists.freelist = (BPMNode**)lodepng_malloc(lists.memsize * sizeof(BPMNode*)); + lists.chains0 = (BPMNode**)lodepng_malloc(lists.listsize * sizeof(BPMNode*)); + lists.chains1 = (BPMNode**)lodepng_malloc(lists.listsize * sizeof(BPMNode*)); + if(!lists.memory || !lists.freelist || !lists.chains0 || !lists.chains1) error = 83; /*alloc fail*/ + + if(!error) { + for(i = 0; i != lists.memsize; ++i) lists.freelist[i] = &lists.memory[i]; + + bpmnode_create(&lists, leaves[0].weight, 1, 0); + bpmnode_create(&lists, leaves[1].weight, 2, 0); + + for(i = 0; i != lists.listsize; ++i) { + lists.chains0[i] = &lists.memory[0]; + lists.chains1[i] = &lists.memory[1]; + } + + /*each boundaryPM call adds one chain to the last list, and we need 2 * numpresent - 2 chains.*/ + for(i = 2; i != 2 * numpresent - 2; ++i) boundaryPM(&lists, leaves, numpresent, (int)maxbitlen - 1, (int)i); + + for(node = lists.chains1[maxbitlen - 1]; node; node = node->tail) { + for(i = 0; i != node->index; ++i) ++lengths[leaves[i].index]; + } + } + + lodepng_free(lists.memory); + lodepng_free(lists.freelist); + lodepng_free(lists.chains0); + lodepng_free(lists.chains1); + } + + lodepng_free(leaves); + return error; +} + +/*Create the Huffman tree given the symbol frequencies*/ +static unsigned HuffmanTree_makeFromFrequencies(HuffmanTree* tree, const unsigned* frequencies, + size_t mincodes, size_t numcodes, unsigned maxbitlen) { + unsigned error = 0; + while(!frequencies[numcodes - 1] && numcodes > mincodes) --numcodes; /*trim zeroes*/ + tree->lengths = (unsigned*)lodepng_malloc(numcodes * sizeof(unsigned)); + if(!tree->lengths) return 83; /*alloc fail*/ + tree->maxbitlen = maxbitlen; + tree->numcodes = (unsigned)numcodes; /*number of symbols*/ + + error = lodepng_huffman_code_lengths(tree->lengths, frequencies, numcodes, maxbitlen); + if(!error) error = HuffmanTree_makeFromLengths2(tree); + return error; +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/*get the literal and length code tree of a deflated block with fixed tree, as per the deflate specification*/ +static unsigned generateFixedLitLenTree(HuffmanTree* tree) { + unsigned i, error = 0; + unsigned* bitlen = (unsigned*)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned)); + if(!bitlen) return 83; /*alloc fail*/ + + /*288 possible codes: 0-255=literals, 256=endcode, 257-285=lengthcodes, 286-287=unused*/ + for(i = 0; i <= 143; ++i) bitlen[i] = 8; + for(i = 144; i <= 255; ++i) bitlen[i] = 9; + for(i = 256; i <= 279; ++i) bitlen[i] = 7; + for(i = 280; i <= 287; ++i) bitlen[i] = 8; + + error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DEFLATE_CODE_SYMBOLS, 15); + + lodepng_free(bitlen); + return error; +} + +/*get the distance code tree of a deflated block with fixed tree, as specified in the deflate specification*/ +static unsigned generateFixedDistanceTree(HuffmanTree* tree) { + unsigned i, error = 0; + unsigned* bitlen = (unsigned*)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned)); + if(!bitlen) return 83; /*alloc fail*/ + + /*there are 32 distance codes, but 30-31 are unused*/ + for(i = 0; i != NUM_DISTANCE_SYMBOLS; ++i) bitlen[i] = 5; + error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DISTANCE_SYMBOLS, 15); + + lodepng_free(bitlen); + return error; +} + +#ifdef LODEPNG_COMPILE_DECODER + +/* +returns the code. The bit reader must already have been ensured at least 15 bits +*/ +static unsigned huffmanDecodeSymbol(LodePNGBitReader* reader, const HuffmanTree* codetree) { + unsigned short code = peekBits(reader, FIRSTBITS); + unsigned short l = codetree->table_len[code]; + unsigned short value = codetree->table_value[code]; + if(l <= FIRSTBITS) { + advanceBits(reader, l); + return value; + } else { + advanceBits(reader, FIRSTBITS); + value += peekBits(reader, l - FIRSTBITS); + advanceBits(reader, codetree->table_len[value] - FIRSTBITS); + return codetree->table_value[value]; + } +} +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_DECODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Inflator (Decompressor) / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*get the tree of a deflated block with fixed tree, as specified in the deflate specification +Returns error code.*/ +static unsigned getTreeInflateFixed(HuffmanTree* tree_ll, HuffmanTree* tree_d) { + unsigned error = generateFixedLitLenTree(tree_ll); + if(error) return error; + return generateFixedDistanceTree(tree_d); +} + +/*get the tree of a deflated block with dynamic tree, the tree itself is also Huffman compressed with a known tree*/ +static unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_d, + LodePNGBitReader* reader) { + /*make sure that length values that aren't filled in will be 0, or a wrong tree will be generated*/ + unsigned error = 0; + unsigned n, HLIT, HDIST, HCLEN, i; + + /*see comments in deflateDynamic for explanation of the context and these variables, it is analogous*/ + unsigned* bitlen_ll = 0; /*lit,len code lengths*/ + unsigned* bitlen_d = 0; /*dist code lengths*/ + /*code length code lengths ("clcl"), the bit lengths of the huffman tree used to compress bitlen_ll and bitlen_d*/ + unsigned* bitlen_cl = 0; + HuffmanTree tree_cl; /*the code tree for code length codes (the huffman tree for compressed huffman trees)*/ + + if(reader->bitsize - reader->bp < 14) return 49; /*error: the bit pointer is or will go past the memory*/ + ensureBits17(reader, 14); + + /*number of literal/length codes + 257. Unlike the spec, the value 257 is added to it here already*/ + HLIT = readBits(reader, 5) + 257; + /*number of distance codes. Unlike the spec, the value 1 is added to it here already*/ + HDIST = readBits(reader, 5) + 1; + /*number of code length codes. Unlike the spec, the value 4 is added to it here already*/ + HCLEN = readBits(reader, 4) + 4; + + bitlen_cl = (unsigned*)lodepng_malloc(NUM_CODE_LENGTH_CODES * sizeof(unsigned)); + if(!bitlen_cl) return 83 /*alloc fail*/; + + HuffmanTree_init(&tree_cl); + + while(!error) { + /*read the code length codes out of 3 * (amount of code length codes) bits*/ + if(lodepng_gtofl(reader->bp, HCLEN * 3, reader->bitsize)) { + ERROR_BREAK(50); /*error: the bit pointer is or will go past the memory*/ + } + for(i = 0; i != HCLEN; ++i) { + ensureBits9(reader, 3); /*out of bounds already checked above */ + bitlen_cl[CLCL_ORDER[i]] = readBits(reader, 3); + } + for(i = HCLEN; i != NUM_CODE_LENGTH_CODES; ++i) { + bitlen_cl[CLCL_ORDER[i]] = 0; + } + + error = HuffmanTree_makeFromLengths(&tree_cl, bitlen_cl, NUM_CODE_LENGTH_CODES, 7); + if(error) break; + + /*now we can use this tree to read the lengths for the tree that this function will return*/ + bitlen_ll = (unsigned*)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned)); + bitlen_d = (unsigned*)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned)); + if(!bitlen_ll || !bitlen_d) ERROR_BREAK(83 /*alloc fail*/); + lodepng_memset(bitlen_ll, 0, NUM_DEFLATE_CODE_SYMBOLS * sizeof(*bitlen_ll)); + lodepng_memset(bitlen_d, 0, NUM_DISTANCE_SYMBOLS * sizeof(*bitlen_d)); + + /*i is the current symbol we're reading in the part that contains the code lengths of lit/len and dist codes*/ + i = 0; + while(i < HLIT + HDIST) { + unsigned code; + ensureBits25(reader, 22); /* up to 15 bits for huffman code, up to 7 extra bits below*/ + code = huffmanDecodeSymbol(reader, &tree_cl); + if(code <= 15) /*a length code*/ { + if(i < HLIT) bitlen_ll[i] = code; + else bitlen_d[i - HLIT] = code; + ++i; + } else if(code == 16) /*repeat previous*/ { + unsigned replength = 3; /*read in the 2 bits that indicate repeat length (3-6)*/ + unsigned value; /*set value to the previous code*/ + + if(i == 0) ERROR_BREAK(54); /*can't repeat previous if i is 0*/ + + replength += readBits(reader, 2); + + if(i < HLIT + 1) value = bitlen_ll[i - 1]; + else value = bitlen_d[i - HLIT - 1]; + /*repeat this value in the next lengths*/ + for(n = 0; n < replength; ++n) { + if(i >= HLIT + HDIST) ERROR_BREAK(13); /*error: i is larger than the amount of codes*/ + if(i < HLIT) bitlen_ll[i] = value; + else bitlen_d[i - HLIT] = value; + ++i; + } + } else if(code == 17) /*repeat "0" 3-10 times*/ { + unsigned replength = 3; /*read in the bits that indicate repeat length*/ + replength += readBits(reader, 3); + + /*repeat this value in the next lengths*/ + for(n = 0; n < replength; ++n) { + if(i >= HLIT + HDIST) ERROR_BREAK(14); /*error: i is larger than the amount of codes*/ + + if(i < HLIT) bitlen_ll[i] = 0; + else bitlen_d[i - HLIT] = 0; + ++i; + } + } else if(code == 18) /*repeat "0" 11-138 times*/ { + unsigned replength = 11; /*read in the bits that indicate repeat length*/ + replength += readBits(reader, 7); + + /*repeat this value in the next lengths*/ + for(n = 0; n < replength; ++n) { + if(i >= HLIT + HDIST) ERROR_BREAK(15); /*error: i is larger than the amount of codes*/ + + if(i < HLIT) bitlen_ll[i] = 0; + else bitlen_d[i - HLIT] = 0; + ++i; + } + } else /*if(code == INVALIDSYMBOL)*/ { + ERROR_BREAK(16); /*error: tried to read disallowed huffman symbol*/ + } + /*check if any of the ensureBits above went out of bounds*/ + if(reader->bp > reader->bitsize) { + /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol + (10=no endcode, 11=wrong jump outside of tree)*/ + /* TODO: revise error codes 10,11,50: the above comment is no longer valid */ + ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ + } + } + if(error) break; + + if(bitlen_ll[256] == 0) ERROR_BREAK(64); /*the length of the end code 256 must be larger than 0*/ + + /*now we've finally got HLIT and HDIST, so generate the code trees, and the function is done*/ + error = HuffmanTree_makeFromLengths(tree_ll, bitlen_ll, NUM_DEFLATE_CODE_SYMBOLS, 15); + if(error) break; + error = HuffmanTree_makeFromLengths(tree_d, bitlen_d, NUM_DISTANCE_SYMBOLS, 15); + + break; /*end of error-while*/ + } + + lodepng_free(bitlen_cl); + lodepng_free(bitlen_ll); + lodepng_free(bitlen_d); + HuffmanTree_cleanup(&tree_cl); + + return error; +} + +/*inflate a block with dynamic of fixed Huffman tree. btype must be 1 or 2.*/ +static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader, + unsigned btype, size_t max_output_size) { + unsigned error = 0; + HuffmanTree tree_ll; /*the huffman tree for literal and length codes*/ + HuffmanTree tree_d; /*the huffman tree for distance codes*/ + const size_t reserved_size = 260; /* must be at least 258 for max length, and a few extra for adding a few extra literals */ + int done = 0; + + if(!ucvector_reserve(out, out->size + reserved_size)) return 83; /*alloc fail*/ + + HuffmanTree_init(&tree_ll); + HuffmanTree_init(&tree_d); + + if(btype == 1) error = getTreeInflateFixed(&tree_ll, &tree_d); + else /*if(btype == 2)*/ error = getTreeInflateDynamic(&tree_ll, &tree_d, reader); + + + while(!error && !done) /*decode all symbols until end reached, breaks at end code*/ { + /*code_ll is literal, length or end code*/ + unsigned code_ll; + /* ensure enough bits for 2 huffman code reads (15 bits each): if the first is a literal, a second literal is read at once. This + appears to be slightly faster, than ensuring 20 bits here for 1 huffman symbol and the potential 5 extra bits for the length symbol.*/ + ensureBits32(reader, 30); + code_ll = huffmanDecodeSymbol(reader, &tree_ll); + if(code_ll <= 255) { + /*slightly faster code path if multiple literals in a row*/ + out->data[out->size++] = (unsigned char)code_ll; + code_ll = huffmanDecodeSymbol(reader, &tree_ll); + } + if(code_ll <= 255) /*literal symbol*/ { + out->data[out->size++] = (unsigned char)code_ll; + } else if(code_ll >= FIRST_LENGTH_CODE_INDEX && code_ll <= LAST_LENGTH_CODE_INDEX) /*length code*/ { + unsigned code_d, distance; + unsigned numextrabits_l, numextrabits_d; /*extra bits for length and distance*/ + size_t start, backward, length; + + /*part 1: get length base*/ + length = LENGTHBASE[code_ll - FIRST_LENGTH_CODE_INDEX]; + + /*part 2: get extra bits and add the value of that to length*/ + numextrabits_l = LENGTHEXTRA[code_ll - FIRST_LENGTH_CODE_INDEX]; + if(numextrabits_l != 0) { + /* bits already ensured above */ + ensureBits25(reader, 5); + length += readBits(reader, numextrabits_l); + } + + /*part 3: get distance code*/ + ensureBits32(reader, 28); /* up to 15 for the huffman symbol, up to 13 for the extra bits */ + code_d = huffmanDecodeSymbol(reader, &tree_d); + if(code_d > 29) { + if(code_d <= 31) { + ERROR_BREAK(18); /*error: invalid distance code (30-31 are never used)*/ + } else /* if(code_d == INVALIDSYMBOL) */{ + ERROR_BREAK(16); /*error: tried to read disallowed huffman symbol*/ + } + } + distance = DISTANCEBASE[code_d]; + + /*part 4: get extra bits from distance*/ + numextrabits_d = DISTANCEEXTRA[code_d]; + if(numextrabits_d != 0) { + /* bits already ensured above */ + distance += readBits(reader, numextrabits_d); + } + + /*part 5: fill in all the out[n] values based on the length and dist*/ + start = out->size; + if(distance > start) ERROR_BREAK(52); /*too long backward distance*/ + backward = start - distance; + + out->size += length; + if(distance < length) { + size_t forward; + lodepng_memcpy(out->data + start, out->data + backward, distance); + start += distance; + for(forward = distance; forward < length; ++forward) { + out->data[start++] = out->data[backward++]; + } + } else { + lodepng_memcpy(out->data + start, out->data + backward, length); + } + } else if(code_ll == 256) { + done = 1; /*end code, finish the loop*/ + } else /*if(code_ll == INVALIDSYMBOL)*/ { + ERROR_BREAK(16); /*error: tried to read disallowed huffman symbol*/ + } + if(out->allocsize - out->size < reserved_size) { + if(!ucvector_reserve(out, out->size + reserved_size)) ERROR_BREAK(83); /*alloc fail*/ + } + /*check if any of the ensureBits above went out of bounds*/ + if(reader->bp > reader->bitsize) { + /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol + (10=no endcode, 11=wrong jump outside of tree)*/ + /* TODO: revise error codes 10,11,50: the above comment is no longer valid */ + ERROR_BREAK(51); /*error, bit pointer jumps past memory*/ + } + if(max_output_size && out->size > max_output_size) { + ERROR_BREAK(109); /*error, larger than max size*/ + } + } + + HuffmanTree_cleanup(&tree_ll); + HuffmanTree_cleanup(&tree_d); + + return error; +} + +static unsigned inflateNoCompression(ucvector* out, LodePNGBitReader* reader, + const LodePNGDecompressSettings* settings) { + size_t bytepos; + size_t size = reader->size; + unsigned LEN, NLEN, error = 0; + + /*go to first boundary of byte*/ + bytepos = (reader->bp + 7u) >> 3u; + + /*read LEN (2 bytes) and NLEN (2 bytes)*/ + if(bytepos + 4 >= size) return 52; /*error, bit pointer will jump past memory*/ + LEN = (unsigned)reader->data[bytepos] + ((unsigned)reader->data[bytepos + 1] << 8u); bytepos += 2; + NLEN = (unsigned)reader->data[bytepos] + ((unsigned)reader->data[bytepos + 1] << 8u); bytepos += 2; + + /*check if 16-bit NLEN is really the one's complement of LEN*/ + if(!settings->ignore_nlen && LEN + NLEN != 65535) { + return 21; /*error: NLEN is not one's complement of LEN*/ + } + + if(!ucvector_resize(out, out->size + LEN)) return 83; /*alloc fail*/ + + /*read the literal data: LEN bytes are now stored in the out buffer*/ + if(bytepos + LEN > size) return 23; /*error: reading outside of in buffer*/ + + /*out->data can be NULL (when LEN is zero), and arithmetic on NULL ptr is undefined*/ + if (LEN) { + lodepng_memcpy(out->data + out->size - LEN, reader->data + bytepos, LEN); + bytepos += LEN; + } + + reader->bp = bytepos << 3u; + + return error; +} + +static unsigned lodepng_inflatev(ucvector* out, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings) { + unsigned BFINAL = 0; + LodePNGBitReader reader; + unsigned error = LodePNGBitReader_init(&reader, in, insize); + + if(error) return error; + + while(!BFINAL) { + unsigned BTYPE; + if(reader.bitsize - reader.bp < 3) return 52; /*error, bit pointer will jump past memory*/ + ensureBits9(&reader, 3); + BFINAL = readBits(&reader, 1); + BTYPE = readBits(&reader, 2); + + if(BTYPE == 3) return 20; /*error: invalid BTYPE*/ + else if(BTYPE == 0) error = inflateNoCompression(out, &reader, settings); /*no compression*/ + else error = inflateHuffmanBlock(out, &reader, BTYPE, settings->max_output_size); /*compression, BTYPE 01 or 10*/ + if(!error && settings->max_output_size && out->size > settings->max_output_size) error = 109; + if(error) break; + } + + return error; +} + +unsigned lodepng_inflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings) { + ucvector v = ucvector_init(*out, *outsize); + unsigned error = lodepng_inflatev(&v, in, insize, settings); + *out = v.data; + *outsize = v.size; + return error; +} + +static unsigned inflatev(ucvector* out, const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings) { + if(settings->custom_inflate) { + unsigned error = settings->custom_inflate(&out->data, &out->size, in, insize, settings); + out->allocsize = out->size; + if(error) { + /*the custom inflate is allowed to have its own error codes, however, we translate it to code 110*/ + error = 110; + /*if there's a max output size, and the custom zlib returned error, then indicate that error instead*/ + if(settings->max_output_size && out->size > settings->max_output_size) error = 109; + } + return error; + } else { + return lodepng_inflatev(out, in, insize, settings); + } +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Deflator (Compressor) / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +static const unsigned MAX_SUPPORTED_DEFLATE_LENGTH = 258; + +/*search the index in the array, that has the largest value smaller than or equal to the given value, +given array must be sorted (if no value is smaller, it returns the size of the given array)*/ +static size_t searchCodeIndex(const unsigned* array, size_t array_size, size_t value) { + /*binary search (only small gain over linear). TODO: use CPU log2 instruction for getting symbols instead*/ + size_t left = 1; + size_t right = array_size - 1; + + while(left <= right) { + size_t mid = (left + right) >> 1; + if(array[mid] >= value) right = mid - 1; + else left = mid + 1; + } + if(left >= array_size || array[left] > value) left--; + return left; +} + +static void addLengthDistance(uivector* values, size_t length, size_t distance) { + /*values in encoded vector are those used by deflate: + 0-255: literal bytes + 256: end + 257-285: length/distance pair (length code, followed by extra length bits, distance code, extra distance bits) + 286-287: invalid*/ + + unsigned length_code = (unsigned)searchCodeIndex(LENGTHBASE, 29, length); + unsigned extra_length = (unsigned)(length - LENGTHBASE[length_code]); + unsigned dist_code = (unsigned)searchCodeIndex(DISTANCEBASE, 30, distance); + unsigned extra_distance = (unsigned)(distance - DISTANCEBASE[dist_code]); + + size_t pos = values->size; + /*TODO: return error when this fails (out of memory)*/ + unsigned ok = uivector_resize(values, values->size + 4); + if(ok) { + values->data[pos + 0] = length_code + FIRST_LENGTH_CODE_INDEX; + values->data[pos + 1] = extra_length; + values->data[pos + 2] = dist_code; + values->data[pos + 3] = extra_distance; + } +} + +/*3 bytes of data get encoded into two bytes. The hash cannot use more than 3 +bytes as input because 3 is the minimum match length for deflate*/ +static const unsigned HASH_NUM_VALUES = 65536; +static const unsigned HASH_BIT_MASK = 65535; /*HASH_NUM_VALUES - 1, but C90 does not like that as initializer*/ + +typedef struct Hash { + int* head; /*hash value to head circular pos - can be outdated if went around window*/ + /*circular pos to prev circular pos*/ + unsigned short* chain; + int* val; /*circular pos to hash value*/ + + /*TODO: do this not only for zeros but for any repeated byte. However for PNG + it's always going to be the zeros that dominate, so not important for PNG*/ + int* headz; /*similar to head, but for chainz*/ + unsigned short* chainz; /*those with same amount of zeros*/ + unsigned short* zeros; /*length of zeros streak, used as a second hash chain*/ +} Hash; + +static unsigned hash_init(Hash* hash, unsigned windowsize) { + unsigned i; + hash->head = (int*)lodepng_malloc(sizeof(int) * HASH_NUM_VALUES); + hash->val = (int*)lodepng_malloc(sizeof(int) * windowsize); + hash->chain = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); + + hash->zeros = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); + hash->headz = (int*)lodepng_malloc(sizeof(int) * (MAX_SUPPORTED_DEFLATE_LENGTH + 1)); + hash->chainz = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); + + if(!hash->head || !hash->chain || !hash->val || !hash->headz|| !hash->chainz || !hash->zeros) { + return 83; /*alloc fail*/ + } + + /*initialize hash table*/ + for(i = 0; i != HASH_NUM_VALUES; ++i) hash->head[i] = -1; + for(i = 0; i != windowsize; ++i) hash->val[i] = -1; + for(i = 0; i != windowsize; ++i) hash->chain[i] = i; /*same value as index indicates uninitialized*/ + + for(i = 0; i <= MAX_SUPPORTED_DEFLATE_LENGTH; ++i) hash->headz[i] = -1; + for(i = 0; i != windowsize; ++i) hash->chainz[i] = i; /*same value as index indicates uninitialized*/ + + return 0; +} + +static void hash_cleanup(Hash* hash) { + lodepng_free(hash->head); + lodepng_free(hash->val); + lodepng_free(hash->chain); + + lodepng_free(hash->zeros); + lodepng_free(hash->headz); + lodepng_free(hash->chainz); +} + + + +static unsigned getHash(const unsigned char* data, size_t size, size_t pos) { + unsigned result = 0; + if(pos + 2 < size) { + /*A simple shift and xor hash is used. Since the data of PNGs is dominated + by zeroes due to the filters, a better hash does not have a significant + effect on speed in traversing the chain, and causes more time spend on + calculating the hash.*/ + result ^= ((unsigned)data[pos + 0] << 0u); + result ^= ((unsigned)data[pos + 1] << 4u); + result ^= ((unsigned)data[pos + 2] << 8u); + } else { + size_t amount, i; + if(pos >= size) return 0; + amount = size - pos; + for(i = 0; i != amount; ++i) result ^= ((unsigned)data[pos + i] << (i * 8u)); + } + return result & HASH_BIT_MASK; +} + +static unsigned countZeros(const unsigned char* data, size_t size, size_t pos) { + const unsigned char* start = data + pos; + const unsigned char* end = start + MAX_SUPPORTED_DEFLATE_LENGTH; + if(end > data + size) end = data + size; + data = start; + while(data != end && *data == 0) ++data; + /*subtracting two addresses returned as 32-bit number (max value is MAX_SUPPORTED_DEFLATE_LENGTH)*/ + return (unsigned)(data - start); +} + +/*wpos = pos & (windowsize - 1)*/ +static void updateHashChain(Hash* hash, size_t wpos, unsigned hashval, unsigned short numzeros) { + hash->val[wpos] = (int)hashval; + if(hash->head[hashval] != -1) hash->chain[wpos] = hash->head[hashval]; + hash->head[hashval] = (int)wpos; + + hash->zeros[wpos] = numzeros; + if(hash->headz[numzeros] != -1) hash->chainz[wpos] = hash->headz[numzeros]; + hash->headz[numzeros] = (int)wpos; +} + +/* +LZ77-encode the data. Return value is error code. The input are raw bytes, the output +is in the form of unsigned integers with codes representing for example literal bytes, or +length/distance pairs. +It uses a hash table technique to let it encode faster. When doing LZ77 encoding, a +sliding window (of windowsize) is used, and all past bytes in that window can be used as +the "dictionary". A brute force search through all possible distances would be slow, and +this hash technique is one out of several ways to speed this up. +*/ +static unsigned encodeLZ77(uivector* out, Hash* hash, + const unsigned char* in, size_t inpos, size_t insize, unsigned windowsize, + unsigned minmatch, unsigned nicematch, unsigned lazymatching) { + size_t pos; + unsigned i, error = 0; + /*for large window lengths, assume the user wants no compression loss. Otherwise, max hash chain length speedup.*/ + unsigned maxchainlength = windowsize >= 8192 ? windowsize : windowsize / 8u; + unsigned maxlazymatch = windowsize >= 8192 ? MAX_SUPPORTED_DEFLATE_LENGTH : 64; + + unsigned usezeros = 1; /*not sure if setting it to false for windowsize < 8192 is better or worse*/ + unsigned numzeros = 0; + + unsigned offset; /*the offset represents the distance in LZ77 terminology*/ + unsigned length; + unsigned lazy = 0; + unsigned lazylength = 0, lazyoffset = 0; + unsigned hashval; + unsigned current_offset, current_length; + unsigned prev_offset; + const unsigned char *lastptr, *foreptr, *backptr; + unsigned hashpos; + + if(windowsize == 0 || windowsize > 32768) return 60; /*error: windowsize smaller/larger than allowed*/ + if((windowsize & (windowsize - 1)) != 0) return 90; /*error: must be power of two*/ + + if(nicematch > MAX_SUPPORTED_DEFLATE_LENGTH) nicematch = MAX_SUPPORTED_DEFLATE_LENGTH; + + for(pos = inpos; pos < insize; ++pos) { + size_t wpos = pos & (windowsize - 1); /*position for in 'circular' hash buffers*/ + unsigned chainlength = 0; + + hashval = getHash(in, insize, pos); + + if(usezeros && hashval == 0) { + if(numzeros == 0) numzeros = countZeros(in, insize, pos); + else if(pos + numzeros > insize || in[pos + numzeros - 1] != 0) --numzeros; + } else { + numzeros = 0; + } + + updateHashChain(hash, wpos, hashval, numzeros); + + /*the length and offset found for the current position*/ + length = 0; + offset = 0; + + hashpos = hash->chain[wpos]; + + lastptr = &in[insize < pos + MAX_SUPPORTED_DEFLATE_LENGTH ? insize : pos + MAX_SUPPORTED_DEFLATE_LENGTH]; + + /*search for the longest string*/ + prev_offset = 0; + for(;;) { + if(chainlength++ >= maxchainlength) break; + current_offset = (unsigned)(hashpos <= wpos ? wpos - hashpos : wpos - hashpos + windowsize); + + if(current_offset < prev_offset) break; /*stop when went completely around the circular buffer*/ + prev_offset = current_offset; + if(current_offset > 0) { + /*test the next characters*/ + foreptr = &in[pos]; + backptr = &in[pos - current_offset]; + + /*common case in PNGs is lots of zeros. Quickly skip over them as a speedup*/ + if(numzeros >= 3) { + unsigned skip = hash->zeros[hashpos]; + if(skip > numzeros) skip = numzeros; + backptr += skip; + foreptr += skip; + } + + while(foreptr != lastptr && *backptr == *foreptr) /*maximum supported length by deflate is max length*/ { + ++backptr; + ++foreptr; + } + current_length = (unsigned)(foreptr - &in[pos]); + + if(current_length > length) { + length = current_length; /*the longest length*/ + offset = current_offset; /*the offset that is related to this longest length*/ + /*jump out once a length of max length is found (speed gain). This also jumps + out if length is MAX_SUPPORTED_DEFLATE_LENGTH*/ + if(current_length >= nicematch) break; + } + } + + if(hashpos == hash->chain[hashpos]) break; + + if(numzeros >= 3 && length > numzeros) { + hashpos = hash->chainz[hashpos]; + if(hash->zeros[hashpos] != numzeros) break; + } else { + hashpos = hash->chain[hashpos]; + /*outdated hash value, happens if particular value was not encountered in whole last window*/ + if(hash->val[hashpos] != (int)hashval) break; + } + } + + if(lazymatching) { + if(!lazy && length >= 3 && length <= maxlazymatch && length < MAX_SUPPORTED_DEFLATE_LENGTH) { + lazy = 1; + lazylength = length; + lazyoffset = offset; + continue; /*try the next byte*/ + } + if(lazy) { + lazy = 0; + if(pos == 0) ERROR_BREAK(81); + if(length > lazylength + 1) { + /*push the previous character as literal*/ + if(!uivector_push_back(out, in[pos - 1])) ERROR_BREAK(83 /*alloc fail*/); + } else { + length = lazylength; + offset = lazyoffset; + hash->head[hashval] = -1; /*the same hashchain update will be done, this ensures no wrong alteration*/ + hash->headz[numzeros] = -1; /*idem*/ + --pos; + } + } + } + if(length >= 3 && offset > windowsize) ERROR_BREAK(86 /*too big (or overflown negative) offset*/); + + /*encode it as length/distance pair or literal value*/ + if(length < 3) /*only lengths of 3 or higher are supported as length/distance pair*/ { + if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/); + } else if(length < minmatch || (length == 3 && offset > 4096)) { + /*compensate for the fact that longer offsets have more extra bits, a + length of only 3 may be not worth it then*/ + if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/); + } else { + addLengthDistance(out, length, offset); + for(i = 1; i < length; ++i) { + ++pos; + wpos = pos & (windowsize - 1); + hashval = getHash(in, insize, pos); + if(usezeros && hashval == 0) { + if(numzeros == 0) numzeros = countZeros(in, insize, pos); + else if(pos + numzeros > insize || in[pos + numzeros - 1] != 0) --numzeros; + } else { + numzeros = 0; + } + updateHashChain(hash, wpos, hashval, numzeros); + } + } + } /*end of the loop through each character of input*/ + + return error; +} + +/* /////////////////////////////////////////////////////////////////////////// */ + +static unsigned deflateNoCompression(ucvector* out, const unsigned char* data, size_t datasize) { + /*non compressed deflate block data: 1 bit BFINAL,2 bits BTYPE,(5 bits): it jumps to start of next byte, + 2 bytes LEN, 2 bytes NLEN, LEN bytes literal DATA*/ + + size_t i, numdeflateblocks = (datasize + 65534u) / 65535u; + size_t datapos = 0; + for(i = 0; i != numdeflateblocks; ++i) { + unsigned BFINAL, BTYPE, LEN, NLEN; + unsigned char firstbyte; + size_t pos = out->size; + + BFINAL = (i == numdeflateblocks - 1); + BTYPE = 0; + + LEN = 65535; + if(datasize - datapos < 65535u) LEN = (unsigned)datasize - (unsigned)datapos; + NLEN = 65535 - LEN; + + if(!ucvector_resize(out, out->size + LEN + 5)) return 83; /*alloc fail*/ + + firstbyte = (unsigned char)(BFINAL + ((BTYPE & 1u) << 1u) + ((BTYPE & 2u) << 1u)); + out->data[pos + 0] = firstbyte; + out->data[pos + 1] = (unsigned char)(LEN & 255); + out->data[pos + 2] = (unsigned char)(LEN >> 8u); + out->data[pos + 3] = (unsigned char)(NLEN & 255); + out->data[pos + 4] = (unsigned char)(NLEN >> 8u); + lodepng_memcpy(out->data + pos + 5, data + datapos, LEN); + datapos += LEN; + } + + return 0; +} + +/* +write the lz77-encoded data, which has lit, len and dist codes, to compressed stream using huffman trees. +tree_ll: the tree for lit and len codes. +tree_d: the tree for distance codes. +*/ +static void writeLZ77data(LodePNGBitWriter* writer, const uivector* lz77_encoded, + const HuffmanTree* tree_ll, const HuffmanTree* tree_d) { + size_t i = 0; + for(i = 0; i != lz77_encoded->size; ++i) { + unsigned val = lz77_encoded->data[i]; + writeBitsReversed(writer, tree_ll->codes[val], tree_ll->lengths[val]); + if(val > 256) /*for a length code, 3 more things have to be added*/ { + unsigned length_index = val - FIRST_LENGTH_CODE_INDEX; + unsigned n_length_extra_bits = LENGTHEXTRA[length_index]; + unsigned length_extra_bits = lz77_encoded->data[++i]; + + unsigned distance_code = lz77_encoded->data[++i]; + + unsigned distance_index = distance_code; + unsigned n_distance_extra_bits = DISTANCEEXTRA[distance_index]; + unsigned distance_extra_bits = lz77_encoded->data[++i]; + + writeBits(writer, length_extra_bits, n_length_extra_bits); + writeBitsReversed(writer, tree_d->codes[distance_code], tree_d->lengths[distance_code]); + writeBits(writer, distance_extra_bits, n_distance_extra_bits); + } + } +} + +/*Deflate for a block of type "dynamic", that is, with freely, optimally, created huffman trees*/ +static unsigned deflateDynamic(LodePNGBitWriter* writer, Hash* hash, + const unsigned char* data, size_t datapos, size_t dataend, + const LodePNGCompressSettings* settings, unsigned final) { + unsigned error = 0; + + /* + A block is compressed as follows: The PNG data is lz77 encoded, resulting in + literal bytes and length/distance pairs. This is then huffman compressed with + two huffman trees. One huffman tree is used for the lit and len values ("ll"), + another huffman tree is used for the dist values ("d"). These two trees are + stored using their code lengths, and to compress even more these code lengths + are also run-length encoded and huffman compressed. This gives a huffman tree + of code lengths "cl". The code lengths used to describe this third tree are + the code length code lengths ("clcl"). + */ + + /*The lz77 encoded data, represented with integers since there will also be length and distance codes in it*/ + uivector lz77_encoded; + HuffmanTree tree_ll; /*tree for lit,len values*/ + HuffmanTree tree_d; /*tree for distance codes*/ + HuffmanTree tree_cl; /*tree for encoding the code lengths representing tree_ll and tree_d*/ + unsigned* frequencies_ll = 0; /*frequency of lit,len codes*/ + unsigned* frequencies_d = 0; /*frequency of dist codes*/ + unsigned* frequencies_cl = 0; /*frequency of code length codes*/ + unsigned* bitlen_lld = 0; /*lit,len,dist code lengths (int bits), literally (without repeat codes).*/ + unsigned* bitlen_lld_e = 0; /*bitlen_lld encoded with repeat codes (this is a rudimentary run length compression)*/ + size_t datasize = dataend - datapos; + + /* + If we could call "bitlen_cl" the the code length code lengths ("clcl"), that is the bit lengths of codes to represent + tree_cl in CLCL_ORDER, then due to the huffman compression of huffman tree representations ("two levels"), there are + some analogies: + bitlen_lld is to tree_cl what data is to tree_ll and tree_d. + bitlen_lld_e is to bitlen_lld what lz77_encoded is to data. + bitlen_cl is to bitlen_lld_e what bitlen_lld is to lz77_encoded. + */ + + unsigned BFINAL = final; + size_t i; + size_t numcodes_ll, numcodes_d, numcodes_lld, numcodes_lld_e, numcodes_cl; + unsigned HLIT, HDIST, HCLEN; + + uivector_init(&lz77_encoded); + HuffmanTree_init(&tree_ll); + HuffmanTree_init(&tree_d); + HuffmanTree_init(&tree_cl); + /* could fit on stack, but >1KB is on the larger side so allocate instead */ + frequencies_ll = (unsigned*)lodepng_malloc(286 * sizeof(*frequencies_ll)); + frequencies_d = (unsigned*)lodepng_malloc(30 * sizeof(*frequencies_d)); + frequencies_cl = (unsigned*)lodepng_malloc(NUM_CODE_LENGTH_CODES * sizeof(*frequencies_cl)); + + if(!frequencies_ll || !frequencies_d || !frequencies_cl) error = 83; /*alloc fail*/ + + /*This while loop never loops due to a break at the end, it is here to + allow breaking out of it to the cleanup phase on error conditions.*/ + while(!error) { + lodepng_memset(frequencies_ll, 0, 286 * sizeof(*frequencies_ll)); + lodepng_memset(frequencies_d, 0, 30 * sizeof(*frequencies_d)); + lodepng_memset(frequencies_cl, 0, NUM_CODE_LENGTH_CODES * sizeof(*frequencies_cl)); + + if(settings->use_lz77) { + error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, settings->windowsize, + settings->minmatch, settings->nicematch, settings->lazymatching); + if(error) break; + } else { + if(!uivector_resize(&lz77_encoded, datasize)) ERROR_BREAK(83 /*alloc fail*/); + for(i = datapos; i < dataend; ++i) lz77_encoded.data[i - datapos] = data[i]; /*no LZ77, but still will be Huffman compressed*/ + } + + /*Count the frequencies of lit, len and dist codes*/ + for(i = 0; i != lz77_encoded.size; ++i) { + unsigned symbol = lz77_encoded.data[i]; + ++frequencies_ll[symbol]; + if(symbol > 256) { + unsigned dist = lz77_encoded.data[i + 2]; + ++frequencies_d[dist]; + i += 3; + } + } + frequencies_ll[256] = 1; /*there will be exactly 1 end code, at the end of the block*/ + + /*Make both huffman trees, one for the lit and len codes, one for the dist codes*/ + error = HuffmanTree_makeFromFrequencies(&tree_ll, frequencies_ll, 257, 286, 15); + if(error) break; + /*2, not 1, is chosen for mincodes: some buggy PNG decoders require at least 2 symbols in the dist tree*/ + error = HuffmanTree_makeFromFrequencies(&tree_d, frequencies_d, 2, 30, 15); + if(error) break; + + numcodes_ll = LODEPNG_MIN(tree_ll.numcodes, 286); + numcodes_d = LODEPNG_MIN(tree_d.numcodes, 30); + /*store the code lengths of both generated trees in bitlen_lld*/ + numcodes_lld = numcodes_ll + numcodes_d; + bitlen_lld = (unsigned*)lodepng_malloc(numcodes_lld * sizeof(*bitlen_lld)); + /*numcodes_lld_e never needs more size than bitlen_lld*/ + bitlen_lld_e = (unsigned*)lodepng_malloc(numcodes_lld * sizeof(*bitlen_lld_e)); + if(!bitlen_lld || !bitlen_lld_e) ERROR_BREAK(83); /*alloc fail*/ + numcodes_lld_e = 0; + + for(i = 0; i != numcodes_ll; ++i) bitlen_lld[i] = tree_ll.lengths[i]; + for(i = 0; i != numcodes_d; ++i) bitlen_lld[numcodes_ll + i] = tree_d.lengths[i]; + + /*run-length compress bitlen_ldd into bitlen_lld_e by using repeat codes 16 (copy length 3-6 times), + 17 (3-10 zeroes), 18 (11-138 zeroes)*/ + for(i = 0; i != numcodes_lld; ++i) { + unsigned j = 0; /*amount of repetitions*/ + while(i + j + 1 < numcodes_lld && bitlen_lld[i + j + 1] == bitlen_lld[i]) ++j; + + if(bitlen_lld[i] == 0 && j >= 2) /*repeat code for zeroes*/ { + ++j; /*include the first zero*/ + if(j <= 10) /*repeat code 17 supports max 10 zeroes*/ { + bitlen_lld_e[numcodes_lld_e++] = 17; + bitlen_lld_e[numcodes_lld_e++] = j - 3; + } else /*repeat code 18 supports max 138 zeroes*/ { + if(j > 138) j = 138; + bitlen_lld_e[numcodes_lld_e++] = 18; + bitlen_lld_e[numcodes_lld_e++] = j - 11; + } + i += (j - 1); + } else if(j >= 3) /*repeat code for value other than zero*/ { + size_t k; + unsigned num = j / 6u, rest = j % 6u; + bitlen_lld_e[numcodes_lld_e++] = bitlen_lld[i]; + for(k = 0; k < num; ++k) { + bitlen_lld_e[numcodes_lld_e++] = 16; + bitlen_lld_e[numcodes_lld_e++] = 6 - 3; + } + if(rest >= 3) { + bitlen_lld_e[numcodes_lld_e++] = 16; + bitlen_lld_e[numcodes_lld_e++] = rest - 3; + } + else j -= rest; + i += j; + } else /*too short to benefit from repeat code*/ { + bitlen_lld_e[numcodes_lld_e++] = bitlen_lld[i]; + } + } + + /*generate tree_cl, the huffmantree of huffmantrees*/ + for(i = 0; i != numcodes_lld_e; ++i) { + ++frequencies_cl[bitlen_lld_e[i]]; + /*after a repeat code come the bits that specify the number of repetitions, + those don't need to be in the frequencies_cl calculation*/ + if(bitlen_lld_e[i] >= 16) ++i; + } + + error = HuffmanTree_makeFromFrequencies(&tree_cl, frequencies_cl, + NUM_CODE_LENGTH_CODES, NUM_CODE_LENGTH_CODES, 7); + if(error) break; + + /*compute amount of code-length-code-lengths to output*/ + numcodes_cl = NUM_CODE_LENGTH_CODES; + /*trim zeros at the end (using CLCL_ORDER), but minimum size must be 4 (see HCLEN below)*/ + while(numcodes_cl > 4u && tree_cl.lengths[CLCL_ORDER[numcodes_cl - 1u]] == 0) { + numcodes_cl--; + } + + /* + Write everything into the output + + After the BFINAL and BTYPE, the dynamic block consists out of the following: + - 5 bits HLIT, 5 bits HDIST, 4 bits HCLEN + - (HCLEN+4)*3 bits code lengths of code length alphabet + - HLIT + 257 code lengths of lit/length alphabet (encoded using the code length + alphabet, + possible repetition codes 16, 17, 18) + - HDIST + 1 code lengths of distance alphabet (encoded using the code length + alphabet, + possible repetition codes 16, 17, 18) + - compressed data + - 256 (end code) + */ + + /*Write block type*/ + writeBits(writer, BFINAL, 1); + writeBits(writer, 0, 1); /*first bit of BTYPE "dynamic"*/ + writeBits(writer, 1, 1); /*second bit of BTYPE "dynamic"*/ + + /*write the HLIT, HDIST and HCLEN values*/ + /*all three sizes take trimmed ending zeroes into account, done either by HuffmanTree_makeFromFrequencies + or in the loop for numcodes_cl above, which saves space. */ + HLIT = (unsigned)(numcodes_ll - 257); + HDIST = (unsigned)(numcodes_d - 1); + HCLEN = (unsigned)(numcodes_cl - 4); + writeBits(writer, HLIT, 5); + writeBits(writer, HDIST, 5); + writeBits(writer, HCLEN, 4); + + /*write the code lengths of the code length alphabet ("bitlen_cl")*/ + for(i = 0; i != numcodes_cl; ++i) writeBits(writer, tree_cl.lengths[CLCL_ORDER[i]], 3); + + /*write the lengths of the lit/len AND the dist alphabet*/ + for(i = 0; i != numcodes_lld_e; ++i) { + writeBitsReversed(writer, tree_cl.codes[bitlen_lld_e[i]], tree_cl.lengths[bitlen_lld_e[i]]); + /*extra bits of repeat codes*/ + if(bitlen_lld_e[i] == 16) writeBits(writer, bitlen_lld_e[++i], 2); + else if(bitlen_lld_e[i] == 17) writeBits(writer, bitlen_lld_e[++i], 3); + else if(bitlen_lld_e[i] == 18) writeBits(writer, bitlen_lld_e[++i], 7); + } + + /*write the compressed data symbols*/ + writeLZ77data(writer, &lz77_encoded, &tree_ll, &tree_d); + /*error: the length of the end code 256 must be larger than 0*/ + if(tree_ll.lengths[256] == 0) ERROR_BREAK(64); + + /*write the end code*/ + writeBitsReversed(writer, tree_ll.codes[256], tree_ll.lengths[256]); + + break; /*end of error-while*/ + } + + /*cleanup*/ + uivector_cleanup(&lz77_encoded); + HuffmanTree_cleanup(&tree_ll); + HuffmanTree_cleanup(&tree_d); + HuffmanTree_cleanup(&tree_cl); + lodepng_free(frequencies_ll); + lodepng_free(frequencies_d); + lodepng_free(frequencies_cl); + lodepng_free(bitlen_lld); + lodepng_free(bitlen_lld_e); + + return error; +} + +static unsigned deflateFixed(LodePNGBitWriter* writer, Hash* hash, + const unsigned char* data, + size_t datapos, size_t dataend, + const LodePNGCompressSettings* settings, unsigned final) { + HuffmanTree tree_ll; /*tree for literal values and length codes*/ + HuffmanTree tree_d; /*tree for distance codes*/ + + unsigned BFINAL = final; + unsigned error = 0; + size_t i; + + HuffmanTree_init(&tree_ll); + HuffmanTree_init(&tree_d); + + error = generateFixedLitLenTree(&tree_ll); + if(!error) error = generateFixedDistanceTree(&tree_d); + + if(!error) { + writeBits(writer, BFINAL, 1); + writeBits(writer, 1, 1); /*first bit of BTYPE*/ + writeBits(writer, 0, 1); /*second bit of BTYPE*/ + + if(settings->use_lz77) /*LZ77 encoded*/ { + uivector lz77_encoded; + uivector_init(&lz77_encoded); + error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, settings->windowsize, + settings->minmatch, settings->nicematch, settings->lazymatching); + if(!error) writeLZ77data(writer, &lz77_encoded, &tree_ll, &tree_d); + uivector_cleanup(&lz77_encoded); + } else /*no LZ77, but still will be Huffman compressed*/ { + for(i = datapos; i < dataend; ++i) { + writeBitsReversed(writer, tree_ll.codes[data[i]], tree_ll.lengths[data[i]]); + } + } + /*add END code*/ + if(!error) writeBitsReversed(writer,tree_ll.codes[256], tree_ll.lengths[256]); + } + + /*cleanup*/ + HuffmanTree_cleanup(&tree_ll); + HuffmanTree_cleanup(&tree_d); + + return error; +} + +static unsigned lodepng_deflatev(ucvector* out, const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings) { + unsigned error = 0; + size_t i, blocksize, numdeflateblocks; + Hash hash; + LodePNGBitWriter writer; + + LodePNGBitWriter_init(&writer, out); + + if(settings->btype > 2) return 61; + else if(settings->btype == 0) return deflateNoCompression(out, in, insize); + else if(settings->btype == 1) blocksize = insize; + else /*if(settings->btype == 2)*/ { + /*on PNGs, deflate blocks of 65-262k seem to give most dense encoding*/ + blocksize = insize / 8u + 8; + if(blocksize < 65536) blocksize = 65536; + if(blocksize > 262144) blocksize = 262144; + } + + numdeflateblocks = (insize + blocksize - 1) / blocksize; + if(numdeflateblocks == 0) numdeflateblocks = 1; + + error = hash_init(&hash, settings->windowsize); + + if(!error) { + for(i = 0; i != numdeflateblocks && !error; ++i) { + unsigned final = (i == numdeflateblocks - 1); + size_t start = i * blocksize; + size_t end = start + blocksize; + if(end > insize) end = insize; + + if(settings->btype == 1) error = deflateFixed(&writer, &hash, in, start, end, settings, final); + else if(settings->btype == 2) error = deflateDynamic(&writer, &hash, in, start, end, settings, final); + } + } + + hash_cleanup(&hash); + + return error; +} + +unsigned lodepng_deflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings) { + ucvector v = ucvector_init(*out, *outsize); + unsigned error = lodepng_deflatev(&v, in, insize, settings); + *out = v.data; + *outsize = v.size; + return error; +} + +static unsigned deflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings) { + if(settings->custom_deflate) { + unsigned error = settings->custom_deflate(out, outsize, in, insize, settings); + /*the custom deflate is allowed to have its own error codes, however, we translate it to code 111*/ + return error ? 111 : 0; + } else { + return lodepng_deflate(out, outsize, in, insize, settings); + } +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Adler32 / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +static unsigned update_adler32(unsigned adler, const unsigned char* data, size_t len) { + unsigned s1 = adler & 0xffffu; + unsigned s2 = (adler >> 16u) & 0xffffu; + + while(len != 0u) { + size_t i; + /*at least 5552 sums can be done before the sums overflow, saving a lot of module divisions*/ + size_t amount = len > 5552u ? 5552u : len; + len -= amount; + for(i = 0; i != amount; ++i) { + s1 += (*data++); + s2 += s1; + } + s1 %= 65521u; + s2 %= 65521u; + } + + return (s2 << 16u) | s1; +} + +/*Return the adler32 of the bytes data[0..len-1]*/ +static unsigned adler32(const unsigned char* data, size_t len) { + return update_adler32(1u, data, len); +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Zlib / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_DECODER + +static unsigned lodepng_zlib_decompressv(ucvector* out, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings) { + unsigned error = 0; + unsigned CM, CINFO, FDICT; + + if(insize < 2) return 53; /*error, size of zlib data too small*/ + /*read information from zlib header*/ + if((in[0] * 256 + in[1]) % 31 != 0) { + /*error: 256 * in[0] + in[1] must be a multiple of 31, the FCHECK value is supposed to be made that way*/ + return 24; + } + + CM = in[0] & 15; + CINFO = (in[0] >> 4) & 15; + /*FCHECK = in[1] & 31;*/ /*FCHECK is already tested above*/ + FDICT = (in[1] >> 5) & 1; + /*FLEVEL = (in[1] >> 6) & 3;*/ /*FLEVEL is not used here*/ + + if(CM != 8 || CINFO > 7) { + /*error: only compression method 8: inflate with sliding window of 32k is supported by the PNG spec*/ + return 25; + } + if(FDICT != 0) { + /*error: the specification of PNG says about the zlib stream: + "The additional flags shall not specify a preset dictionary."*/ + return 26; + } + + error = inflatev(out, in + 2, insize - 2, settings); + if(error) return error; + + if(!settings->ignore_adler32) { + unsigned ADLER32 = lodepng_read32bitInt(&in[insize - 4]); + unsigned checksum = adler32(out->data, out->size); + if(checksum != ADLER32) return 58; /*error, adler checksum not correct, data must be corrupted*/ + } + + return 0; /*no error*/ +} + + +unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGDecompressSettings* settings) { + ucvector v = ucvector_init(*out, *outsize); + unsigned error = lodepng_zlib_decompressv(&v, in, insize, settings); + *out = v.data; + *outsize = v.size; + return error; +} + +/*expected_size is expected output size, to avoid intermediate allocations. Set to 0 if not known. */ +static unsigned zlib_decompress(unsigned char** out, size_t* outsize, size_t expected_size, + const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings) { + unsigned error; + if(settings->custom_zlib) { + error = settings->custom_zlib(out, outsize, in, insize, settings); + if(error) { + /*the custom zlib is allowed to have its own error codes, however, we translate it to code 110*/ + error = 110; + /*if there's a max output size, and the custom zlib returned error, then indicate that error instead*/ + if(settings->max_output_size && *outsize > settings->max_output_size) error = 109; + } + } else { + ucvector v = ucvector_init(*out, *outsize); + if(expected_size) { + /*reserve the memory to avoid intermediate reallocations*/ + ucvector_resize(&v, *outsize + expected_size); + v.size = *outsize; + } + error = lodepng_zlib_decompressv(&v, in, insize, settings); + *out = v.data; + *outsize = v.size; + } + return error; +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER + +unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGCompressSettings* settings) { + size_t i; + unsigned error; + unsigned char* deflatedata = 0; + size_t deflatesize = 0; + + error = deflate(&deflatedata, &deflatesize, in, insize, settings); + + *out = NULL; + *outsize = 0; + if(!error) { + *outsize = deflatesize + 6; + *out = (unsigned char*)lodepng_malloc(*outsize); + if(!*out) error = 83; /*alloc fail*/ + } + + if(!error) { + unsigned ADLER32 = adler32(in, insize); + /*zlib data: 1 byte CMF (CM+CINFO), 1 byte FLG, deflate data, 4 byte ADLER32 checksum of the Decompressed data*/ + unsigned CMF = 120; /*0b01111000: CM 8, CINFO 7. With CINFO 7, any window size up to 32768 can be used.*/ + unsigned FLEVEL = 0; + unsigned FDICT = 0; + unsigned CMFFLG = 256 * CMF + FDICT * 32 + FLEVEL * 64; + unsigned FCHECK = 31 - CMFFLG % 31; + CMFFLG += FCHECK; + + (*out)[0] = (unsigned char)(CMFFLG >> 8); + (*out)[1] = (unsigned char)(CMFFLG & 255); + for(i = 0; i != deflatesize; ++i) (*out)[i + 2] = deflatedata[i]; + lodepng_set32bitInt(&(*out)[*outsize - 4], ADLER32); + } + + lodepng_free(deflatedata); + return error; +} + +/* compress using the default or custom zlib function */ +static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGCompressSettings* settings) { + if(settings->custom_zlib) { + unsigned error = settings->custom_zlib(out, outsize, in, insize, settings); + /*the custom zlib is allowed to have its own error codes, however, we translate it to code 111*/ + return error ? 111 : 0; + } else { + return lodepng_zlib_compress(out, outsize, in, insize, settings); + } +} + +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#else /*no LODEPNG_COMPILE_ZLIB*/ + +#ifdef LODEPNG_COMPILE_DECODER +static unsigned zlib_decompress(unsigned char** out, size_t* outsize, size_t expected_size, + const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings) { + if(!settings->custom_zlib) return 87; /*no custom zlib function provided */ + (void)expected_size; + return settings->custom_zlib(out, outsize, in, insize, settings); +} +#endif /*LODEPNG_COMPILE_DECODER*/ +#ifdef LODEPNG_COMPILE_ENCODER +static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGCompressSettings* settings) { + if(!settings->custom_zlib) return 87; /*no custom zlib function provided */ + return settings->custom_zlib(out, outsize, in, insize, settings); +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#endif /*LODEPNG_COMPILE_ZLIB*/ + +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_ENCODER + +/*this is a good tradeoff between speed and compression ratio*/ +#define DEFAULT_WINDOWSIZE 2048 + +void lodepng_compress_settings_init(LodePNGCompressSettings* settings) { + /*compress with dynamic huffman tree (not in the mathematical sense, just not the predefined one)*/ + settings->btype = 2; + settings->use_lz77 = 1; + settings->windowsize = DEFAULT_WINDOWSIZE; + settings->minmatch = 3; + settings->nicematch = 128; + settings->lazymatching = 1; + + settings->custom_zlib = 0; + settings->custom_deflate = 0; + settings->custom_context = 0; +} + +const LodePNGCompressSettings lodepng_default_compress_settings = {2, 1, DEFAULT_WINDOWSIZE, 3, 128, 1, 0, 0, 0}; + + +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_DECODER + +void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings) { + settings->ignore_adler32 = 0; + settings->ignore_nlen = 0; + settings->max_output_size = 0; + + settings->custom_zlib = 0; + settings->custom_inflate = 0; + settings->custom_context = 0; +} + +const LodePNGDecompressSettings lodepng_default_decompress_settings = {0, 0, 0, 0, 0, 0}; + +#endif /*LODEPNG_COMPILE_DECODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* // End of Zlib related code. Begin of PNG related code. // */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_PNG + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / CRC32 / */ +/* ////////////////////////////////////////////////////////////////////////// */ + + +#ifdef LODEPNG_COMPILE_CRC + +static const unsigned lodepng_crc32_table0[256] = { + 0x00000000u, 0x77073096u, 0xee0e612cu, 0x990951bau, 0x076dc419u, 0x706af48fu, 0xe963a535u, 0x9e6495a3u, + 0x0edb8832u, 0x79dcb8a4u, 0xe0d5e91eu, 0x97d2d988u, 0x09b64c2bu, 0x7eb17cbdu, 0xe7b82d07u, 0x90bf1d91u, + 0x1db71064u, 0x6ab020f2u, 0xf3b97148u, 0x84be41deu, 0x1adad47du, 0x6ddde4ebu, 0xf4d4b551u, 0x83d385c7u, + 0x136c9856u, 0x646ba8c0u, 0xfd62f97au, 0x8a65c9ecu, 0x14015c4fu, 0x63066cd9u, 0xfa0f3d63u, 0x8d080df5u, + 0x3b6e20c8u, 0x4c69105eu, 0xd56041e4u, 0xa2677172u, 0x3c03e4d1u, 0x4b04d447u, 0xd20d85fdu, 0xa50ab56bu, + 0x35b5a8fau, 0x42b2986cu, 0xdbbbc9d6u, 0xacbcf940u, 0x32d86ce3u, 0x45df5c75u, 0xdcd60dcfu, 0xabd13d59u, + 0x26d930acu, 0x51de003au, 0xc8d75180u, 0xbfd06116u, 0x21b4f4b5u, 0x56b3c423u, 0xcfba9599u, 0xb8bda50fu, + 0x2802b89eu, 0x5f058808u, 0xc60cd9b2u, 0xb10be924u, 0x2f6f7c87u, 0x58684c11u, 0xc1611dabu, 0xb6662d3du, + 0x76dc4190u, 0x01db7106u, 0x98d220bcu, 0xefd5102au, 0x71b18589u, 0x06b6b51fu, 0x9fbfe4a5u, 0xe8b8d433u, + 0x7807c9a2u, 0x0f00f934u, 0x9609a88eu, 0xe10e9818u, 0x7f6a0dbbu, 0x086d3d2du, 0x91646c97u, 0xe6635c01u, + 0x6b6b51f4u, 0x1c6c6162u, 0x856530d8u, 0xf262004eu, 0x6c0695edu, 0x1b01a57bu, 0x8208f4c1u, 0xf50fc457u, + 0x65b0d9c6u, 0x12b7e950u, 0x8bbeb8eau, 0xfcb9887cu, 0x62dd1ddfu, 0x15da2d49u, 0x8cd37cf3u, 0xfbd44c65u, + 0x4db26158u, 0x3ab551ceu, 0xa3bc0074u, 0xd4bb30e2u, 0x4adfa541u, 0x3dd895d7u, 0xa4d1c46du, 0xd3d6f4fbu, + 0x4369e96au, 0x346ed9fcu, 0xad678846u, 0xda60b8d0u, 0x44042d73u, 0x33031de5u, 0xaa0a4c5fu, 0xdd0d7cc9u, + 0x5005713cu, 0x270241aau, 0xbe0b1010u, 0xc90c2086u, 0x5768b525u, 0x206f85b3u, 0xb966d409u, 0xce61e49fu, + 0x5edef90eu, 0x29d9c998u, 0xb0d09822u, 0xc7d7a8b4u, 0x59b33d17u, 0x2eb40d81u, 0xb7bd5c3bu, 0xc0ba6cadu, + 0xedb88320u, 0x9abfb3b6u, 0x03b6e20cu, 0x74b1d29au, 0xead54739u, 0x9dd277afu, 0x04db2615u, 0x73dc1683u, + 0xe3630b12u, 0x94643b84u, 0x0d6d6a3eu, 0x7a6a5aa8u, 0xe40ecf0bu, 0x9309ff9du, 0x0a00ae27u, 0x7d079eb1u, + 0xf00f9344u, 0x8708a3d2u, 0x1e01f268u, 0x6906c2feu, 0xf762575du, 0x806567cbu, 0x196c3671u, 0x6e6b06e7u, + 0xfed41b76u, 0x89d32be0u, 0x10da7a5au, 0x67dd4accu, 0xf9b9df6fu, 0x8ebeeff9u, 0x17b7be43u, 0x60b08ed5u, + 0xd6d6a3e8u, 0xa1d1937eu, 0x38d8c2c4u, 0x4fdff252u, 0xd1bb67f1u, 0xa6bc5767u, 0x3fb506ddu, 0x48b2364bu, + 0xd80d2bdau, 0xaf0a1b4cu, 0x36034af6u, 0x41047a60u, 0xdf60efc3u, 0xa867df55u, 0x316e8eefu, 0x4669be79u, + 0xcb61b38cu, 0xbc66831au, 0x256fd2a0u, 0x5268e236u, 0xcc0c7795u, 0xbb0b4703u, 0x220216b9u, 0x5505262fu, + 0xc5ba3bbeu, 0xb2bd0b28u, 0x2bb45a92u, 0x5cb36a04u, 0xc2d7ffa7u, 0xb5d0cf31u, 0x2cd99e8bu, 0x5bdeae1du, + 0x9b64c2b0u, 0xec63f226u, 0x756aa39cu, 0x026d930au, 0x9c0906a9u, 0xeb0e363fu, 0x72076785u, 0x05005713u, + 0x95bf4a82u, 0xe2b87a14u, 0x7bb12baeu, 0x0cb61b38u, 0x92d28e9bu, 0xe5d5be0du, 0x7cdcefb7u, 0x0bdbdf21u, + 0x86d3d2d4u, 0xf1d4e242u, 0x68ddb3f8u, 0x1fda836eu, 0x81be16cdu, 0xf6b9265bu, 0x6fb077e1u, 0x18b74777u, + 0x88085ae6u, 0xff0f6a70u, 0x66063bcau, 0x11010b5cu, 0x8f659effu, 0xf862ae69u, 0x616bffd3u, 0x166ccf45u, + 0xa00ae278u, 0xd70dd2eeu, 0x4e048354u, 0x3903b3c2u, 0xa7672661u, 0xd06016f7u, 0x4969474du, 0x3e6e77dbu, + 0xaed16a4au, 0xd9d65adcu, 0x40df0b66u, 0x37d83bf0u, 0xa9bcae53u, 0xdebb9ec5u, 0x47b2cf7fu, 0x30b5ffe9u, + 0xbdbdf21cu, 0xcabac28au, 0x53b39330u, 0x24b4a3a6u, 0xbad03605u, 0xcdd70693u, 0x54de5729u, 0x23d967bfu, + 0xb3667a2eu, 0xc4614ab8u, 0x5d681b02u, 0x2a6f2b94u, 0xb40bbe37u, 0xc30c8ea1u, 0x5a05df1bu, 0x2d02ef8du +}; + +static const unsigned lodepng_crc32_table1[256] = { + 0x00000000u, 0x191b3141u, 0x32366282u, 0x2b2d53c3u, 0x646cc504u, 0x7d77f445u, 0x565aa786u, 0x4f4196c7u, + 0xc8d98a08u, 0xd1c2bb49u, 0xfaefe88au, 0xe3f4d9cbu, 0xacb54f0cu, 0xb5ae7e4du, 0x9e832d8eu, 0x87981ccfu, + 0x4ac21251u, 0x53d92310u, 0x78f470d3u, 0x61ef4192u, 0x2eaed755u, 0x37b5e614u, 0x1c98b5d7u, 0x05838496u, + 0x821b9859u, 0x9b00a918u, 0xb02dfadbu, 0xa936cb9au, 0xe6775d5du, 0xff6c6c1cu, 0xd4413fdfu, 0xcd5a0e9eu, + 0x958424a2u, 0x8c9f15e3u, 0xa7b24620u, 0xbea97761u, 0xf1e8e1a6u, 0xe8f3d0e7u, 0xc3de8324u, 0xdac5b265u, + 0x5d5daeaau, 0x44469febu, 0x6f6bcc28u, 0x7670fd69u, 0x39316baeu, 0x202a5aefu, 0x0b07092cu, 0x121c386du, + 0xdf4636f3u, 0xc65d07b2u, 0xed705471u, 0xf46b6530u, 0xbb2af3f7u, 0xa231c2b6u, 0x891c9175u, 0x9007a034u, + 0x179fbcfbu, 0x0e848dbau, 0x25a9de79u, 0x3cb2ef38u, 0x73f379ffu, 0x6ae848beu, 0x41c51b7du, 0x58de2a3cu, + 0xf0794f05u, 0xe9627e44u, 0xc24f2d87u, 0xdb541cc6u, 0x94158a01u, 0x8d0ebb40u, 0xa623e883u, 0xbf38d9c2u, + 0x38a0c50du, 0x21bbf44cu, 0x0a96a78fu, 0x138d96ceu, 0x5ccc0009u, 0x45d73148u, 0x6efa628bu, 0x77e153cau, + 0xbabb5d54u, 0xa3a06c15u, 0x888d3fd6u, 0x91960e97u, 0xded79850u, 0xc7cca911u, 0xece1fad2u, 0xf5facb93u, + 0x7262d75cu, 0x6b79e61du, 0x4054b5deu, 0x594f849fu, 0x160e1258u, 0x0f152319u, 0x243870dau, 0x3d23419bu, + 0x65fd6ba7u, 0x7ce65ae6u, 0x57cb0925u, 0x4ed03864u, 0x0191aea3u, 0x188a9fe2u, 0x33a7cc21u, 0x2abcfd60u, + 0xad24e1afu, 0xb43fd0eeu, 0x9f12832du, 0x8609b26cu, 0xc94824abu, 0xd05315eau, 0xfb7e4629u, 0xe2657768u, + 0x2f3f79f6u, 0x362448b7u, 0x1d091b74u, 0x04122a35u, 0x4b53bcf2u, 0x52488db3u, 0x7965de70u, 0x607eef31u, + 0xe7e6f3feu, 0xfefdc2bfu, 0xd5d0917cu, 0xcccba03du, 0x838a36fau, 0x9a9107bbu, 0xb1bc5478u, 0xa8a76539u, + 0x3b83984bu, 0x2298a90au, 0x09b5fac9u, 0x10aecb88u, 0x5fef5d4fu, 0x46f46c0eu, 0x6dd93fcdu, 0x74c20e8cu, + 0xf35a1243u, 0xea412302u, 0xc16c70c1u, 0xd8774180u, 0x9736d747u, 0x8e2de606u, 0xa500b5c5u, 0xbc1b8484u, + 0x71418a1au, 0x685abb5bu, 0x4377e898u, 0x5a6cd9d9u, 0x152d4f1eu, 0x0c367e5fu, 0x271b2d9cu, 0x3e001cddu, + 0xb9980012u, 0xa0833153u, 0x8bae6290u, 0x92b553d1u, 0xddf4c516u, 0xc4eff457u, 0xefc2a794u, 0xf6d996d5u, + 0xae07bce9u, 0xb71c8da8u, 0x9c31de6bu, 0x852aef2au, 0xca6b79edu, 0xd37048acu, 0xf85d1b6fu, 0xe1462a2eu, + 0x66de36e1u, 0x7fc507a0u, 0x54e85463u, 0x4df36522u, 0x02b2f3e5u, 0x1ba9c2a4u, 0x30849167u, 0x299fa026u, + 0xe4c5aeb8u, 0xfdde9ff9u, 0xd6f3cc3au, 0xcfe8fd7bu, 0x80a96bbcu, 0x99b25afdu, 0xb29f093eu, 0xab84387fu, + 0x2c1c24b0u, 0x350715f1u, 0x1e2a4632u, 0x07317773u, 0x4870e1b4u, 0x516bd0f5u, 0x7a468336u, 0x635db277u, + 0xcbfad74eu, 0xd2e1e60fu, 0xf9ccb5ccu, 0xe0d7848du, 0xaf96124au, 0xb68d230bu, 0x9da070c8u, 0x84bb4189u, + 0x03235d46u, 0x1a386c07u, 0x31153fc4u, 0x280e0e85u, 0x674f9842u, 0x7e54a903u, 0x5579fac0u, 0x4c62cb81u, + 0x8138c51fu, 0x9823f45eu, 0xb30ea79du, 0xaa1596dcu, 0xe554001bu, 0xfc4f315au, 0xd7626299u, 0xce7953d8u, + 0x49e14f17u, 0x50fa7e56u, 0x7bd72d95u, 0x62cc1cd4u, 0x2d8d8a13u, 0x3496bb52u, 0x1fbbe891u, 0x06a0d9d0u, + 0x5e7ef3ecu, 0x4765c2adu, 0x6c48916eu, 0x7553a02fu, 0x3a1236e8u, 0x230907a9u, 0x0824546au, 0x113f652bu, + 0x96a779e4u, 0x8fbc48a5u, 0xa4911b66u, 0xbd8a2a27u, 0xf2cbbce0u, 0xebd08da1u, 0xc0fdde62u, 0xd9e6ef23u, + 0x14bce1bdu, 0x0da7d0fcu, 0x268a833fu, 0x3f91b27eu, 0x70d024b9u, 0x69cb15f8u, 0x42e6463bu, 0x5bfd777au, + 0xdc656bb5u, 0xc57e5af4u, 0xee530937u, 0xf7483876u, 0xb809aeb1u, 0xa1129ff0u, 0x8a3fcc33u, 0x9324fd72u +}; + +static const unsigned lodepng_crc32_table2[256] = { + 0x00000000u, 0x01c26a37u, 0x0384d46eu, 0x0246be59u, 0x0709a8dcu, 0x06cbc2ebu, 0x048d7cb2u, 0x054f1685u, + 0x0e1351b8u, 0x0fd13b8fu, 0x0d9785d6u, 0x0c55efe1u, 0x091af964u, 0x08d89353u, 0x0a9e2d0au, 0x0b5c473du, + 0x1c26a370u, 0x1de4c947u, 0x1fa2771eu, 0x1e601d29u, 0x1b2f0bacu, 0x1aed619bu, 0x18abdfc2u, 0x1969b5f5u, + 0x1235f2c8u, 0x13f798ffu, 0x11b126a6u, 0x10734c91u, 0x153c5a14u, 0x14fe3023u, 0x16b88e7au, 0x177ae44du, + 0x384d46e0u, 0x398f2cd7u, 0x3bc9928eu, 0x3a0bf8b9u, 0x3f44ee3cu, 0x3e86840bu, 0x3cc03a52u, 0x3d025065u, + 0x365e1758u, 0x379c7d6fu, 0x35dac336u, 0x3418a901u, 0x3157bf84u, 0x3095d5b3u, 0x32d36beau, 0x331101ddu, + 0x246be590u, 0x25a98fa7u, 0x27ef31feu, 0x262d5bc9u, 0x23624d4cu, 0x22a0277bu, 0x20e69922u, 0x2124f315u, + 0x2a78b428u, 0x2bbade1fu, 0x29fc6046u, 0x283e0a71u, 0x2d711cf4u, 0x2cb376c3u, 0x2ef5c89au, 0x2f37a2adu, + 0x709a8dc0u, 0x7158e7f7u, 0x731e59aeu, 0x72dc3399u, 0x7793251cu, 0x76514f2bu, 0x7417f172u, 0x75d59b45u, + 0x7e89dc78u, 0x7f4bb64fu, 0x7d0d0816u, 0x7ccf6221u, 0x798074a4u, 0x78421e93u, 0x7a04a0cau, 0x7bc6cafdu, + 0x6cbc2eb0u, 0x6d7e4487u, 0x6f38fadeu, 0x6efa90e9u, 0x6bb5866cu, 0x6a77ec5bu, 0x68315202u, 0x69f33835u, + 0x62af7f08u, 0x636d153fu, 0x612bab66u, 0x60e9c151u, 0x65a6d7d4u, 0x6464bde3u, 0x662203bau, 0x67e0698du, + 0x48d7cb20u, 0x4915a117u, 0x4b531f4eu, 0x4a917579u, 0x4fde63fcu, 0x4e1c09cbu, 0x4c5ab792u, 0x4d98dda5u, + 0x46c49a98u, 0x4706f0afu, 0x45404ef6u, 0x448224c1u, 0x41cd3244u, 0x400f5873u, 0x4249e62au, 0x438b8c1du, + 0x54f16850u, 0x55330267u, 0x5775bc3eu, 0x56b7d609u, 0x53f8c08cu, 0x523aaabbu, 0x507c14e2u, 0x51be7ed5u, + 0x5ae239e8u, 0x5b2053dfu, 0x5966ed86u, 0x58a487b1u, 0x5deb9134u, 0x5c29fb03u, 0x5e6f455au, 0x5fad2f6du, + 0xe1351b80u, 0xe0f771b7u, 0xe2b1cfeeu, 0xe373a5d9u, 0xe63cb35cu, 0xe7fed96bu, 0xe5b86732u, 0xe47a0d05u, + 0xef264a38u, 0xeee4200fu, 0xeca29e56u, 0xed60f461u, 0xe82fe2e4u, 0xe9ed88d3u, 0xebab368au, 0xea695cbdu, + 0xfd13b8f0u, 0xfcd1d2c7u, 0xfe976c9eu, 0xff5506a9u, 0xfa1a102cu, 0xfbd87a1bu, 0xf99ec442u, 0xf85cae75u, + 0xf300e948u, 0xf2c2837fu, 0xf0843d26u, 0xf1465711u, 0xf4094194u, 0xf5cb2ba3u, 0xf78d95fau, 0xf64fffcdu, + 0xd9785d60u, 0xd8ba3757u, 0xdafc890eu, 0xdb3ee339u, 0xde71f5bcu, 0xdfb39f8bu, 0xddf521d2u, 0xdc374be5u, + 0xd76b0cd8u, 0xd6a966efu, 0xd4efd8b6u, 0xd52db281u, 0xd062a404u, 0xd1a0ce33u, 0xd3e6706au, 0xd2241a5du, + 0xc55efe10u, 0xc49c9427u, 0xc6da2a7eu, 0xc7184049u, 0xc25756ccu, 0xc3953cfbu, 0xc1d382a2u, 0xc011e895u, + 0xcb4dafa8u, 0xca8fc59fu, 0xc8c97bc6u, 0xc90b11f1u, 0xcc440774u, 0xcd866d43u, 0xcfc0d31au, 0xce02b92du, + 0x91af9640u, 0x906dfc77u, 0x922b422eu, 0x93e92819u, 0x96a63e9cu, 0x976454abu, 0x9522eaf2u, 0x94e080c5u, + 0x9fbcc7f8u, 0x9e7eadcfu, 0x9c381396u, 0x9dfa79a1u, 0x98b56f24u, 0x99770513u, 0x9b31bb4au, 0x9af3d17du, + 0x8d893530u, 0x8c4b5f07u, 0x8e0de15eu, 0x8fcf8b69u, 0x8a809decu, 0x8b42f7dbu, 0x89044982u, 0x88c623b5u, + 0x839a6488u, 0x82580ebfu, 0x801eb0e6u, 0x81dcdad1u, 0x8493cc54u, 0x8551a663u, 0x8717183au, 0x86d5720du, + 0xa9e2d0a0u, 0xa820ba97u, 0xaa6604ceu, 0xaba46ef9u, 0xaeeb787cu, 0xaf29124bu, 0xad6fac12u, 0xacadc625u, + 0xa7f18118u, 0xa633eb2fu, 0xa4755576u, 0xa5b73f41u, 0xa0f829c4u, 0xa13a43f3u, 0xa37cfdaau, 0xa2be979du, + 0xb5c473d0u, 0xb40619e7u, 0xb640a7beu, 0xb782cd89u, 0xb2cddb0cu, 0xb30fb13bu, 0xb1490f62u, 0xb08b6555u, + 0xbbd72268u, 0xba15485fu, 0xb853f606u, 0xb9919c31u, 0xbcde8ab4u, 0xbd1ce083u, 0xbf5a5edau, 0xbe9834edu +}; + +static const unsigned lodepng_crc32_table3[256] = { + 0x00000000u, 0xb8bc6765u, 0xaa09c88bu, 0x12b5afeeu, 0x8f629757u, 0x37def032u, 0x256b5fdcu, 0x9dd738b9u, + 0xc5b428efu, 0x7d084f8au, 0x6fbde064u, 0xd7018701u, 0x4ad6bfb8u, 0xf26ad8ddu, 0xe0df7733u, 0x58631056u, + 0x5019579fu, 0xe8a530fau, 0xfa109f14u, 0x42acf871u, 0xdf7bc0c8u, 0x67c7a7adu, 0x75720843u, 0xcdce6f26u, + 0x95ad7f70u, 0x2d111815u, 0x3fa4b7fbu, 0x8718d09eu, 0x1acfe827u, 0xa2738f42u, 0xb0c620acu, 0x087a47c9u, + 0xa032af3eu, 0x188ec85bu, 0x0a3b67b5u, 0xb28700d0u, 0x2f503869u, 0x97ec5f0cu, 0x8559f0e2u, 0x3de59787u, + 0x658687d1u, 0xdd3ae0b4u, 0xcf8f4f5au, 0x7733283fu, 0xeae41086u, 0x525877e3u, 0x40edd80du, 0xf851bf68u, + 0xf02bf8a1u, 0x48979fc4u, 0x5a22302au, 0xe29e574fu, 0x7f496ff6u, 0xc7f50893u, 0xd540a77du, 0x6dfcc018u, + 0x359fd04eu, 0x8d23b72bu, 0x9f9618c5u, 0x272a7fa0u, 0xbafd4719u, 0x0241207cu, 0x10f48f92u, 0xa848e8f7u, + 0x9b14583du, 0x23a83f58u, 0x311d90b6u, 0x89a1f7d3u, 0x1476cf6au, 0xaccaa80fu, 0xbe7f07e1u, 0x06c36084u, + 0x5ea070d2u, 0xe61c17b7u, 0xf4a9b859u, 0x4c15df3cu, 0xd1c2e785u, 0x697e80e0u, 0x7bcb2f0eu, 0xc377486bu, + 0xcb0d0fa2u, 0x73b168c7u, 0x6104c729u, 0xd9b8a04cu, 0x446f98f5u, 0xfcd3ff90u, 0xee66507eu, 0x56da371bu, + 0x0eb9274du, 0xb6054028u, 0xa4b0efc6u, 0x1c0c88a3u, 0x81dbb01au, 0x3967d77fu, 0x2bd27891u, 0x936e1ff4u, + 0x3b26f703u, 0x839a9066u, 0x912f3f88u, 0x299358edu, 0xb4446054u, 0x0cf80731u, 0x1e4da8dfu, 0xa6f1cfbau, + 0xfe92dfecu, 0x462eb889u, 0x549b1767u, 0xec277002u, 0x71f048bbu, 0xc94c2fdeu, 0xdbf98030u, 0x6345e755u, + 0x6b3fa09cu, 0xd383c7f9u, 0xc1366817u, 0x798a0f72u, 0xe45d37cbu, 0x5ce150aeu, 0x4e54ff40u, 0xf6e89825u, + 0xae8b8873u, 0x1637ef16u, 0x048240f8u, 0xbc3e279du, 0x21e91f24u, 0x99557841u, 0x8be0d7afu, 0x335cb0cau, + 0xed59b63bu, 0x55e5d15eu, 0x47507eb0u, 0xffec19d5u, 0x623b216cu, 0xda874609u, 0xc832e9e7u, 0x708e8e82u, + 0x28ed9ed4u, 0x9051f9b1u, 0x82e4565fu, 0x3a58313au, 0xa78f0983u, 0x1f336ee6u, 0x0d86c108u, 0xb53aa66du, + 0xbd40e1a4u, 0x05fc86c1u, 0x1749292fu, 0xaff54e4au, 0x322276f3u, 0x8a9e1196u, 0x982bbe78u, 0x2097d91du, + 0x78f4c94bu, 0xc048ae2eu, 0xd2fd01c0u, 0x6a4166a5u, 0xf7965e1cu, 0x4f2a3979u, 0x5d9f9697u, 0xe523f1f2u, + 0x4d6b1905u, 0xf5d77e60u, 0xe762d18eu, 0x5fdeb6ebu, 0xc2098e52u, 0x7ab5e937u, 0x680046d9u, 0xd0bc21bcu, + 0x88df31eau, 0x3063568fu, 0x22d6f961u, 0x9a6a9e04u, 0x07bda6bdu, 0xbf01c1d8u, 0xadb46e36u, 0x15080953u, + 0x1d724e9au, 0xa5ce29ffu, 0xb77b8611u, 0x0fc7e174u, 0x9210d9cdu, 0x2aacbea8u, 0x38191146u, 0x80a57623u, + 0xd8c66675u, 0x607a0110u, 0x72cfaefeu, 0xca73c99bu, 0x57a4f122u, 0xef189647u, 0xfdad39a9u, 0x45115eccu, + 0x764dee06u, 0xcef18963u, 0xdc44268du, 0x64f841e8u, 0xf92f7951u, 0x41931e34u, 0x5326b1dau, 0xeb9ad6bfu, + 0xb3f9c6e9u, 0x0b45a18cu, 0x19f00e62u, 0xa14c6907u, 0x3c9b51beu, 0x842736dbu, 0x96929935u, 0x2e2efe50u, + 0x2654b999u, 0x9ee8defcu, 0x8c5d7112u, 0x34e11677u, 0xa9362eceu, 0x118a49abu, 0x033fe645u, 0xbb838120u, + 0xe3e09176u, 0x5b5cf613u, 0x49e959fdu, 0xf1553e98u, 0x6c820621u, 0xd43e6144u, 0xc68bceaau, 0x7e37a9cfu, + 0xd67f4138u, 0x6ec3265du, 0x7c7689b3u, 0xc4caeed6u, 0x591dd66fu, 0xe1a1b10au, 0xf3141ee4u, 0x4ba87981u, + 0x13cb69d7u, 0xab770eb2u, 0xb9c2a15cu, 0x017ec639u, 0x9ca9fe80u, 0x241599e5u, 0x36a0360bu, 0x8e1c516eu, + 0x866616a7u, 0x3eda71c2u, 0x2c6fde2cu, 0x94d3b949u, 0x090481f0u, 0xb1b8e695u, 0xa30d497bu, 0x1bb12e1eu, + 0x43d23e48u, 0xfb6e592du, 0xe9dbf6c3u, 0x516791a6u, 0xccb0a91fu, 0x740cce7au, 0x66b96194u, 0xde0506f1u +}; + +static const unsigned lodepng_crc32_table4[256] = { + 0x00000000u, 0x3d6029b0u, 0x7ac05360u, 0x47a07ad0u, 0xf580a6c0u, 0xc8e08f70u, 0x8f40f5a0u, 0xb220dc10u, + 0x30704bc1u, 0x0d106271u, 0x4ab018a1u, 0x77d03111u, 0xc5f0ed01u, 0xf890c4b1u, 0xbf30be61u, 0x825097d1u, + 0x60e09782u, 0x5d80be32u, 0x1a20c4e2u, 0x2740ed52u, 0x95603142u, 0xa80018f2u, 0xefa06222u, 0xd2c04b92u, + 0x5090dc43u, 0x6df0f5f3u, 0x2a508f23u, 0x1730a693u, 0xa5107a83u, 0x98705333u, 0xdfd029e3u, 0xe2b00053u, + 0xc1c12f04u, 0xfca106b4u, 0xbb017c64u, 0x866155d4u, 0x344189c4u, 0x0921a074u, 0x4e81daa4u, 0x73e1f314u, + 0xf1b164c5u, 0xccd14d75u, 0x8b7137a5u, 0xb6111e15u, 0x0431c205u, 0x3951ebb5u, 0x7ef19165u, 0x4391b8d5u, + 0xa121b886u, 0x9c419136u, 0xdbe1ebe6u, 0xe681c256u, 0x54a11e46u, 0x69c137f6u, 0x2e614d26u, 0x13016496u, + 0x9151f347u, 0xac31daf7u, 0xeb91a027u, 0xd6f18997u, 0x64d15587u, 0x59b17c37u, 0x1e1106e7u, 0x23712f57u, + 0x58f35849u, 0x659371f9u, 0x22330b29u, 0x1f532299u, 0xad73fe89u, 0x9013d739u, 0xd7b3ade9u, 0xead38459u, + 0x68831388u, 0x55e33a38u, 0x124340e8u, 0x2f236958u, 0x9d03b548u, 0xa0639cf8u, 0xe7c3e628u, 0xdaa3cf98u, + 0x3813cfcbu, 0x0573e67bu, 0x42d39cabu, 0x7fb3b51bu, 0xcd93690bu, 0xf0f340bbu, 0xb7533a6bu, 0x8a3313dbu, + 0x0863840au, 0x3503adbau, 0x72a3d76au, 0x4fc3fedau, 0xfde322cau, 0xc0830b7au, 0x872371aau, 0xba43581au, + 0x9932774du, 0xa4525efdu, 0xe3f2242du, 0xde920d9du, 0x6cb2d18du, 0x51d2f83du, 0x167282edu, 0x2b12ab5du, + 0xa9423c8cu, 0x9422153cu, 0xd3826fecu, 0xeee2465cu, 0x5cc29a4cu, 0x61a2b3fcu, 0x2602c92cu, 0x1b62e09cu, + 0xf9d2e0cfu, 0xc4b2c97fu, 0x8312b3afu, 0xbe729a1fu, 0x0c52460fu, 0x31326fbfu, 0x7692156fu, 0x4bf23cdfu, + 0xc9a2ab0eu, 0xf4c282beu, 0xb362f86eu, 0x8e02d1deu, 0x3c220dceu, 0x0142247eu, 0x46e25eaeu, 0x7b82771eu, + 0xb1e6b092u, 0x8c869922u, 0xcb26e3f2u, 0xf646ca42u, 0x44661652u, 0x79063fe2u, 0x3ea64532u, 0x03c66c82u, + 0x8196fb53u, 0xbcf6d2e3u, 0xfb56a833u, 0xc6368183u, 0x74165d93u, 0x49767423u, 0x0ed60ef3u, 0x33b62743u, + 0xd1062710u, 0xec660ea0u, 0xabc67470u, 0x96a65dc0u, 0x248681d0u, 0x19e6a860u, 0x5e46d2b0u, 0x6326fb00u, + 0xe1766cd1u, 0xdc164561u, 0x9bb63fb1u, 0xa6d61601u, 0x14f6ca11u, 0x2996e3a1u, 0x6e369971u, 0x5356b0c1u, + 0x70279f96u, 0x4d47b626u, 0x0ae7ccf6u, 0x3787e546u, 0x85a73956u, 0xb8c710e6u, 0xff676a36u, 0xc2074386u, + 0x4057d457u, 0x7d37fde7u, 0x3a978737u, 0x07f7ae87u, 0xb5d77297u, 0x88b75b27u, 0xcf1721f7u, 0xf2770847u, + 0x10c70814u, 0x2da721a4u, 0x6a075b74u, 0x576772c4u, 0xe547aed4u, 0xd8278764u, 0x9f87fdb4u, 0xa2e7d404u, + 0x20b743d5u, 0x1dd76a65u, 0x5a7710b5u, 0x67173905u, 0xd537e515u, 0xe857cca5u, 0xaff7b675u, 0x92979fc5u, + 0xe915e8dbu, 0xd475c16bu, 0x93d5bbbbu, 0xaeb5920bu, 0x1c954e1bu, 0x21f567abu, 0x66551d7bu, 0x5b3534cbu, + 0xd965a31au, 0xe4058aaau, 0xa3a5f07au, 0x9ec5d9cau, 0x2ce505dau, 0x11852c6au, 0x562556bau, 0x6b457f0au, + 0x89f57f59u, 0xb49556e9u, 0xf3352c39u, 0xce550589u, 0x7c75d999u, 0x4115f029u, 0x06b58af9u, 0x3bd5a349u, + 0xb9853498u, 0x84e51d28u, 0xc34567f8u, 0xfe254e48u, 0x4c059258u, 0x7165bbe8u, 0x36c5c138u, 0x0ba5e888u, + 0x28d4c7dfu, 0x15b4ee6fu, 0x521494bfu, 0x6f74bd0fu, 0xdd54611fu, 0xe03448afu, 0xa794327fu, 0x9af41bcfu, + 0x18a48c1eu, 0x25c4a5aeu, 0x6264df7eu, 0x5f04f6ceu, 0xed242adeu, 0xd044036eu, 0x97e479beu, 0xaa84500eu, + 0x4834505du, 0x755479edu, 0x32f4033du, 0x0f942a8du, 0xbdb4f69du, 0x80d4df2du, 0xc774a5fdu, 0xfa148c4du, + 0x78441b9cu, 0x4524322cu, 0x028448fcu, 0x3fe4614cu, 0x8dc4bd5cu, 0xb0a494ecu, 0xf704ee3cu, 0xca64c78cu +}; + +static const unsigned lodepng_crc32_table5[256] = { + 0x00000000u, 0xcb5cd3a5u, 0x4dc8a10bu, 0x869472aeu, 0x9b914216u, 0x50cd91b3u, 0xd659e31du, 0x1d0530b8u, + 0xec53826du, 0x270f51c8u, 0xa19b2366u, 0x6ac7f0c3u, 0x77c2c07bu, 0xbc9e13deu, 0x3a0a6170u, 0xf156b2d5u, + 0x03d6029bu, 0xc88ad13eu, 0x4e1ea390u, 0x85427035u, 0x9847408du, 0x531b9328u, 0xd58fe186u, 0x1ed33223u, + 0xef8580f6u, 0x24d95353u, 0xa24d21fdu, 0x6911f258u, 0x7414c2e0u, 0xbf481145u, 0x39dc63ebu, 0xf280b04eu, + 0x07ac0536u, 0xccf0d693u, 0x4a64a43du, 0x81387798u, 0x9c3d4720u, 0x57619485u, 0xd1f5e62bu, 0x1aa9358eu, + 0xebff875bu, 0x20a354feu, 0xa6372650u, 0x6d6bf5f5u, 0x706ec54du, 0xbb3216e8u, 0x3da66446u, 0xf6fab7e3u, + 0x047a07adu, 0xcf26d408u, 0x49b2a6a6u, 0x82ee7503u, 0x9feb45bbu, 0x54b7961eu, 0xd223e4b0u, 0x197f3715u, + 0xe82985c0u, 0x23755665u, 0xa5e124cbu, 0x6ebdf76eu, 0x73b8c7d6u, 0xb8e41473u, 0x3e7066ddu, 0xf52cb578u, + 0x0f580a6cu, 0xc404d9c9u, 0x4290ab67u, 0x89cc78c2u, 0x94c9487au, 0x5f959bdfu, 0xd901e971u, 0x125d3ad4u, + 0xe30b8801u, 0x28575ba4u, 0xaec3290au, 0x659ffaafu, 0x789aca17u, 0xb3c619b2u, 0x35526b1cu, 0xfe0eb8b9u, + 0x0c8e08f7u, 0xc7d2db52u, 0x4146a9fcu, 0x8a1a7a59u, 0x971f4ae1u, 0x5c439944u, 0xdad7ebeau, 0x118b384fu, + 0xe0dd8a9au, 0x2b81593fu, 0xad152b91u, 0x6649f834u, 0x7b4cc88cu, 0xb0101b29u, 0x36846987u, 0xfdd8ba22u, + 0x08f40f5au, 0xc3a8dcffu, 0x453cae51u, 0x8e607df4u, 0x93654d4cu, 0x58399ee9u, 0xdeadec47u, 0x15f13fe2u, + 0xe4a78d37u, 0x2ffb5e92u, 0xa96f2c3cu, 0x6233ff99u, 0x7f36cf21u, 0xb46a1c84u, 0x32fe6e2au, 0xf9a2bd8fu, + 0x0b220dc1u, 0xc07ede64u, 0x46eaaccau, 0x8db67f6fu, 0x90b34fd7u, 0x5bef9c72u, 0xdd7beedcu, 0x16273d79u, + 0xe7718facu, 0x2c2d5c09u, 0xaab92ea7u, 0x61e5fd02u, 0x7ce0cdbau, 0xb7bc1e1fu, 0x31286cb1u, 0xfa74bf14u, + 0x1eb014d8u, 0xd5ecc77du, 0x5378b5d3u, 0x98246676u, 0x852156ceu, 0x4e7d856bu, 0xc8e9f7c5u, 0x03b52460u, + 0xf2e396b5u, 0x39bf4510u, 0xbf2b37beu, 0x7477e41bu, 0x6972d4a3u, 0xa22e0706u, 0x24ba75a8u, 0xefe6a60du, + 0x1d661643u, 0xd63ac5e6u, 0x50aeb748u, 0x9bf264edu, 0x86f75455u, 0x4dab87f0u, 0xcb3ff55eu, 0x006326fbu, + 0xf135942eu, 0x3a69478bu, 0xbcfd3525u, 0x77a1e680u, 0x6aa4d638u, 0xa1f8059du, 0x276c7733u, 0xec30a496u, + 0x191c11eeu, 0xd240c24bu, 0x54d4b0e5u, 0x9f886340u, 0x828d53f8u, 0x49d1805du, 0xcf45f2f3u, 0x04192156u, + 0xf54f9383u, 0x3e134026u, 0xb8873288u, 0x73dbe12du, 0x6eded195u, 0xa5820230u, 0x2316709eu, 0xe84aa33bu, + 0x1aca1375u, 0xd196c0d0u, 0x5702b27eu, 0x9c5e61dbu, 0x815b5163u, 0x4a0782c6u, 0xcc93f068u, 0x07cf23cdu, + 0xf6999118u, 0x3dc542bdu, 0xbb513013u, 0x700de3b6u, 0x6d08d30eu, 0xa65400abu, 0x20c07205u, 0xeb9ca1a0u, + 0x11e81eb4u, 0xdab4cd11u, 0x5c20bfbfu, 0x977c6c1au, 0x8a795ca2u, 0x41258f07u, 0xc7b1fda9u, 0x0ced2e0cu, + 0xfdbb9cd9u, 0x36e74f7cu, 0xb0733dd2u, 0x7b2fee77u, 0x662adecfu, 0xad760d6au, 0x2be27fc4u, 0xe0beac61u, + 0x123e1c2fu, 0xd962cf8au, 0x5ff6bd24u, 0x94aa6e81u, 0x89af5e39u, 0x42f38d9cu, 0xc467ff32u, 0x0f3b2c97u, + 0xfe6d9e42u, 0x35314de7u, 0xb3a53f49u, 0x78f9ececu, 0x65fcdc54u, 0xaea00ff1u, 0x28347d5fu, 0xe368aefau, + 0x16441b82u, 0xdd18c827u, 0x5b8cba89u, 0x90d0692cu, 0x8dd55994u, 0x46898a31u, 0xc01df89fu, 0x0b412b3au, + 0xfa1799efu, 0x314b4a4au, 0xb7df38e4u, 0x7c83eb41u, 0x6186dbf9u, 0xaada085cu, 0x2c4e7af2u, 0xe712a957u, + 0x15921919u, 0xdececabcu, 0x585ab812u, 0x93066bb7u, 0x8e035b0fu, 0x455f88aau, 0xc3cbfa04u, 0x089729a1u, + 0xf9c19b74u, 0x329d48d1u, 0xb4093a7fu, 0x7f55e9dau, 0x6250d962u, 0xa90c0ac7u, 0x2f987869u, 0xe4c4abccu +}; + +static const unsigned lodepng_crc32_table6[256] = { + 0x00000000u, 0xa6770bb4u, 0x979f1129u, 0x31e81a9du, 0xf44f2413u, 0x52382fa7u, 0x63d0353au, 0xc5a73e8eu, + 0x33ef4e67u, 0x959845d3u, 0xa4705f4eu, 0x020754fau, 0xc7a06a74u, 0x61d761c0u, 0x503f7b5du, 0xf64870e9u, + 0x67de9cceu, 0xc1a9977au, 0xf0418de7u, 0x56368653u, 0x9391b8ddu, 0x35e6b369u, 0x040ea9f4u, 0xa279a240u, + 0x5431d2a9u, 0xf246d91du, 0xc3aec380u, 0x65d9c834u, 0xa07ef6bau, 0x0609fd0eu, 0x37e1e793u, 0x9196ec27u, + 0xcfbd399cu, 0x69ca3228u, 0x582228b5u, 0xfe552301u, 0x3bf21d8fu, 0x9d85163bu, 0xac6d0ca6u, 0x0a1a0712u, + 0xfc5277fbu, 0x5a257c4fu, 0x6bcd66d2u, 0xcdba6d66u, 0x081d53e8u, 0xae6a585cu, 0x9f8242c1u, 0x39f54975u, + 0xa863a552u, 0x0e14aee6u, 0x3ffcb47bu, 0x998bbfcfu, 0x5c2c8141u, 0xfa5b8af5u, 0xcbb39068u, 0x6dc49bdcu, + 0x9b8ceb35u, 0x3dfbe081u, 0x0c13fa1cu, 0xaa64f1a8u, 0x6fc3cf26u, 0xc9b4c492u, 0xf85cde0fu, 0x5e2bd5bbu, + 0x440b7579u, 0xe27c7ecdu, 0xd3946450u, 0x75e36fe4u, 0xb044516au, 0x16335adeu, 0x27db4043u, 0x81ac4bf7u, + 0x77e43b1eu, 0xd19330aau, 0xe07b2a37u, 0x460c2183u, 0x83ab1f0du, 0x25dc14b9u, 0x14340e24u, 0xb2430590u, + 0x23d5e9b7u, 0x85a2e203u, 0xb44af89eu, 0x123df32au, 0xd79acda4u, 0x71edc610u, 0x4005dc8du, 0xe672d739u, + 0x103aa7d0u, 0xb64dac64u, 0x87a5b6f9u, 0x21d2bd4du, 0xe47583c3u, 0x42028877u, 0x73ea92eau, 0xd59d995eu, + 0x8bb64ce5u, 0x2dc14751u, 0x1c295dccu, 0xba5e5678u, 0x7ff968f6u, 0xd98e6342u, 0xe86679dfu, 0x4e11726bu, + 0xb8590282u, 0x1e2e0936u, 0x2fc613abu, 0x89b1181fu, 0x4c162691u, 0xea612d25u, 0xdb8937b8u, 0x7dfe3c0cu, + 0xec68d02bu, 0x4a1fdb9fu, 0x7bf7c102u, 0xdd80cab6u, 0x1827f438u, 0xbe50ff8cu, 0x8fb8e511u, 0x29cfeea5u, + 0xdf879e4cu, 0x79f095f8u, 0x48188f65u, 0xee6f84d1u, 0x2bc8ba5fu, 0x8dbfb1ebu, 0xbc57ab76u, 0x1a20a0c2u, + 0x8816eaf2u, 0x2e61e146u, 0x1f89fbdbu, 0xb9fef06fu, 0x7c59cee1u, 0xda2ec555u, 0xebc6dfc8u, 0x4db1d47cu, + 0xbbf9a495u, 0x1d8eaf21u, 0x2c66b5bcu, 0x8a11be08u, 0x4fb68086u, 0xe9c18b32u, 0xd82991afu, 0x7e5e9a1bu, + 0xefc8763cu, 0x49bf7d88u, 0x78576715u, 0xde206ca1u, 0x1b87522fu, 0xbdf0599bu, 0x8c184306u, 0x2a6f48b2u, + 0xdc27385bu, 0x7a5033efu, 0x4bb82972u, 0xedcf22c6u, 0x28681c48u, 0x8e1f17fcu, 0xbff70d61u, 0x198006d5u, + 0x47abd36eu, 0xe1dcd8dau, 0xd034c247u, 0x7643c9f3u, 0xb3e4f77du, 0x1593fcc9u, 0x247be654u, 0x820cede0u, + 0x74449d09u, 0xd23396bdu, 0xe3db8c20u, 0x45ac8794u, 0x800bb91au, 0x267cb2aeu, 0x1794a833u, 0xb1e3a387u, + 0x20754fa0u, 0x86024414u, 0xb7ea5e89u, 0x119d553du, 0xd43a6bb3u, 0x724d6007u, 0x43a57a9au, 0xe5d2712eu, + 0x139a01c7u, 0xb5ed0a73u, 0x840510eeu, 0x22721b5au, 0xe7d525d4u, 0x41a22e60u, 0x704a34fdu, 0xd63d3f49u, + 0xcc1d9f8bu, 0x6a6a943fu, 0x5b828ea2u, 0xfdf58516u, 0x3852bb98u, 0x9e25b02cu, 0xafcdaab1u, 0x09baa105u, + 0xfff2d1ecu, 0x5985da58u, 0x686dc0c5u, 0xce1acb71u, 0x0bbdf5ffu, 0xadcafe4bu, 0x9c22e4d6u, 0x3a55ef62u, + 0xabc30345u, 0x0db408f1u, 0x3c5c126cu, 0x9a2b19d8u, 0x5f8c2756u, 0xf9fb2ce2u, 0xc813367fu, 0x6e643dcbu, + 0x982c4d22u, 0x3e5b4696u, 0x0fb35c0bu, 0xa9c457bfu, 0x6c636931u, 0xca146285u, 0xfbfc7818u, 0x5d8b73acu, + 0x03a0a617u, 0xa5d7ada3u, 0x943fb73eu, 0x3248bc8au, 0xf7ef8204u, 0x519889b0u, 0x6070932du, 0xc6079899u, + 0x304fe870u, 0x9638e3c4u, 0xa7d0f959u, 0x01a7f2edu, 0xc400cc63u, 0x6277c7d7u, 0x539fdd4au, 0xf5e8d6feu, + 0x647e3ad9u, 0xc209316du, 0xf3e12bf0u, 0x55962044u, 0x90311ecau, 0x3646157eu, 0x07ae0fe3u, 0xa1d90457u, + 0x579174beu, 0xf1e67f0au, 0xc00e6597u, 0x66796e23u, 0xa3de50adu, 0x05a95b19u, 0x34414184u, 0x92364a30u +}; + +static const unsigned lodepng_crc32_table7[256] = { + 0x00000000u, 0xccaa009eu, 0x4225077du, 0x8e8f07e3u, 0x844a0efau, 0x48e00e64u, 0xc66f0987u, 0x0ac50919u, + 0xd3e51bb5u, 0x1f4f1b2bu, 0x91c01cc8u, 0x5d6a1c56u, 0x57af154fu, 0x9b0515d1u, 0x158a1232u, 0xd92012acu, + 0x7cbb312bu, 0xb01131b5u, 0x3e9e3656u, 0xf23436c8u, 0xf8f13fd1u, 0x345b3f4fu, 0xbad438acu, 0x767e3832u, + 0xaf5e2a9eu, 0x63f42a00u, 0xed7b2de3u, 0x21d12d7du, 0x2b142464u, 0xe7be24fau, 0x69312319u, 0xa59b2387u, + 0xf9766256u, 0x35dc62c8u, 0xbb53652bu, 0x77f965b5u, 0x7d3c6cacu, 0xb1966c32u, 0x3f196bd1u, 0xf3b36b4fu, + 0x2a9379e3u, 0xe639797du, 0x68b67e9eu, 0xa41c7e00u, 0xaed97719u, 0x62737787u, 0xecfc7064u, 0x205670fau, + 0x85cd537du, 0x496753e3u, 0xc7e85400u, 0x0b42549eu, 0x01875d87u, 0xcd2d5d19u, 0x43a25afau, 0x8f085a64u, + 0x562848c8u, 0x9a824856u, 0x140d4fb5u, 0xd8a74f2bu, 0xd2624632u, 0x1ec846acu, 0x9047414fu, 0x5ced41d1u, + 0x299dc2edu, 0xe537c273u, 0x6bb8c590u, 0xa712c50eu, 0xadd7cc17u, 0x617dcc89u, 0xeff2cb6au, 0x2358cbf4u, + 0xfa78d958u, 0x36d2d9c6u, 0xb85dde25u, 0x74f7debbu, 0x7e32d7a2u, 0xb298d73cu, 0x3c17d0dfu, 0xf0bdd041u, + 0x5526f3c6u, 0x998cf358u, 0x1703f4bbu, 0xdba9f425u, 0xd16cfd3cu, 0x1dc6fda2u, 0x9349fa41u, 0x5fe3fadfu, + 0x86c3e873u, 0x4a69e8edu, 0xc4e6ef0eu, 0x084cef90u, 0x0289e689u, 0xce23e617u, 0x40ace1f4u, 0x8c06e16au, + 0xd0eba0bbu, 0x1c41a025u, 0x92cea7c6u, 0x5e64a758u, 0x54a1ae41u, 0x980baedfu, 0x1684a93cu, 0xda2ea9a2u, + 0x030ebb0eu, 0xcfa4bb90u, 0x412bbc73u, 0x8d81bcedu, 0x8744b5f4u, 0x4beeb56au, 0xc561b289u, 0x09cbb217u, + 0xac509190u, 0x60fa910eu, 0xee7596edu, 0x22df9673u, 0x281a9f6au, 0xe4b09ff4u, 0x6a3f9817u, 0xa6959889u, + 0x7fb58a25u, 0xb31f8abbu, 0x3d908d58u, 0xf13a8dc6u, 0xfbff84dfu, 0x37558441u, 0xb9da83a2u, 0x7570833cu, + 0x533b85dau, 0x9f918544u, 0x111e82a7u, 0xddb48239u, 0xd7718b20u, 0x1bdb8bbeu, 0x95548c5du, 0x59fe8cc3u, + 0x80de9e6fu, 0x4c749ef1u, 0xc2fb9912u, 0x0e51998cu, 0x04949095u, 0xc83e900bu, 0x46b197e8u, 0x8a1b9776u, + 0x2f80b4f1u, 0xe32ab46fu, 0x6da5b38cu, 0xa10fb312u, 0xabcaba0bu, 0x6760ba95u, 0xe9efbd76u, 0x2545bde8u, + 0xfc65af44u, 0x30cfafdau, 0xbe40a839u, 0x72eaa8a7u, 0x782fa1beu, 0xb485a120u, 0x3a0aa6c3u, 0xf6a0a65du, + 0xaa4de78cu, 0x66e7e712u, 0xe868e0f1u, 0x24c2e06fu, 0x2e07e976u, 0xe2ade9e8u, 0x6c22ee0bu, 0xa088ee95u, + 0x79a8fc39u, 0xb502fca7u, 0x3b8dfb44u, 0xf727fbdau, 0xfde2f2c3u, 0x3148f25du, 0xbfc7f5beu, 0x736df520u, + 0xd6f6d6a7u, 0x1a5cd639u, 0x94d3d1dau, 0x5879d144u, 0x52bcd85du, 0x9e16d8c3u, 0x1099df20u, 0xdc33dfbeu, + 0x0513cd12u, 0xc9b9cd8cu, 0x4736ca6fu, 0x8b9ccaf1u, 0x8159c3e8u, 0x4df3c376u, 0xc37cc495u, 0x0fd6c40bu, + 0x7aa64737u, 0xb60c47a9u, 0x3883404au, 0xf42940d4u, 0xfeec49cdu, 0x32464953u, 0xbcc94eb0u, 0x70634e2eu, + 0xa9435c82u, 0x65e95c1cu, 0xeb665bffu, 0x27cc5b61u, 0x2d095278u, 0xe1a352e6u, 0x6f2c5505u, 0xa386559bu, + 0x061d761cu, 0xcab77682u, 0x44387161u, 0x889271ffu, 0x825778e6u, 0x4efd7878u, 0xc0727f9bu, 0x0cd87f05u, + 0xd5f86da9u, 0x19526d37u, 0x97dd6ad4u, 0x5b776a4au, 0x51b26353u, 0x9d1863cdu, 0x1397642eu, 0xdf3d64b0u, + 0x83d02561u, 0x4f7a25ffu, 0xc1f5221cu, 0x0d5f2282u, 0x079a2b9bu, 0xcb302b05u, 0x45bf2ce6u, 0x89152c78u, + 0x50353ed4u, 0x9c9f3e4au, 0x121039a9u, 0xdeba3937u, 0xd47f302eu, 0x18d530b0u, 0x965a3753u, 0x5af037cdu, + 0xff6b144au, 0x33c114d4u, 0xbd4e1337u, 0x71e413a9u, 0x7b211ab0u, 0xb78b1a2eu, 0x39041dcdu, 0xf5ae1d53u, + 0x2c8e0fffu, 0xe0240f61u, 0x6eab0882u, 0xa201081cu, 0xa8c40105u, 0x646e019bu, 0xeae10678u, 0x264b06e6u +}; + +/* Computes the cyclic redundancy check as used by PNG chunks*/ +unsigned lodepng_crc32(const unsigned char* data, size_t length) { + /*Using the Slicing by Eight algorithm*/ + unsigned r = 0xffffffffu; + while(length >= 8) { + r = lodepng_crc32_table7[(data[0] ^ (r & 0xffu))] ^ + lodepng_crc32_table6[(data[1] ^ ((r >> 8) & 0xffu))] ^ + lodepng_crc32_table5[(data[2] ^ ((r >> 16) & 0xffu))] ^ + lodepng_crc32_table4[(data[3] ^ ((r >> 24) & 0xffu))] ^ + lodepng_crc32_table3[data[4]] ^ + lodepng_crc32_table2[data[5]] ^ + lodepng_crc32_table1[data[6]] ^ + lodepng_crc32_table0[data[7]]; + data += 8; + length -= 8; + } + while(length--) { + r = lodepng_crc32_table0[(r ^ *data++) & 0xffu] ^ (r >> 8); + } + return r ^ 0xffffffffu; +} +#else /* LODEPNG_COMPILE_CRC */ +/*in this case, the function is only declared here, and must be defined externally +so that it will be linked in. + +Example implementation that uses a much smaller lookup table for memory constrained cases: + +unsigned lodepng_crc32(const unsigned char* data, size_t length) { + unsigned r = 0xffffffffu; + static const unsigned table[16] = { + 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c + }; + while(length--) { + r = table[(r ^ *data) & 0xf] ^ (r >> 4); + r = table[(r ^ (*data >> 4)) & 0xf] ^ (r >> 4); + data++; + } + return r ^ 0xffffffffu; +} +*/ +unsigned lodepng_crc32(const unsigned char* data, size_t length); +#endif /* LODEPNG_COMPILE_CRC */ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Reading and writing PNG color channel bits / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/* The color channel bits of less-than-8-bit pixels are read with the MSB of bytes first, +so LodePNGBitWriter and LodePNGBitReader can't be used for those. */ + +static unsigned char readBitFromReversedStream(size_t* bitpointer, const unsigned char* bitstream) { + unsigned char result = (unsigned char)((bitstream[(*bitpointer) >> 3] >> (7 - ((*bitpointer) & 0x7))) & 1); + ++(*bitpointer); + return result; +} + +/* TODO: make this faster */ +static unsigned readBitsFromReversedStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits) { + unsigned result = 0; + size_t i; + for(i = 0 ; i < nbits; ++i) { + result <<= 1u; + result |= (unsigned)readBitFromReversedStream(bitpointer, bitstream); + } + return result; +} + +static void setBitOfReversedStream(size_t* bitpointer, unsigned char* bitstream, unsigned char bit) { + /*the current bit in bitstream may be 0 or 1 for this to work*/ + if(bit == 0) bitstream[(*bitpointer) >> 3u] &= (unsigned char)(~(1u << (7u - ((*bitpointer) & 7u)))); + else bitstream[(*bitpointer) >> 3u] |= (1u << (7u - ((*bitpointer) & 7u))); + ++(*bitpointer); +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / PNG chunks / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +unsigned lodepng_chunk_length(const unsigned char* chunk) { + return lodepng_read32bitInt(chunk); +} + +void lodepng_chunk_type(char type[5], const unsigned char* chunk) { + unsigned i; + for(i = 0; i != 4; ++i) type[i] = (char)chunk[4 + i]; + type[4] = 0; /*null termination char*/ +} + +unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type) { + if(lodepng_strlen(type) != 4) return 0; + return (chunk[4] == type[0] && chunk[5] == type[1] && chunk[6] == type[2] && chunk[7] == type[3]); +} + +/* chunk type name must exist only out of alphabetic characters a-z or A-Z */ +static unsigned char lodepng_chunk_type_name_valid(const unsigned char* chunk) { + unsigned i; + for(i = 0; i != 4; ++i) { + char c = (char)chunk[4 + i]; + if(!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) { + return 0; /* not valid */ + } + } + return 1; /* valid */ +} + +unsigned char lodepng_chunk_ancillary(const unsigned char* chunk) { + return((chunk[4] & 32) != 0); +} + +unsigned char lodepng_chunk_private(const unsigned char* chunk) { + return((chunk[5] & 32) != 0); +} + +/* this is an error if it is reserved: the third character must be uppercase in the PNG standard, +lowercasing this character is reserved for possible future extension by the spec*/ +static unsigned char lodepng_chunk_reserved(const unsigned char* chunk) { + return((chunk[6] & 32) != 0); +} + +unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk) { + return((chunk[7] & 32) != 0); +} + +unsigned char* lodepng_chunk_data(unsigned char* chunk) { + return &chunk[8]; +} + +const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk) { + return &chunk[8]; +} + +unsigned lodepng_chunk_check_crc(const unsigned char* chunk) { + unsigned length = lodepng_chunk_length(chunk); + unsigned crc = lodepng_read32bitInt(&chunk[length + 8]); + /*the CRC is taken of the data and the 4 chunk type letters, not the length*/ + unsigned checksum = lodepng_crc32(&chunk[4], length + 4); + if(crc != checksum) return 1; + else return 0; +} + +void lodepng_chunk_generate_crc(unsigned char* chunk) { + unsigned length = lodepng_chunk_length(chunk); + unsigned crc = lodepng_crc32(&chunk[4], length + 4); + lodepng_set32bitInt(chunk + 8 + length, crc); +} + +unsigned char* lodepng_chunk_next(unsigned char* chunk, unsigned char* end) { + size_t available_size = (size_t)(end - chunk); + if(chunk >= end || available_size < 12) return end; /*too small to contain a chunk*/ + if(chunk[0] == 0x89 && chunk[1] == 0x50 && chunk[2] == 0x4e && chunk[3] == 0x47 + && chunk[4] == 0x0d && chunk[5] == 0x0a && chunk[6] == 0x1a && chunk[7] == 0x0a) { + /* Is PNG magic header at start of PNG file. Jump to first actual chunk. */ + return chunk + 8; + } else { + size_t total_chunk_length; + if(lodepng_addofl(lodepng_chunk_length(chunk), 12, &total_chunk_length)) return end; + if(total_chunk_length > available_size) return end; /*outside of range*/ + return chunk + total_chunk_length; + } +} + +const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk, const unsigned char* end) { + size_t available_size = (size_t)(end - chunk); + if(chunk >= end || available_size < 12) return end; /*too small to contain a chunk*/ + if(chunk[0] == 0x89 && chunk[1] == 0x50 && chunk[2] == 0x4e && chunk[3] == 0x47 + && chunk[4] == 0x0d && chunk[5] == 0x0a && chunk[6] == 0x1a && chunk[7] == 0x0a) { + /* Is PNG magic header at start of PNG file. Jump to first actual chunk. */ + return chunk + 8; + } else { + size_t total_chunk_length; + if(lodepng_addofl(lodepng_chunk_length(chunk), 12, &total_chunk_length)) return end; + if(total_chunk_length > available_size) return end; /*outside of range*/ + return chunk + total_chunk_length; + } +} + +unsigned char* lodepng_chunk_find(unsigned char* chunk, unsigned char* end, const char type[5]) { + for(;;) { + if(chunk >= end || end - chunk < 12) return 0; /* past file end: chunk + 12 > end */ + if(lodepng_chunk_type_equals(chunk, type)) return chunk; + chunk = lodepng_chunk_next(chunk, end); + } +} + +const unsigned char* lodepng_chunk_find_const(const unsigned char* chunk, const unsigned char* end, const char type[5]) { + for(;;) { + if(chunk >= end || end - chunk < 12) return 0; /* past file end: chunk + 12 > end */ + if(lodepng_chunk_type_equals(chunk, type)) return chunk; + chunk = lodepng_chunk_next_const(chunk, end); + } +} + +unsigned lodepng_chunk_append(unsigned char** out, size_t* outsize, const unsigned char* chunk) { + unsigned i; + size_t total_chunk_length, new_length; + unsigned char *chunk_start, *new_buffer; + + if(!lodepng_chunk_type_name_valid(chunk)) { + return 121; /* invalid chunk type name */ + } + if(lodepng_chunk_reserved(chunk)) { + return 122; /* invalid third lowercase character */ + } + + if(lodepng_addofl(lodepng_chunk_length(chunk), 12, &total_chunk_length)) return 77; + if(lodepng_addofl(*outsize, total_chunk_length, &new_length)) return 77; + + new_buffer = (unsigned char*)lodepng_realloc(*out, new_length); + if(!new_buffer) return 83; /*alloc fail*/ + (*out) = new_buffer; + (*outsize) = new_length; + chunk_start = &(*out)[new_length - total_chunk_length]; + + for(i = 0; i != total_chunk_length; ++i) chunk_start[i] = chunk[i]; + + return 0; +} + +/*Sets length and name and allocates the space for data and crc but does not +set data or crc yet. Returns the start of the chunk in chunk. The start of +the data is at chunk + 8. To finalize chunk, add the data, then use +lodepng_chunk_generate_crc */ +static unsigned lodepng_chunk_init(unsigned char** chunk, + ucvector* out, + size_t length, const char* type) { + size_t new_length = out->size; + if(lodepng_addofl(new_length, length, &new_length)) return 77; + if(lodepng_addofl(new_length, 12, &new_length)) return 77; + if(!ucvector_resize(out, new_length)) return 83; /*alloc fail*/ + *chunk = out->data + new_length - length - 12u; + + /*1: length*/ + lodepng_set32bitInt(*chunk, (unsigned)length); + + /*2: chunk name (4 letters)*/ + lodepng_memcpy(*chunk + 4, type, 4); + + return 0; +} + +/* like lodepng_chunk_create but with custom allocsize */ +static unsigned lodepng_chunk_createv(ucvector* out, + size_t length, const char* type, const unsigned char* data) { + unsigned char* chunk; + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, length, type)); + + /*3: the data*/ + lodepng_memcpy(chunk + 8, data, length); + + /*4: CRC (of the chunkname characters and the data)*/ + lodepng_chunk_generate_crc(chunk); + + return 0; +} + +unsigned lodepng_chunk_create(unsigned char** out, size_t* outsize, + size_t length, const char* type, const unsigned char* data) { + ucvector v = ucvector_init(*out, *outsize); + unsigned error = lodepng_chunk_createv(&v, length, type, data); + *out = v.data; + *outsize = v.size; + return error; +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Color types, channels, bits / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*checks if the colortype is valid and the bitdepth bd is allowed for this colortype. +Return value is a LodePNG error code.*/ +static unsigned checkColorValidity(LodePNGColorType colortype, unsigned bd) { + switch(colortype) { + case LCT_GREY: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16)) return 37; break; + case LCT_RGB: if(!( bd == 8 || bd == 16)) return 37; break; + case LCT_PALETTE: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 )) return 37; break; + case LCT_GREY_ALPHA: if(!( bd == 8 || bd == 16)) return 37; break; + case LCT_RGBA: if(!( bd == 8 || bd == 16)) return 37; break; + case LCT_MAX_OCTET_VALUE: return 31; /* invalid color type */ + default: return 31; /* invalid color type */ + } + return 0; /*allowed color type / bits combination*/ +} + +static unsigned getNumColorChannels(LodePNGColorType colortype) { + switch(colortype) { + case LCT_GREY: return 1; + case LCT_RGB: return 3; + case LCT_PALETTE: return 1; + case LCT_GREY_ALPHA: return 2; + case LCT_RGBA: return 4; + case LCT_MAX_OCTET_VALUE: return 0; /* invalid color type */ + default: return 0; /*invalid color type*/ + } +} + +static unsigned lodepng_get_bpp_lct(LodePNGColorType colortype, unsigned bitdepth) { + /*bits per pixel is amount of channels * bits per channel*/ + return getNumColorChannels(colortype) * bitdepth; +} + +/* ////////////////////////////////////////////////////////////////////////// */ + +void lodepng_color_mode_init(LodePNGColorMode* info) { + info->key_defined = 0; + info->key_r = info->key_g = info->key_b = 0; + info->colortype = LCT_RGBA; + info->bitdepth = 8; + info->palette = 0; + info->palettesize = 0; +} + +/*allocates palette memory if needed, and initializes all colors to black*/ +static void lodepng_color_mode_alloc_palette(LodePNGColorMode* info) { + size_t i; + /*if the palette is already allocated, it will have size 1024 so no reallocation needed in that case*/ + /*the palette must have room for up to 256 colors with 4 bytes each.*/ + if(!info->palette) info->palette = (unsigned char*)lodepng_malloc(1024); + if(!info->palette) return; /*alloc fail*/ + for(i = 0; i != 256; ++i) { + /*Initialize all unused colors with black, the value used for invalid palette indices. + This is an error according to the PNG spec, but common PNG decoders make it black instead. + That makes color conversion slightly faster due to no error handling needed.*/ + info->palette[i * 4 + 0] = 0; + info->palette[i * 4 + 1] = 0; + info->palette[i * 4 + 2] = 0; + info->palette[i * 4 + 3] = 255; + } +} + +void lodepng_color_mode_cleanup(LodePNGColorMode* info) { + lodepng_palette_clear(info); +} + +unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source) { + lodepng_color_mode_cleanup(dest); + lodepng_memcpy(dest, source, sizeof(LodePNGColorMode)); + if(source->palette) { + dest->palette = (unsigned char*)lodepng_malloc(1024); + if(!dest->palette && source->palettesize) return 83; /*alloc fail*/ + lodepng_memcpy(dest->palette, source->palette, source->palettesize * 4); + } + return 0; +} + +LodePNGColorMode lodepng_color_mode_make(LodePNGColorType colortype, unsigned bitdepth) { + LodePNGColorMode result; + lodepng_color_mode_init(&result); + result.colortype = colortype; + result.bitdepth = bitdepth; + return result; +} + +static int lodepng_color_mode_equal(const LodePNGColorMode* a, const LodePNGColorMode* b) { + size_t i; + if(a->colortype != b->colortype) return 0; + if(a->bitdepth != b->bitdepth) return 0; + if(a->key_defined != b->key_defined) return 0; + if(a->key_defined) { + if(a->key_r != b->key_r) return 0; + if(a->key_g != b->key_g) return 0; + if(a->key_b != b->key_b) return 0; + } + if(a->palettesize != b->palettesize) return 0; + for(i = 0; i != a->palettesize * 4; ++i) { + if(a->palette[i] != b->palette[i]) return 0; + } + return 1; +} + +void lodepng_palette_clear(LodePNGColorMode* info) { + if(info->palette) lodepng_free(info->palette); + info->palette = 0; + info->palettesize = 0; +} + +unsigned lodepng_palette_add(LodePNGColorMode* info, + unsigned char r, unsigned char g, unsigned char b, unsigned char a) { + if(!info->palette) /*allocate palette if empty*/ { + lodepng_color_mode_alloc_palette(info); + if(!info->palette) return 83; /*alloc fail*/ + } + if(info->palettesize >= 256) { + return 108; /*too many palette values*/ + } + info->palette[4 * info->palettesize + 0] = r; + info->palette[4 * info->palettesize + 1] = g; + info->palette[4 * info->palettesize + 2] = b; + info->palette[4 * info->palettesize + 3] = a; + ++info->palettesize; + return 0; +} + +/*calculate bits per pixel out of colortype and bitdepth*/ +unsigned lodepng_get_bpp(const LodePNGColorMode* info) { + return lodepng_get_bpp_lct(info->colortype, info->bitdepth); +} + +unsigned lodepng_get_channels(const LodePNGColorMode* info) { + return getNumColorChannels(info->colortype); +} + +unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info) { + return info->colortype == LCT_GREY || info->colortype == LCT_GREY_ALPHA; +} + +unsigned lodepng_is_alpha_type(const LodePNGColorMode* info) { + return (info->colortype & 4) != 0; /*4 or 6*/ +} + +unsigned lodepng_is_palette_type(const LodePNGColorMode* info) { + return info->colortype == LCT_PALETTE; +} + +unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info) { + size_t i; + for(i = 0; i != info->palettesize; ++i) { + if(info->palette[i * 4 + 3] < 255) return 1; + } + return 0; +} + +unsigned lodepng_can_have_alpha(const LodePNGColorMode* info) { + return info->key_defined + || lodepng_is_alpha_type(info) + || lodepng_has_palette_alpha(info); +} + +static size_t lodepng_get_raw_size_lct(unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) { + size_t bpp = lodepng_get_bpp_lct(colortype, bitdepth); + size_t n = (size_t)w * (size_t)h; + return ((n / 8u) * bpp) + ((n & 7u) * bpp + 7u) / 8u; +} + +size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color) { + return lodepng_get_raw_size_lct(w, h, color->colortype, color->bitdepth); +} + + +#ifdef LODEPNG_COMPILE_PNG + +/*in an idat chunk, each scanline is a multiple of 8 bits, unlike the lodepng output buffer, +and in addition has one extra byte per line: the filter byte. So this gives a larger +result than lodepng_get_raw_size. Set h to 1 to get the size of 1 row including filter byte. */ +static size_t lodepng_get_raw_size_idat(unsigned w, unsigned h, unsigned bpp) { + /* + 1 for the filter byte, and possibly plus padding bits per line. */ + /* Ignoring casts, the expression is equal to (w * bpp + 7) / 8 + 1, but avoids overflow of w * bpp */ + size_t line = ((size_t)(w / 8u) * bpp) + 1u + ((w & 7u) * bpp + 7u) / 8u; + return (size_t)h * line; +} + +#ifdef LODEPNG_COMPILE_DECODER +/*Safely checks whether size_t overflow can be caused due to amount of pixels. +This check is overcautious rather than precise. If this check indicates no overflow, +you can safely compute in a size_t (but not an unsigned): +-(size_t)w * (size_t)h * 8 +-amount of bytes in IDAT (including filter, padding and Adam7 bytes) +-amount of bytes in raw color model +Returns 1 if overflow possible, 0 if not. +*/ +static int lodepng_pixel_overflow(unsigned w, unsigned h, + const LodePNGColorMode* pngcolor, const LodePNGColorMode* rawcolor) { + size_t bpp = LODEPNG_MAX(lodepng_get_bpp(pngcolor), lodepng_get_bpp(rawcolor)); + size_t numpixels, total; + size_t line; /* bytes per line in worst case */ + + if(lodepng_mulofl((size_t)w, (size_t)h, &numpixels)) return 1; + if(lodepng_mulofl(numpixels, 8, &total)) return 1; /* bit pointer with 8-bit color, or 8 bytes per channel color */ + + /* Bytes per scanline with the expression "(w / 8u) * bpp) + ((w & 7u) * bpp + 7u) / 8u" */ + if(lodepng_mulofl((size_t)(w / 8u), bpp, &line)) return 1; + if(lodepng_addofl(line, ((w & 7u) * bpp + 7u) / 8u, &line)) return 1; + + if(lodepng_addofl(line, 5, &line)) return 1; /* 5 bytes overhead per line: 1 filterbyte, 4 for Adam7 worst case */ + if(lodepng_mulofl(line, h, &total)) return 1; /* Total bytes in worst case */ + + return 0; /* no overflow */ +} +#endif /*LODEPNG_COMPILE_DECODER*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + +static void LodePNGUnknownChunks_init(LodePNGInfo* info) { + unsigned i; + for(i = 0; i != 3; ++i) info->unknown_chunks_data[i] = 0; + for(i = 0; i != 3; ++i) info->unknown_chunks_size[i] = 0; +} + +static void LodePNGUnknownChunks_cleanup(LodePNGInfo* info) { + unsigned i; + for(i = 0; i != 3; ++i) lodepng_free(info->unknown_chunks_data[i]); +} + +static unsigned LodePNGUnknownChunks_copy(LodePNGInfo* dest, const LodePNGInfo* src) { + unsigned i; + + LodePNGUnknownChunks_cleanup(dest); + + for(i = 0; i != 3; ++i) { + size_t j; + dest->unknown_chunks_size[i] = src->unknown_chunks_size[i]; + dest->unknown_chunks_data[i] = (unsigned char*)lodepng_malloc(src->unknown_chunks_size[i]); + if(!dest->unknown_chunks_data[i] && dest->unknown_chunks_size[i]) return 83; /*alloc fail*/ + for(j = 0; j < src->unknown_chunks_size[i]; ++j) { + dest->unknown_chunks_data[i][j] = src->unknown_chunks_data[i][j]; + } + } + + return 0; +} + +/******************************************************************************/ + +static void LodePNGText_init(LodePNGInfo* info) { + info->text_num = 0; + info->text_keys = NULL; + info->text_strings = NULL; +} + +static void LodePNGText_cleanup(LodePNGInfo* info) { + size_t i; + for(i = 0; i != info->text_num; ++i) { + lodepng_free(info->text_keys[i]); + lodepng_free(info->text_strings[i]); + } + lodepng_free(info->text_keys); + lodepng_free(info->text_strings); +} + +static unsigned LodePNGText_copy(LodePNGInfo* dest, const LodePNGInfo* source) { + size_t i = 0; + dest->text_keys = NULL; + dest->text_strings = NULL; + dest->text_num = 0; + for(i = 0; i != source->text_num; ++i) { + CERROR_TRY_RETURN(lodepng_add_text(dest, source->text_keys[i], source->text_strings[i])); + } + return 0; +} + +static unsigned lodepng_add_text_sized(LodePNGInfo* info, const char* key, const char* str, size_t size) { + char** new_keys = (char**)(lodepng_realloc(info->text_keys, sizeof(char*) * (info->text_num + 1))); + char** new_strings = (char**)(lodepng_realloc(info->text_strings, sizeof(char*) * (info->text_num + 1))); + + if(new_keys) info->text_keys = new_keys; + if(new_strings) info->text_strings = new_strings; + + if(!new_keys || !new_strings) return 83; /*alloc fail*/ + + ++info->text_num; + info->text_keys[info->text_num - 1] = alloc_string(key); + info->text_strings[info->text_num - 1] = alloc_string_sized(str, size); + if(!info->text_keys[info->text_num - 1] || !info->text_strings[info->text_num - 1]) return 83; /*alloc fail*/ + + return 0; +} + +unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str) { + return lodepng_add_text_sized(info, key, str, lodepng_strlen(str)); +} + +void lodepng_clear_text(LodePNGInfo* info) { + LodePNGText_cleanup(info); + /*cleanup only deconstructs, need to init again to set appropriate pointers to NULL*/ + LodePNGText_init(info); +} + +/******************************************************************************/ + +static void LodePNGIText_init(LodePNGInfo* info) { + info->itext_num = 0; + info->itext_keys = NULL; + info->itext_langtags = NULL; + info->itext_transkeys = NULL; + info->itext_strings = NULL; +} + +static void LodePNGIText_cleanup(LodePNGInfo* info) { + size_t i; + for(i = 0; i != info->itext_num; ++i) { + lodepng_free(info->itext_keys[i]); + lodepng_free(info->itext_langtags[i]); + lodepng_free(info->itext_transkeys[i]); + lodepng_free(info->itext_strings[i]); + } + lodepng_free(info->itext_keys); + lodepng_free(info->itext_langtags); + lodepng_free(info->itext_transkeys); + lodepng_free(info->itext_strings); +} + +static unsigned LodePNGIText_copy(LodePNGInfo* dest, const LodePNGInfo* source) { + size_t i = 0; + dest->itext_keys = NULL; + dest->itext_langtags = NULL; + dest->itext_transkeys = NULL; + dest->itext_strings = NULL; + dest->itext_num = 0; + for(i = 0; i != source->itext_num; ++i) { + CERROR_TRY_RETURN(lodepng_add_itext(dest, source->itext_keys[i], source->itext_langtags[i], + source->itext_transkeys[i], source->itext_strings[i])); + } + return 0; +} + +void lodepng_clear_itext(LodePNGInfo* info) { + LodePNGIText_cleanup(info); + /*cleanup only deconstructs, need to init again to set appropriate pointers to NULL*/ + LodePNGIText_init(info); +} + +static unsigned lodepng_add_itext_sized(LodePNGInfo* info, const char* key, const char* langtag, + const char* transkey, const char* str, size_t size) { + char** new_keys = (char**)(lodepng_realloc(info->itext_keys, sizeof(char*) * (info->itext_num + 1))); + char** new_langtags = (char**)(lodepng_realloc(info->itext_langtags, sizeof(char*) * (info->itext_num + 1))); + char** new_transkeys = (char**)(lodepng_realloc(info->itext_transkeys, sizeof(char*) * (info->itext_num + 1))); + char** new_strings = (char**)(lodepng_realloc(info->itext_strings, sizeof(char*) * (info->itext_num + 1))); + + if(new_keys) info->itext_keys = new_keys; + if(new_langtags) info->itext_langtags = new_langtags; + if(new_transkeys) info->itext_transkeys = new_transkeys; + if(new_strings) info->itext_strings = new_strings; + + if(!new_keys || !new_langtags || !new_transkeys || !new_strings) return 83; /*alloc fail*/ + + ++info->itext_num; + + info->itext_keys[info->itext_num - 1] = alloc_string(key); + info->itext_langtags[info->itext_num - 1] = alloc_string(langtag); + info->itext_transkeys[info->itext_num - 1] = alloc_string(transkey); + info->itext_strings[info->itext_num - 1] = alloc_string_sized(str, size); + + return 0; +} + +unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag, + const char* transkey, const char* str) { + return lodepng_add_itext_sized(info, key, langtag, transkey, str, lodepng_strlen(str)); +} + +unsigned lodepng_set_icc(LodePNGInfo* info, const char* name, const unsigned char* profile, unsigned profile_size) { + if(info->iccp_defined) lodepng_clear_icc(info); + + if(profile_size == 0) return 123; /*invalid ICC profile size*/ + + info->iccp_name = alloc_string(name); + if(!info->iccp_name) return 83; /*alloc fail*/ + + info->iccp_profile = (unsigned char*)lodepng_malloc(profile_size); + if(!info->iccp_profile) { + lodepng_free(info->iccp_name); + return 83; /*alloc fail*/ + } + + lodepng_memcpy(info->iccp_profile, profile, profile_size); + info->iccp_profile_size = profile_size; + info->iccp_defined = 1; + + return 0; /*ok*/ +} + +static void lodepng_init_icc(LodePNGInfo* info) { + info->iccp_defined = 0; + info->iccp_name = NULL; + info->iccp_profile = NULL; + info->iccp_profile_size = 0; +} + +void lodepng_clear_icc(LodePNGInfo* info) { + lodepng_free(info->iccp_name); + lodepng_free(info->iccp_profile); + lodepng_init_icc(info); +} + +unsigned lodepng_set_exif(LodePNGInfo* info, const unsigned char* exif, unsigned exif_size) { + if(info->exif_defined) lodepng_clear_exif(info); + info->exif = (unsigned char*)lodepng_malloc(exif_size); + + if(!info->exif) return 83; /*alloc fail*/ + + lodepng_memcpy(info->exif, exif, exif_size); + info->exif_size = exif_size; + info->exif_defined = 1; + + return 0; /*ok*/ +} + +static void lodepng_init_exif(LodePNGInfo* info) { + info->exif_defined = 0; + info->exif = NULL; + info->exif_size = 0; +} + +void lodepng_clear_exif(LodePNGInfo* info) { + lodepng_free(info->exif); + lodepng_init_exif(info); +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +void lodepng_info_init(LodePNGInfo* info) { + lodepng_color_mode_init(&info->color); + info->interlace_method = 0; + info->compression_method = 0; + info->filter_method = 0; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + info->background_defined = 0; + info->background_r = info->background_g = info->background_b = 0; + + LodePNGText_init(info); + LodePNGIText_init(info); + lodepng_init_icc(info); + lodepng_init_exif(info); + + info->time_defined = 0; + info->phys_defined = 0; + + info->gama_defined = 0; + info->chrm_defined = 0; + info->srgb_defined = 0; + info->cicp_defined = 0; + info->cicp_color_primaries = 0; + info->cicp_transfer_function = 0; + info->cicp_matrix_coefficients = 0; + info->cicp_video_full_range_flag = 0; + info->mdcv_defined = 0; + info->mdcv_red_x = 0; + info->mdcv_red_y = 0; + info->mdcv_green_x = 0; + info->mdcv_green_y = 0; + info->mdcv_blue_x = 0; + info->mdcv_blue_y = 0; + info->mdcv_white_x = 0; + info->mdcv_white_y = 0; + info->mdcv_max_luminance = 0; + info->mdcv_min_luminance = 0; + info->clli_defined = 0; + info->clli_max_cll = 0; + info->clli_max_fall = 0; + + info->sbit_defined = 0; + info->sbit_r = info->sbit_g = info->sbit_b = info->sbit_a = 0; + + LodePNGUnknownChunks_init(info); +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} + +void lodepng_info_cleanup(LodePNGInfo* info) { + lodepng_color_mode_cleanup(&info->color); +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + LodePNGText_cleanup(info); + LodePNGIText_cleanup(info); + + lodepng_clear_icc(info); + lodepng_clear_exif(info); + + LodePNGUnknownChunks_cleanup(info); +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} + +unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source) { + lodepng_info_cleanup(dest); + lodepng_memcpy(dest, source, sizeof(LodePNGInfo)); + + /*ensure to initialize all fields pointing to allocated data to NULL first*/ + lodepng_color_mode_init(&dest->color); +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + LodePNGText_init(dest); + LodePNGIText_init(dest); + lodepng_init_icc(dest); + lodepng_init_exif(dest); + LodePNGUnknownChunks_init(dest); +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + + CERROR_TRY_RETURN(lodepng_color_mode_copy(&dest->color, &source->color)); +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + CERROR_TRY_RETURN(LodePNGText_copy(dest, source)); + CERROR_TRY_RETURN(LodePNGIText_copy(dest, source)); + if(source->iccp_defined) { + CERROR_TRY_RETURN(lodepng_set_icc(dest, source->iccp_name, source->iccp_profile, source->iccp_profile_size)); + } + if(source->exif_defined) { + CERROR_TRY_RETURN(lodepng_set_exif(dest, source->exif, source->exif_size)); + } + CERROR_TRY_RETURN(LodePNGUnknownChunks_copy(dest, source)); +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + + return 0; +} + +/* ////////////////////////////////////////////////////////////////////////// */ + +/*index: bitgroup index, bits: bitgroup size(1, 2 or 4), in: bitgroup value, out: octet array to add bits to*/ +static void addColorBits(unsigned char* out, size_t index, unsigned bits, unsigned in) { + unsigned m = bits == 1 ? 7 : bits == 2 ? 3 : 1; /*8 / bits - 1*/ + /*p = the partial index in the byte, e.g. with 4 palettebits it is 0 for first half or 1 for second half*/ + unsigned p = index & m; + in &= (1u << bits) - 1u; /*filter out any other bits of the input value*/ + in = in << (bits * (m - p)); + if(p == 0) out[index * bits / 8u] = in; + else out[index * bits / 8u] |= in; +} + +typedef struct ColorTree ColorTree; + +/* +One node of a color tree +This is the data structure used to count the number of unique colors and to get a palette +index for a color. It's like an octree, but because the alpha channel is used too, each +node has 16 instead of 8 children. +*/ +struct ColorTree { + ColorTree* children[16]; /*up to 16 pointers to ColorTree of next level*/ + int index; /*the payload. Only has a meaningful value if this is in the last level*/ +}; + +static void color_tree_init(ColorTree* tree) { + lodepng_memset(tree->children, 0, 16 * sizeof(*tree->children)); + tree->index = -1; +} + +static void color_tree_cleanup(ColorTree* tree) { + int i; + for(i = 0; i != 16; ++i) { + if(tree->children[i]) { + color_tree_cleanup(tree->children[i]); + lodepng_free(tree->children[i]); + } + } +} + +/*returns -1 if color not present, its index otherwise*/ +static int color_tree_get(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { + int bit = 0; + for(bit = 0; bit < 8; ++bit) { + int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1); + if(!tree->children[i]) return -1; + else tree = tree->children[i]; + } + return tree ? tree->index : -1; +} + +#ifdef LODEPNG_COMPILE_ENCODER +static int color_tree_has(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a) { + return color_tree_get(tree, r, g, b, a) >= 0; +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/*color is not allowed to already exist. +Index should be >= 0 (it's signed to be compatible with using -1 for "doesn't exist") +Returns error code, or 0 if ok*/ +static unsigned color_tree_add(ColorTree* tree, + unsigned char r, unsigned char g, unsigned char b, unsigned char a, unsigned index) { + int bit; + for(bit = 0; bit < 8; ++bit) { + int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1); + if(!tree->children[i]) { + tree->children[i] = (ColorTree*)lodepng_malloc(sizeof(ColorTree)); + if(!tree->children[i]) return 83; /*alloc fail*/ + color_tree_init(tree->children[i]); + } + tree = tree->children[i]; + } + tree->index = (int)index; + return 0; +} + +/*put a pixel, given its RGBA color, into image of any color type*/ +static unsigned rgba8ToPixel(unsigned char* out, size_t i, + const LodePNGColorMode* mode, ColorTree* tree /*for palette*/, + unsigned char r, unsigned char g, unsigned char b, unsigned char a) { + if(mode->colortype == LCT_GREY) { + unsigned char gray = r; /*((unsigned short)r + g + b) / 3u;*/ + if(mode->bitdepth == 8) out[i] = gray; + else if(mode->bitdepth == 16) out[i * 2 + 0] = out[i * 2 + 1] = gray; + else { + /*take the most significant bits of gray*/ + gray = ((unsigned)gray >> (8u - mode->bitdepth)) & ((1u << mode->bitdepth) - 1u); + addColorBits(out, i, mode->bitdepth, gray); + } + } else if(mode->colortype == LCT_RGB) { + if(mode->bitdepth == 8) { + out[i * 3 + 0] = r; + out[i * 3 + 1] = g; + out[i * 3 + 2] = b; + } else { + out[i * 6 + 0] = out[i * 6 + 1] = r; + out[i * 6 + 2] = out[i * 6 + 3] = g; + out[i * 6 + 4] = out[i * 6 + 5] = b; + } + } else if(mode->colortype == LCT_PALETTE) { + int index = color_tree_get(tree, r, g, b, a); + if(index < 0) return 82; /*color not in palette*/ + if(mode->bitdepth == 8) out[i] = index; + else addColorBits(out, i, mode->bitdepth, (unsigned)index); + } else if(mode->colortype == LCT_GREY_ALPHA) { + unsigned char gray = r; /*((unsigned short)r + g + b) / 3u;*/ + if(mode->bitdepth == 8) { + out[i * 2 + 0] = gray; + out[i * 2 + 1] = a; + } else if(mode->bitdepth == 16) { + out[i * 4 + 0] = out[i * 4 + 1] = gray; + out[i * 4 + 2] = out[i * 4 + 3] = a; + } + } else if(mode->colortype == LCT_RGBA) { + if(mode->bitdepth == 8) { + out[i * 4 + 0] = r; + out[i * 4 + 1] = g; + out[i * 4 + 2] = b; + out[i * 4 + 3] = a; + } else { + out[i * 8 + 0] = out[i * 8 + 1] = r; + out[i * 8 + 2] = out[i * 8 + 3] = g; + out[i * 8 + 4] = out[i * 8 + 5] = b; + out[i * 8 + 6] = out[i * 8 + 7] = a; + } + } + + return 0; /*no error*/ +} + +/*put a pixel, given its RGBA16 color, into image of any color 16-bitdepth type*/ +static void rgba16ToPixel(unsigned char* out, size_t i, + const LodePNGColorMode* mode, + unsigned short r, unsigned short g, unsigned short b, unsigned short a) { + if(mode->colortype == LCT_GREY) { + unsigned short gray = r; /*((unsigned)r + g + b) / 3u;*/ + out[i * 2 + 0] = (gray >> 8) & 255; + out[i * 2 + 1] = gray & 255; + } else if(mode->colortype == LCT_RGB) { + out[i * 6 + 0] = (r >> 8) & 255; + out[i * 6 + 1] = r & 255; + out[i * 6 + 2] = (g >> 8) & 255; + out[i * 6 + 3] = g & 255; + out[i * 6 + 4] = (b >> 8) & 255; + out[i * 6 + 5] = b & 255; + } else if(mode->colortype == LCT_GREY_ALPHA) { + unsigned short gray = r; /*((unsigned)r + g + b) / 3u;*/ + out[i * 4 + 0] = (gray >> 8) & 255; + out[i * 4 + 1] = gray & 255; + out[i * 4 + 2] = (a >> 8) & 255; + out[i * 4 + 3] = a & 255; + } else if(mode->colortype == LCT_RGBA) { + out[i * 8 + 0] = (r >> 8) & 255; + out[i * 8 + 1] = r & 255; + out[i * 8 + 2] = (g >> 8) & 255; + out[i * 8 + 3] = g & 255; + out[i * 8 + 4] = (b >> 8) & 255; + out[i * 8 + 5] = b & 255; + out[i * 8 + 6] = (a >> 8) & 255; + out[i * 8 + 7] = a & 255; + } +} + +/*Get RGBA8 color of pixel with index i (y * width + x) from the raw image with given color type.*/ +static void getPixelColorRGBA8(unsigned char* r, unsigned char* g, + unsigned char* b, unsigned char* a, + const unsigned char* in, size_t i, + const LodePNGColorMode* mode) { + if(mode->colortype == LCT_GREY) { + if(mode->bitdepth == 8) { + *r = *g = *b = in[i]; + if(mode->key_defined && *r == mode->key_r) *a = 0; + else *a = 255; + } else if(mode->bitdepth == 16) { + *r = *g = *b = in[i * 2 + 0]; + if(mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0; + else *a = 255; + } else { + unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/ + size_t j = i * mode->bitdepth; + unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth); + *r = *g = *b = (value * 255) / highest; + if(mode->key_defined && value == mode->key_r) *a = 0; + else *a = 255; + } + } else if(mode->colortype == LCT_RGB) { + if(mode->bitdepth == 8) { + *r = in[i * 3 + 0]; *g = in[i * 3 + 1]; *b = in[i * 3 + 2]; + if(mode->key_defined && *r == mode->key_r && *g == mode->key_g && *b == mode->key_b) *a = 0; + else *a = 255; + } else { + *r = in[i * 6 + 0]; + *g = in[i * 6 + 2]; + *b = in[i * 6 + 4]; + if(mode->key_defined && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r + && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g + && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0; + else *a = 255; + } + } else if(mode->colortype == LCT_PALETTE) { + unsigned index; + if(mode->bitdepth == 8) index = in[i]; + else { + size_t j = i * mode->bitdepth; + index = readBitsFromReversedStream(&j, in, mode->bitdepth); + } + /*out of bounds of palette not checked: see lodepng_color_mode_alloc_palette.*/ + *r = mode->palette[index * 4 + 0]; + *g = mode->palette[index * 4 + 1]; + *b = mode->palette[index * 4 + 2]; + *a = mode->palette[index * 4 + 3]; + } else if(mode->colortype == LCT_GREY_ALPHA) { + if(mode->bitdepth == 8) { + *r = *g = *b = in[i * 2 + 0]; + *a = in[i * 2 + 1]; + } else { + *r = *g = *b = in[i * 4 + 0]; + *a = in[i * 4 + 2]; + } + } else if(mode->colortype == LCT_RGBA) { + if(mode->bitdepth == 8) { + *r = in[i * 4 + 0]; + *g = in[i * 4 + 1]; + *b = in[i * 4 + 2]; + *a = in[i * 4 + 3]; + } else { + *r = in[i * 8 + 0]; + *g = in[i * 8 + 2]; + *b = in[i * 8 + 4]; + *a = in[i * 8 + 6]; + } + } +} + +/*Similar to getPixelColorRGBA8, but with all the for loops inside of the color +mode test cases, optimized to convert the colors much faster, when converting +to the common case of RGBA with 8 bit per channel. buffer must be RGBA with +enough memory.*/ +static void getPixelColorsRGBA8(unsigned char* LODEPNG_RESTRICT buffer, size_t numpixels, + const unsigned char* LODEPNG_RESTRICT in, + const LodePNGColorMode* mode) { + unsigned num_channels = 4; + size_t i; + if(mode->colortype == LCT_GREY) { + if(mode->bitdepth == 8) { + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + buffer[0] = buffer[1] = buffer[2] = in[i]; + buffer[3] = 255; + } + if(mode->key_defined) { + buffer -= numpixels * num_channels; + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + if(buffer[0] == mode->key_r) buffer[3] = 0; + } + } + } else if(mode->bitdepth == 16) { + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + buffer[0] = buffer[1] = buffer[2] = in[i * 2]; + buffer[3] = mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r ? 0 : 255; + } + } else { + unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/ + size_t j = 0; + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth); + buffer[0] = buffer[1] = buffer[2] = (value * 255) / highest; + buffer[3] = mode->key_defined && value == mode->key_r ? 0 : 255; + } + } + } else if(mode->colortype == LCT_RGB) { + if(mode->bitdepth == 8) { + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + lodepng_memcpy(buffer, &in[i * 3], 3); + buffer[3] = 255; + } + if(mode->key_defined) { + buffer -= numpixels * num_channels; + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + if(buffer[0] == mode->key_r && buffer[1]== mode->key_g && buffer[2] == mode->key_b) buffer[3] = 0; + } + } + } else { + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + buffer[0] = in[i * 6 + 0]; + buffer[1] = in[i * 6 + 2]; + buffer[2] = in[i * 6 + 4]; + buffer[3] = mode->key_defined + && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r + && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g + && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b ? 0 : 255; + } + } + } else if(mode->colortype == LCT_PALETTE) { + if(mode->bitdepth == 8) { + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + unsigned index = in[i]; + /*out of bounds of palette not checked: see lodepng_color_mode_alloc_palette.*/ + lodepng_memcpy(buffer, &mode->palette[index * 4], 4); + } + } else { + size_t j = 0; + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + unsigned index = readBitsFromReversedStream(&j, in, mode->bitdepth); + /*out of bounds of palette not checked: see lodepng_color_mode_alloc_palette.*/ + lodepng_memcpy(buffer, &mode->palette[index * 4], 4); + } + } + } else if(mode->colortype == LCT_GREY_ALPHA) { + if(mode->bitdepth == 8) { + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + buffer[0] = buffer[1] = buffer[2] = in[i * 2 + 0]; + buffer[3] = in[i * 2 + 1]; + } + } else { + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + buffer[0] = buffer[1] = buffer[2] = in[i * 4 + 0]; + buffer[3] = in[i * 4 + 2]; + } + } + } else if(mode->colortype == LCT_RGBA) { + if(mode->bitdepth == 8) { + lodepng_memcpy(buffer, in, numpixels * 4); + } else { + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + buffer[0] = in[i * 8 + 0]; + buffer[1] = in[i * 8 + 2]; + buffer[2] = in[i * 8 + 4]; + buffer[3] = in[i * 8 + 6]; + } + } + } +} + +/*Similar to getPixelColorsRGBA8, but with 3-channel RGB output.*/ +static void getPixelColorsRGB8(unsigned char* LODEPNG_RESTRICT buffer, size_t numpixels, + const unsigned char* LODEPNG_RESTRICT in, + const LodePNGColorMode* mode) { + const unsigned num_channels = 3; + size_t i; + if(mode->colortype == LCT_GREY) { + if(mode->bitdepth == 8) { + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + buffer[0] = buffer[1] = buffer[2] = in[i]; + } + } else if(mode->bitdepth == 16) { + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + buffer[0] = buffer[1] = buffer[2] = in[i * 2]; + } + } else { + unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/ + size_t j = 0; + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth); + buffer[0] = buffer[1] = buffer[2] = (value * 255) / highest; + } + } + } else if(mode->colortype == LCT_RGB) { + if(mode->bitdepth == 8) { + lodepng_memcpy(buffer, in, numpixels * 3); + } else { + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + buffer[0] = in[i * 6 + 0]; + buffer[1] = in[i * 6 + 2]; + buffer[2] = in[i * 6 + 4]; + } + } + } else if(mode->colortype == LCT_PALETTE) { + if(mode->bitdepth == 8) { + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + unsigned index = in[i]; + /*out of bounds of palette not checked: see lodepng_color_mode_alloc_palette.*/ + lodepng_memcpy(buffer, &mode->palette[index * 4], 3); + } + } else { + size_t j = 0; + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + unsigned index = readBitsFromReversedStream(&j, in, mode->bitdepth); + /*out of bounds of palette not checked: see lodepng_color_mode_alloc_palette.*/ + lodepng_memcpy(buffer, &mode->palette[index * 4], 3); + } + } + } else if(mode->colortype == LCT_GREY_ALPHA) { + if(mode->bitdepth == 8) { + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + buffer[0] = buffer[1] = buffer[2] = in[i * 2 + 0]; + } + } else { + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + buffer[0] = buffer[1] = buffer[2] = in[i * 4 + 0]; + } + } + } else if(mode->colortype == LCT_RGBA) { + if(mode->bitdepth == 8) { + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + lodepng_memcpy(buffer, &in[i * 4], 3); + } + } else { + for(i = 0; i != numpixels; ++i, buffer += num_channels) { + buffer[0] = in[i * 8 + 0]; + buffer[1] = in[i * 8 + 2]; + buffer[2] = in[i * 8 + 4]; + } + } + } +} + +/*Get RGBA16 color of pixel with index i (y * width + x) from the raw image with +given color type, but the given color type must be 16-bit itself.*/ +static void getPixelColorRGBA16(unsigned short* r, unsigned short* g, unsigned short* b, unsigned short* a, + const unsigned char* in, size_t i, const LodePNGColorMode* mode) { + if(mode->colortype == LCT_GREY) { + *r = *g = *b = 256 * in[i * 2 + 0] + in[i * 2 + 1]; + if(mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0; + else *a = 65535; + } else if(mode->colortype == LCT_RGB) { + *r = 256u * in[i * 6 + 0] + in[i * 6 + 1]; + *g = 256u * in[i * 6 + 2] + in[i * 6 + 3]; + *b = 256u * in[i * 6 + 4] + in[i * 6 + 5]; + if(mode->key_defined + && 256u * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r + && 256u * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g + && 256u * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0; + else *a = 65535; + } else if(mode->colortype == LCT_GREY_ALPHA) { + *r = *g = *b = 256u * in[i * 4 + 0] + in[i * 4 + 1]; + *a = 256u * in[i * 4 + 2] + in[i * 4 + 3]; + } else if(mode->colortype == LCT_RGBA) { + *r = 256u * in[i * 8 + 0] + in[i * 8 + 1]; + *g = 256u * in[i * 8 + 2] + in[i * 8 + 3]; + *b = 256u * in[i * 8 + 4] + in[i * 8 + 5]; + *a = 256u * in[i * 8 + 6] + in[i * 8 + 7]; + } +} + +unsigned lodepng_convert(unsigned char* out, const unsigned char* in, + const LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, + unsigned w, unsigned h) { + size_t i; + ColorTree tree; + size_t numpixels = (size_t)w * (size_t)h; + unsigned error = 0; + + if(mode_in->colortype == LCT_PALETTE && !mode_in->palette) { + return 107; /* error: must provide palette if input mode is palette */ + } + + if(lodepng_color_mode_equal(mode_out, mode_in)) { + size_t numbytes = lodepng_get_raw_size(w, h, mode_in); + lodepng_memcpy(out, in, numbytes); + return 0; + } + + if(mode_out->colortype == LCT_PALETTE) { + size_t palettesize = mode_out->palettesize; + const unsigned char* palette = mode_out->palette; + size_t palsize = (size_t)1u << mode_out->bitdepth; + /*if the user specified output palette but did not give the values, assume + they want the values of the input color type (assuming that one is palette). + Note that we never create a new palette ourselves.*/ + if(palettesize == 0) { + palettesize = mode_in->palettesize; + palette = mode_in->palette; + /*if the input was also palette with same bitdepth, then the color types are also + equal, so copy literally. This to preserve the exact indices that were in the PNG + even in case there are duplicate colors in the palette.*/ + if(mode_in->colortype == LCT_PALETTE && mode_in->bitdepth == mode_out->bitdepth) { + size_t numbytes = lodepng_get_raw_size(w, h, mode_in); + lodepng_memcpy(out, in, numbytes); + return 0; + } + } + if(palettesize < palsize) palsize = palettesize; + color_tree_init(&tree); + for(i = 0; i != palsize; ++i) { + const unsigned char* p = &palette[i * 4]; + error = color_tree_add(&tree, p[0], p[1], p[2], p[3], (unsigned)i); + if(error) break; + } + } + + if(!error) { + if(mode_in->bitdepth == 16 && mode_out->bitdepth == 16) { + for(i = 0; i != numpixels; ++i) { + unsigned short r = 0, g = 0, b = 0, a = 0; + getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in); + rgba16ToPixel(out, i, mode_out, r, g, b, a); + } + } else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGBA) { + getPixelColorsRGBA8(out, numpixels, in, mode_in); + } else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGB) { + getPixelColorsRGB8(out, numpixels, in, mode_in); + } else { + unsigned char r = 0, g = 0, b = 0, a = 0; + for(i = 0; i != numpixels; ++i) { + getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode_in); + error = rgba8ToPixel(out, i, mode_out, &tree, r, g, b, a); + if(error) break; + } + } + } + + if(mode_out->colortype == LCT_PALETTE) { + color_tree_cleanup(&tree); + } + + return error; +} + + +/* Converts a single rgb color without alpha from one type to another, color bits truncated to +their bitdepth. In case of single channel (gray or palette), only the r channel is used. Slow +function, do not use to process all pixels of an image. Alpha channel not supported on purpose: +this is for bKGD, supporting alpha may prevent it from finding a color in the palette, from the +specification it looks like bKGD should ignore the alpha values of the palette since it can use +any palette index but doesn't have an alpha channel. Idem with ignoring color key. */ +unsigned lodepng_convert_rgb( + unsigned* r_out, unsigned* g_out, unsigned* b_out, + unsigned r_in, unsigned g_in, unsigned b_in, + const LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in) { + unsigned r = 0, g = 0, b = 0; + unsigned mul = 65535 / ((1u << mode_in->bitdepth) - 1u); /*65535, 21845, 4369, 257, 1*/ + unsigned shift = 16 - mode_out->bitdepth; + + if(mode_in->colortype == LCT_GREY || mode_in->colortype == LCT_GREY_ALPHA) { + r = g = b = r_in * mul; + } else if(mode_in->colortype == LCT_RGB || mode_in->colortype == LCT_RGBA) { + r = r_in * mul; + g = g_in * mul; + b = b_in * mul; + } else if(mode_in->colortype == LCT_PALETTE) { + if(r_in >= mode_in->palettesize) return 82; + r = mode_in->palette[r_in * 4 + 0] * 257u; + g = mode_in->palette[r_in * 4 + 1] * 257u; + b = mode_in->palette[r_in * 4 + 2] * 257u; + } else { + return 31; + } + + /* now convert to output format */ + if(mode_out->colortype == LCT_GREY || mode_out->colortype == LCT_GREY_ALPHA) { + *r_out = r >> shift ; + } else if(mode_out->colortype == LCT_RGB || mode_out->colortype == LCT_RGBA) { + *r_out = r >> shift ; + *g_out = g >> shift ; + *b_out = b >> shift ; + } else if(mode_out->colortype == LCT_PALETTE) { + unsigned i; + /* a 16-bit color cannot be in the palette */ + if((r >> 8) != (r & 255) || (g >> 8) != (g & 255) || (b >> 8) != (b & 255)) return 82; + for(i = 0; i < mode_out->palettesize; i++) { + unsigned j = i * 4; + if((r >> 8) == mode_out->palette[j + 0] && (g >> 8) == mode_out->palette[j + 1] && + (b >> 8) == mode_out->palette[j + 2]) { + *r_out = i; + return 0; + } + } + return 82; + } else { + return 31; + } + + return 0; +} + +#ifdef LODEPNG_COMPILE_ENCODER + +void lodepng_color_stats_init(LodePNGColorStats* stats) { + /*stats*/ + stats->colored = 0; + stats->key = 0; + stats->key_r = stats->key_g = stats->key_b = 0; + stats->alpha = 0; + stats->numcolors = 0; + stats->bits = 1; + stats->numpixels = 0; + /*settings*/ + stats->allow_palette = 1; + stats->allow_greyscale = 1; +} + +/*function used for debug purposes with C++*/ +/*void printColorStats(LodePNGColorStats* p) { + std::cout << "colored: " << (int)p->colored << ", "; + std::cout << "key: " << (int)p->key << ", "; + std::cout << "key_r: " << (int)p->key_r << ", "; + std::cout << "key_g: " << (int)p->key_g << ", "; + std::cout << "key_b: " << (int)p->key_b << ", "; + std::cout << "alpha: " << (int)p->alpha << ", "; + std::cout << "numcolors: " << (int)p->numcolors << ", "; + std::cout << "bits: " << (int)p->bits << std::endl; +}*/ + +/*Returns how many bits needed to represent given value (max 8 bit)*/ +static unsigned getValueRequiredBits(unsigned char value) { + if(value == 0 || value == 255) return 1; + /*The scaling of 2-bit and 4-bit values uses multiples of 85 and 17*/ + if(value % 17 == 0) return value % 85 == 0 ? 2 : 4; + return 8; +} + +/*stats must already have been inited. */ +unsigned lodepng_compute_color_stats(LodePNGColorStats* stats, + const unsigned char* in, unsigned w, unsigned h, + const LodePNGColorMode* mode_in) { + size_t i; + ColorTree tree; + size_t numpixels = (size_t)w * (size_t)h; + unsigned error = 0; + + /* mark things as done already if it would be impossible to have a more expensive case */ + unsigned colored_done = lodepng_is_greyscale_type(mode_in) ? 1 : 0; + unsigned alpha_done = lodepng_can_have_alpha(mode_in) ? 0 : 1; + unsigned numcolors_done = 0; + unsigned bpp = lodepng_get_bpp(mode_in); + unsigned bits_done = (stats->bits == 1 && bpp == 1) ? 1 : 0; + unsigned sixteen = 0; /* whether the input image is 16 bit */ + unsigned maxnumcolors = 257; + if(bpp <= 8) maxnumcolors = LODEPNG_MIN(257, stats->numcolors + (1u << bpp)); + + stats->numpixels += numpixels; + + /*if palette not allowed, no need to compute numcolors*/ + if(!stats->allow_palette) numcolors_done = 1; + + color_tree_init(&tree); + + /*If the stats was already filled in from previous data, fill its palette in tree + and mark things as done already if we know they are the most expensive case already*/ + if(stats->alpha) alpha_done = 1; + if(stats->colored) colored_done = 1; + if(stats->bits == 16) numcolors_done = 1; + if(stats->bits >= bpp) bits_done = 1; + if(stats->numcolors >= maxnumcolors) numcolors_done = 1; + + if(!numcolors_done) { + for(i = 0; i < stats->numcolors; i++) { + const unsigned char* color = &stats->palette[i * 4]; + error = color_tree_add(&tree, color[0], color[1], color[2], color[3], (unsigned)i); + if(error) goto cleanup; + } + } + + /*Check if the 16-bit input is truly 16-bit*/ + if(mode_in->bitdepth == 16 && !sixteen) { + unsigned short r = 0, g = 0, b = 0, a = 0; + for(i = 0; i != numpixels; ++i) { + getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in); + if((r & 255) != ((r >> 8) & 255) || (g & 255) != ((g >> 8) & 255) || + (b & 255) != ((b >> 8) & 255) || (a & 255) != ((a >> 8) & 255)) /*first and second byte differ*/ { + stats->bits = 16; + sixteen = 1; + bits_done = 1; + numcolors_done = 1; /*counting colors no longer useful, palette doesn't support 16-bit*/ + break; + } + } + } + + if(sixteen) { + unsigned short r = 0, g = 0, b = 0, a = 0; + + for(i = 0; i != numpixels; ++i) { + getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in); + + if(!colored_done && (r != g || r != b)) { + stats->colored = 1; + colored_done = 1; + } + + if(!alpha_done) { + unsigned matchkey = (r == stats->key_r && g == stats->key_g && b == stats->key_b); + if(a != 65535 && (a != 0 || (stats->key && !matchkey))) { + stats->alpha = 1; + stats->key = 0; + alpha_done = 1; + } else if(a == 0 && !stats->alpha && !stats->key) { + stats->key = 1; + stats->key_r = r; + stats->key_g = g; + stats->key_b = b; + } else if(a == 65535 && stats->key && matchkey) { + /* Color key cannot be used if an opaque pixel also has that RGB color. */ + stats->alpha = 1; + stats->key = 0; + alpha_done = 1; + } + } + if(alpha_done && numcolors_done && colored_done && bits_done) break; + } + + if(stats->key && !stats->alpha) { + for(i = 0; i != numpixels; ++i) { + getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in); + if(a != 0 && r == stats->key_r && g == stats->key_g && b == stats->key_b) { + /* Color key cannot be used if an opaque pixel also has that RGB color. */ + stats->alpha = 1; + stats->key = 0; + alpha_done = 1; + } + } + } + } else /* < 16-bit */ { + unsigned char r = 0, g = 0, b = 0, a = 0; + unsigned char pr = 0, pg = 0, pb = 0, pa = 0; + for(i = 0; i != numpixels; ++i) { + getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode_in); + + /*skip if color same as before, this speeds up large non-photographic + images with many same colors by avoiding 'color_tree_has' below */ + if(i != 0 && r == pr && g == pg && b == pb && a == pa) continue; + pr = r; + pg = g; + pb = b; + pa = a; + + if(!bits_done && stats->bits < 8) { + /*only r is checked, < 8 bits is only relevant for grayscale*/ + unsigned bits = getValueRequiredBits(r); + if(bits > stats->bits) stats->bits = bits; + } + bits_done = (stats->bits >= bpp); + + if(!colored_done && (r != g || r != b)) { + stats->colored = 1; + colored_done = 1; + if(stats->bits < 8) stats->bits = 8; /*PNG has no colored modes with less than 8-bit per channel*/ + } + + if(!alpha_done) { + unsigned matchkey = (r == stats->key_r && g == stats->key_g && b == stats->key_b); + if(a != 255 && (a != 0 || (stats->key && !matchkey))) { + stats->alpha = 1; + stats->key = 0; + alpha_done = 1; + if(stats->bits < 8) stats->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ + } else if(a == 0 && !stats->alpha && !stats->key) { + stats->key = 1; + stats->key_r = r; + stats->key_g = g; + stats->key_b = b; + } else if(a == 255 && stats->key && matchkey) { + /* Color key cannot be used if an opaque pixel also has that RGB color. */ + stats->alpha = 1; + stats->key = 0; + alpha_done = 1; + if(stats->bits < 8) stats->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ + } + } + + if(!numcolors_done) { + if(!color_tree_has(&tree, r, g, b, a)) { + error = color_tree_add(&tree, r, g, b, a, stats->numcolors); + if(error) goto cleanup; + if(stats->numcolors < 256) { + unsigned char* p = stats->palette; + unsigned n = stats->numcolors; + p[n * 4 + 0] = r; + p[n * 4 + 1] = g; + p[n * 4 + 2] = b; + p[n * 4 + 3] = a; + } + ++stats->numcolors; + numcolors_done = stats->numcolors >= maxnumcolors; + } + } + + if(alpha_done && numcolors_done && colored_done && bits_done) break; + } + + if(stats->key && !stats->alpha) { + for(i = 0; i != numpixels; ++i) { + getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode_in); + if(a != 0 && r == stats->key_r && g == stats->key_g && b == stats->key_b) { + /* Color key cannot be used if an opaque pixel also has that RGB color. */ + stats->alpha = 1; + stats->key = 0; + alpha_done = 1; + if(stats->bits < 8) stats->bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ + } + } + } + + /*make the stats's key always 16-bit for consistency - repeat each byte twice*/ + stats->key_r += (stats->key_r << 8); + stats->key_g += (stats->key_g << 8); + stats->key_b += (stats->key_b << 8); + } + +cleanup: + color_tree_cleanup(&tree); + return error; +} + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +/*Adds a single color to the color stats. The stats must already have been inited. The color must be given as 16-bit +(with 2 bytes repeating for 8-bit and 65535 for opaque alpha channel). This function is expensive, do not call it for +all pixels of an image but only for a few additional values. */ +static unsigned lodepng_color_stats_add(LodePNGColorStats* stats, + unsigned r, unsigned g, unsigned b, unsigned a) { + unsigned error = 0; + unsigned char image[8]; + LodePNGColorMode mode; + lodepng_color_mode_init(&mode); + image[0] = r >> 8; image[1] = r; image[2] = g >> 8; image[3] = g; + image[4] = b >> 8; image[5] = b; image[6] = a >> 8; image[7] = a; + mode.bitdepth = 16; + mode.colortype = LCT_RGBA; + error = lodepng_compute_color_stats(stats, image, 1, 1, &mode); + lodepng_color_mode_cleanup(&mode); + return error; +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +/*Computes a minimal PNG color model that can contain all colors as indicated by the stats. +The stats should be computed with lodepng_compute_color_stats. +mode_in is raw color profile of the image the stats were computed on, to copy palette order from when relevant. +Minimal PNG color model means the color type and bit depth that gives smallest amount of bits in the output image, +e.g. gray if only grayscale pixels, palette if less than 256 colors, color key if only single transparent color, ... +This is used if auto_convert is enabled (it is by default). +*/ +static unsigned auto_choose_color(LodePNGColorMode* mode_out, + const LodePNGColorMode* mode_in, + const LodePNGColorStats* stats) { + unsigned error = 0; + unsigned palettebits; + size_t i, n; + size_t numpixels = stats->numpixels; + unsigned palette_ok, gray_ok; + + unsigned alpha = stats->alpha; + unsigned key = stats->key; + unsigned bits = stats->bits; + + mode_out->key_defined = 0; + + if(key && numpixels <= 16) { + alpha = 1; /*too few pixels to justify tRNS chunk overhead*/ + key = 0; + if(bits < 8) bits = 8; /*PNG has no alphachannel modes with less than 8-bit per channel*/ + } + + gray_ok = !stats->colored; + if(!stats->allow_greyscale) gray_ok = 0; + if(!gray_ok && bits < 8) bits = 8; + + n = stats->numcolors; + palettebits = n <= 2 ? 1 : (n <= 4 ? 2 : (n <= 16 ? 4 : 8)); + palette_ok = n <= 256 && bits <= 8 && n != 0; /*n==0 means likely numcolors wasn't computed*/ + if(numpixels < n * 2) palette_ok = 0; /*don't add palette overhead if image has only a few pixels*/ + if(gray_ok && !alpha && bits <= palettebits) palette_ok = 0; /*gray is less overhead*/ + if(!stats->allow_palette) palette_ok = 0; + + if(palette_ok) { + const unsigned char* p = stats->palette; + lodepng_palette_clear(mode_out); /*remove potential earlier palette*/ + for(i = 0; i != stats->numcolors; ++i) { + error = lodepng_palette_add(mode_out, p[i * 4 + 0], p[i * 4 + 1], p[i * 4 + 2], p[i * 4 + 3]); + if(error) break; + } + + mode_out->colortype = LCT_PALETTE; + mode_out->bitdepth = palettebits; + + if(mode_in->colortype == LCT_PALETTE && mode_in->palettesize >= mode_out->palettesize + && mode_in->bitdepth == mode_out->bitdepth) { + /*If input should have same palette colors, keep original to preserve its order and prevent conversion*/ + lodepng_color_mode_cleanup(mode_out); /*clears palette, keeps the above set colortype and bitdepth fields as-is*/ + lodepng_color_mode_copy(mode_out, mode_in); + } + } else /*8-bit or 16-bit per channel*/ { + mode_out->bitdepth = bits; + mode_out->colortype = alpha ? (gray_ok ? LCT_GREY_ALPHA : LCT_RGBA) + : (gray_ok ? LCT_GREY : LCT_RGB); + if(key) { + unsigned mask = (1u << mode_out->bitdepth) - 1u; /*stats always uses 16-bit, mask converts it*/ + mode_out->key_r = stats->key_r & mask; + mode_out->key_g = stats->key_g & mask; + mode_out->key_b = stats->key_b & mask; + mode_out->key_defined = 1; + } + } + + return error; +} + +#endif /* #ifdef LODEPNG_COMPILE_ENCODER */ + +/*Paeth predictor, used by PNG filter type 4*/ +static unsigned char paethPredictor(unsigned char a, unsigned char b, unsigned char c) { + /* the subtractions of unsigned char cast it to a signed type. + With gcc, short is faster than int, with clang int is as fast (as of april 2023)*/ + short pa = (b - c) < 0 ? -(b - c) : (b - c); + short pb = (a - c) < 0 ? -(a - c) : (a - c); + /* writing it out like this compiles to something faster than introducing a temp variable*/ + short pc = (a + b - c - c) < 0 ? -(a + b - c - c) : (a + b - c - c); + /* return input value associated with smallest of pa, pb, pc (with certain priority if equal) */ + if(pb < pa) { a = b; pa = pb; } + return (pc < pa) ? c : a; +} + +/*shared values used by multiple Adam7 related functions*/ + +static const unsigned ADAM7_IX[7] = { 0, 4, 0, 2, 0, 1, 0 }; /*x start values*/ +static const unsigned ADAM7_IY[7] = { 0, 0, 4, 0, 2, 0, 1 }; /*y start values*/ +static const unsigned ADAM7_DX[7] = { 8, 8, 4, 4, 2, 2, 1 }; /*x delta values*/ +static const unsigned ADAM7_DY[7] = { 8, 8, 8, 4, 4, 2, 2 }; /*y delta values*/ + +/* +Outputs various dimensions and positions in the image related to the Adam7 reduced images. +passw: output containing the width of the 7 passes +passh: output containing the height of the 7 passes +filter_passstart: output containing the index of the start and end of each + reduced image with filter bytes +padded_passstart output containing the index of the start and end of each + reduced image when without filter bytes but with padded scanlines +passstart: output containing the index of the start and end of each reduced + image without padding between scanlines, but still padding between the images +w, h: width and height of non-interlaced image +bpp: bits per pixel +"padded" is only relevant if bpp is less than 8 and a scanline or image does not + end at a full byte +*/ +static void Adam7_getpassvalues(unsigned passw[7], unsigned passh[7], size_t filter_passstart[8], + size_t padded_passstart[8], size_t passstart[8], unsigned w, unsigned h, unsigned bpp) { + /*the passstart values have 8 values: the 8th one indicates the byte after the end of the 7th (= last) pass*/ + unsigned i; + + /*calculate width and height in pixels of each pass*/ + for(i = 0; i != 7; ++i) { + passw[i] = (w + ADAM7_DX[i] - ADAM7_IX[i] - 1) / ADAM7_DX[i]; + passh[i] = (h + ADAM7_DY[i] - ADAM7_IY[i] - 1) / ADAM7_DY[i]; + if(passw[i] == 0) passh[i] = 0; + if(passh[i] == 0) passw[i] = 0; + } + + filter_passstart[0] = padded_passstart[0] = passstart[0] = 0; + for(i = 0; i != 7; ++i) { + /*if passw[i] is 0, it's 0 bytes, not 1 (no filtertype-byte)*/ + filter_passstart[i + 1] = filter_passstart[i] + + ((passw[i] && passh[i]) ? passh[i] * (1u + (passw[i] * bpp + 7u) / 8u) : 0); + /*bits padded if needed to fill full byte at end of each scanline*/ + padded_passstart[i + 1] = padded_passstart[i] + passh[i] * ((passw[i] * bpp + 7u) / 8u); + /*only padded at end of reduced image*/ + passstart[i + 1] = passstart[i] + (passh[i] * passw[i] * bpp + 7u) / 8u; + } +} + +#ifdef LODEPNG_COMPILE_DECODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / PNG Decoder / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*read the information from the header and store it in the LodePNGInfo. return value is error*/ +unsigned lodepng_inspect(unsigned* w, unsigned* h, LodePNGState* state, + const unsigned char* in, size_t insize) { + unsigned width, height; + LodePNGInfo* info = &state->info_png; + if(insize == 0 || in == 0) { + CERROR_RETURN_ERROR(state->error, 48); /*error: the given data is empty*/ + } + if(insize < 33) { + CERROR_RETURN_ERROR(state->error, 27); /*error: the data length is smaller than the length of a PNG header*/ + } + + /*when decoding a new PNG image, make sure all parameters created after previous decoding are reset*/ + /* TODO: remove this. One should use a new LodePNGState for new sessions */ + lodepng_info_cleanup(info); + lodepng_info_init(info); + + if(in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71 + || in[4] != 13 || in[5] != 10 || in[6] != 26 || in[7] != 10) { + CERROR_RETURN_ERROR(state->error, 28); /*error: the first 8 bytes are not the correct PNG signature*/ + } + if(lodepng_chunk_length(in + 8) != 13) { + CERROR_RETURN_ERROR(state->error, 94); /*error: header size must be 13 bytes*/ + } + if(!lodepng_chunk_type_equals(in + 8, "IHDR")) { + CERROR_RETURN_ERROR(state->error, 29); /*error: it doesn't start with a IHDR chunk!*/ + } + + /*read the values given in the header*/ + width = lodepng_read32bitInt(&in[16]); + height = lodepng_read32bitInt(&in[20]); + /*TODO: remove the undocumented feature that allows to give null pointers to width or height*/ + if(w) *w = width; + if(h) *h = height; + info->color.bitdepth = in[24]; + info->color.colortype = (LodePNGColorType)in[25]; + info->compression_method = in[26]; + info->filter_method = in[27]; + info->interlace_method = in[28]; + + /*errors returned only after the parsing so other values are still output*/ + + /*error: invalid image size*/ + if(width == 0 || height == 0) CERROR_RETURN_ERROR(state->error, 93); + /*error: invalid colortype or bitdepth combination*/ + state->error = checkColorValidity(info->color.colortype, info->color.bitdepth); + if(state->error) return state->error; + /*error: only compression method 0 is allowed in the specification*/ + if(info->compression_method != 0) CERROR_RETURN_ERROR(state->error, 32); + /*error: only filter method 0 is allowed in the specification*/ + if(info->filter_method != 0) CERROR_RETURN_ERROR(state->error, 33); + /*error: only interlace methods 0 and 1 exist in the specification*/ + if(info->interlace_method > 1) CERROR_RETURN_ERROR(state->error, 34); + + if(!state->decoder.ignore_crc) { + unsigned crc = lodepng_read32bitInt(&in[29]); + unsigned checksum = lodepng_crc32(&in[12], 17); + if(crc != checksum) { + CERROR_RETURN_ERROR(state->error, 57); /*invalid CRC*/ + } + } + + return state->error; +} + +static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scanline, const unsigned char* precon, + size_t bytewidth, unsigned char filterType, size_t length) { + /* + For PNG filter method 0 + unfilter a PNG image scanline by scanline. when the pixels are smaller than 1 byte, + the filter works byte per byte (bytewidth = 1) + precon is the previous unfiltered scanline, recon the result, scanline the current one + the incoming scanlines do NOT include the filtertype byte, that one is given in the parameter filterType instead + recon and scanline MAY be the same memory address! precon must be disjoint. + */ + + size_t i; + switch(filterType) { + case 0: + for(i = 0; i != length; ++i) recon[i] = scanline[i]; + break; + case 1: { + size_t j = 0; + for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i]; + for(i = bytewidth; i != length; ++i, ++j) recon[i] = scanline[i] + recon[j]; + break; + } + case 2: + if(precon) { + for(i = 0; i != length; ++i) recon[i] = scanline[i] + precon[i]; + } else { + for(i = 0; i != length; ++i) recon[i] = scanline[i]; + } + break; + case 3: + if(precon) { + size_t j = 0; + for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i] + (precon[i] >> 1u); + /* Unroll independent paths of this predictor. A 6x and 8x version is also possible but that adds + too much code. Whether this speeds up anything depends on compiler and settings. */ + if(bytewidth >= 4) { + for(; i + 3 < length; i += 4, j += 4) { + unsigned char s0 = scanline[i + 0], s1 = scanline[i + 1], s2 = scanline[i + 2], s3 = scanline[i + 3]; + unsigned char r0 = recon[j + 0], r1 = recon[j + 1], r2 = recon[j + 2], r3 = recon[j + 3]; + unsigned char p0 = precon[i + 0], p1 = precon[i + 1], p2 = precon[i + 2], p3 = precon[i + 3]; + recon[i + 0] = s0 + ((r0 + p0) >> 1u); + recon[i + 1] = s1 + ((r1 + p1) >> 1u); + recon[i + 2] = s2 + ((r2 + p2) >> 1u); + recon[i + 3] = s3 + ((r3 + p3) >> 1u); + } + } else if(bytewidth >= 3) { + for(; i + 2 < length; i += 3, j += 3) { + unsigned char s0 = scanline[i + 0], s1 = scanline[i + 1], s2 = scanline[i + 2]; + unsigned char r0 = recon[j + 0], r1 = recon[j + 1], r2 = recon[j + 2]; + unsigned char p0 = precon[i + 0], p1 = precon[i + 1], p2 = precon[i + 2]; + recon[i + 0] = s0 + ((r0 + p0) >> 1u); + recon[i + 1] = s1 + ((r1 + p1) >> 1u); + recon[i + 2] = s2 + ((r2 + p2) >> 1u); + } + } else if(bytewidth >= 2) { + for(; i + 1 < length; i += 2, j += 2) { + unsigned char s0 = scanline[i + 0], s1 = scanline[i + 1]; + unsigned char r0 = recon[j + 0], r1 = recon[j + 1]; + unsigned char p0 = precon[i + 0], p1 = precon[i + 1]; + recon[i + 0] = s0 + ((r0 + p0) >> 1u); + recon[i + 1] = s1 + ((r1 + p1) >> 1u); + } + } + for(; i != length; ++i, ++j) recon[i] = scanline[i] + ((recon[j] + precon[i]) >> 1u); + } else { + size_t j = 0; + for(i = 0; i != bytewidth; ++i) recon[i] = scanline[i]; + for(i = bytewidth; i != length; ++i, ++j) recon[i] = scanline[i] + (recon[j] >> 1u); + } + break; + case 4: + if(precon) { + /* Unroll independent paths of this predictor. Whether this speeds up + anything depends on compiler and settings. */ + if(bytewidth == 8) { + unsigned char a0, b0 = 0, c0, d0 = 0, a1, b1 = 0, c1, d1 = 0; + unsigned char a2, b2 = 0, c2, d2 = 0, a3, b3 = 0, c3, d3 = 0; + unsigned char a4, b4 = 0, c4, d4 = 0, a5, b5 = 0, c5, d5 = 0; + unsigned char a6, b6 = 0, c6, d6 = 0, a7, b7 = 0, c7, d7 = 0; + for(i = 0; i + 7 < length; i += 8) { + c0 = b0; c1 = b1; c2 = b2; c3 = b3; + c4 = b4; c5 = b5; c6 = b6; c7 = b7; + b0 = precon[i + 0]; b1 = precon[i + 1]; b2 = precon[i + 2]; b3 = precon[i + 3]; + b4 = precon[i + 4]; b5 = precon[i + 5]; b6 = precon[i + 6]; b7 = precon[i + 7]; + a0 = d0; a1 = d1; a2 = d2; a3 = d3; + a4 = d4; a5 = d5; a6 = d6; a7 = d7; + d0 = scanline[i + 0] + paethPredictor(a0, b0, c0); + d1 = scanline[i + 1] + paethPredictor(a1, b1, c1); + d2 = scanline[i + 2] + paethPredictor(a2, b2, c2); + d3 = scanline[i + 3] + paethPredictor(a3, b3, c3); + d4 = scanline[i + 4] + paethPredictor(a4, b4, c4); + d5 = scanline[i + 5] + paethPredictor(a5, b5, c5); + d6 = scanline[i + 6] + paethPredictor(a6, b6, c6); + d7 = scanline[i + 7] + paethPredictor(a7, b7, c7); + recon[i + 0] = d0; recon[i + 1] = d1; recon[i + 2] = d2; recon[i + 3] = d3; + recon[i + 4] = d4; recon[i + 5] = d5; recon[i + 6] = d6; recon[i + 7] = d7; + } + } else if(bytewidth == 6) { + unsigned char a0, b0 = 0, c0, d0 = 0, a1, b1 = 0, c1, d1 = 0; + unsigned char a2, b2 = 0, c2, d2 = 0, a3, b3 = 0, c3, d3 = 0; + unsigned char a4, b4 = 0, c4, d4 = 0, a5, b5 = 0, c5, d5 = 0; + for(i = 0; i + 5 < length; i += 6) { + c0 = b0; c1 = b1; c2 = b2; + c3 = b3; c4 = b4; c5 = b5; + b0 = precon[i + 0]; b1 = precon[i + 1]; b2 = precon[i + 2]; + b3 = precon[i + 3]; b4 = precon[i + 4]; b5 = precon[i + 5]; + a0 = d0; a1 = d1; a2 = d2; + a3 = d3; a4 = d4; a5 = d5; + d0 = scanline[i + 0] + paethPredictor(a0, b0, c0); + d1 = scanline[i + 1] + paethPredictor(a1, b1, c1); + d2 = scanline[i + 2] + paethPredictor(a2, b2, c2); + d3 = scanline[i + 3] + paethPredictor(a3, b3, c3); + d4 = scanline[i + 4] + paethPredictor(a4, b4, c4); + d5 = scanline[i + 5] + paethPredictor(a5, b5, c5); + recon[i + 0] = d0; recon[i + 1] = d1; recon[i + 2] = d2; + recon[i + 3] = d3; recon[i + 4] = d4; recon[i + 5] = d5; + } + } else if(bytewidth == 4) { + unsigned char a0, b0 = 0, c0, d0 = 0, a1, b1 = 0, c1, d1 = 0; + unsigned char a2, b2 = 0, c2, d2 = 0, a3, b3 = 0, c3, d3 = 0; + for(i = 0; i + 3 < length; i += 4) { + c0 = b0; c1 = b1; c2 = b2; c3 = b3; + b0 = precon[i + 0]; b1 = precon[i + 1]; b2 = precon[i + 2]; b3 = precon[i + 3]; + a0 = d0; a1 = d1; a2 = d2; a3 = d3; + d0 = scanline[i + 0] + paethPredictor(a0, b0, c0); + d1 = scanline[i + 1] + paethPredictor(a1, b1, c1); + d2 = scanline[i + 2] + paethPredictor(a2, b2, c2); + d3 = scanline[i + 3] + paethPredictor(a3, b3, c3); + recon[i + 0] = d0; recon[i + 1] = d1; recon[i + 2] = d2; recon[i + 3] = d3; + } + } else if(bytewidth == 3) { + unsigned char a0, b0 = 0, c0, d0 = 0; + unsigned char a1, b1 = 0, c1, d1 = 0; + unsigned char a2, b2 = 0, c2, d2 = 0; + for(i = 0; i + 2 < length; i += 3) { + c0 = b0; c1 = b1; c2 = b2; + b0 = precon[i + 0]; b1 = precon[i + 1]; b2 = precon[i + 2]; + a0 = d0; a1 = d1; a2 = d2; + d0 = scanline[i + 0] + paethPredictor(a0, b0, c0); + d1 = scanline[i + 1] + paethPredictor(a1, b1, c1); + d2 = scanline[i + 2] + paethPredictor(a2, b2, c2); + recon[i + 0] = d0; recon[i + 1] = d1; recon[i + 2] = d2; + } + } else if(bytewidth == 2) { + unsigned char a0, b0 = 0, c0, d0 = 0; + unsigned char a1, b1 = 0, c1, d1 = 0; + for(i = 0; i + 1 < length; i += 2) { + c0 = b0; c1 = b1; + b0 = precon[i + 0]; + b1 = precon[i + 1]; + a0 = d0; a1 = d1; + d0 = scanline[i + 0] + paethPredictor(a0, b0, c0); + d1 = scanline[i + 1] + paethPredictor(a1, b1, c1); + recon[i + 0] = d0; + recon[i + 1] = d1; + } + } else if(bytewidth == 1) { + unsigned char a, b = 0, c, d = 0; + for(i = 0; i != length; ++i) { + c = b; + b = precon[i]; + a = d; + d = scanline[i] + paethPredictor(a, b, c); + recon[i] = d; + } + } else { + /* Normally not a possible case, but this would handle it correctly */ + for(i = 0; i != bytewidth; ++i) { + recon[i] = (scanline[i] + precon[i]); /*paethPredictor(0, precon[i], 0) is always precon[i]*/ + } + } + /* finish any remaining bytes */ + for(; i != length; ++i) { + recon[i] = (scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[i - bytewidth])); + } + } else { + size_t j = 0; + for(i = 0; i != bytewidth; ++i) { + recon[i] = scanline[i]; + } + for(i = bytewidth; i != length; ++i, ++j) { + /*paethPredictor(recon[i - bytewidth], 0, 0) is always recon[i - bytewidth]*/ + recon[i] = (scanline[i] + recon[j]); + } + } + break; + default: return 36; /*error: invalid filter type given*/ + } + return 0; +} + +static unsigned unfilter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) { + /* + For PNG filter method 0 + this function unfilters a single image (e.g. without interlacing this is called once, with Adam7 seven times) + out must have enough bytes allocated already, in must have the scanlines + 1 filtertype byte per scanline + w and h are image dimensions or dimensions of reduced image, bpp is bits per pixel + in and out are allowed to be the same memory address (but aren't the same size since in has the extra filter bytes) + */ + + unsigned y; + unsigned char* prevline = 0; + + /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/ + size_t bytewidth = (bpp + 7u) / 8u; + /*the width of a scanline in bytes, not including the filter type*/ + size_t linebytes = lodepng_get_raw_size_idat(w, 1, bpp) - 1u; + + for(y = 0; y < h; ++y) { + size_t outindex = linebytes * y; + size_t inindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ + unsigned char filterType = in[inindex]; + + CERROR_TRY_RETURN(unfilterScanline(&out[outindex], &in[inindex + 1], prevline, bytewidth, filterType, linebytes)); + + prevline = &out[outindex]; + } + + return 0; +} + +/* +in: Adam7 interlaced image, with no padding bits between scanlines, but between + reduced images so that each reduced image starts at a byte. +out: the same pixels, but re-ordered so that they're now a non-interlaced image with size w*h +bpp: bits per pixel +out has the following size in bits: w * h * bpp. +in is possibly bigger due to padding bits between reduced images. +out must be big enough AND must be 0 everywhere if bpp < 8 in the current implementation +(because that's likely a little bit faster) +NOTE: comments about padding bits are only relevant if bpp < 8 +*/ +static void Adam7_deinterlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) { + unsigned passw[7], passh[7]; + size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned i; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + if(bpp >= 8) { + for(i = 0; i != 7; ++i) { + unsigned x, y, b; + size_t bytewidth = bpp / 8u; + for(y = 0; y < passh[i]; ++y) + for(x = 0; x < passw[i]; ++x) { + size_t pixelinstart = passstart[i] + (y * passw[i] + x) * bytewidth; + size_t pixeloutstart = ((ADAM7_IY[i] + (size_t)y * ADAM7_DY[i]) * (size_t)w + + ADAM7_IX[i] + (size_t)x * ADAM7_DX[i]) * bytewidth; + for(b = 0; b < bytewidth; ++b) { + out[pixeloutstart + b] = in[pixelinstart + b]; + } + } + } + } else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/ { + for(i = 0; i != 7; ++i) { + unsigned x, y, b; + unsigned ilinebits = bpp * passw[i]; + unsigned olinebits = bpp * w; + size_t obp, ibp; /*bit pointers (for out and in buffer)*/ + for(y = 0; y < passh[i]; ++y) + for(x = 0; x < passw[i]; ++x) { + ibp = (8 * passstart[i]) + (y * ilinebits + x * bpp); + obp = (ADAM7_IY[i] + (size_t)y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + (size_t)x * ADAM7_DX[i]) * bpp; + for(b = 0; b < bpp; ++b) { + unsigned char bit = readBitFromReversedStream(&ibp, in); + setBitOfReversedStream(&obp, out, bit); + } + } + } + } +} + +static void removePaddingBits(unsigned char* out, const unsigned char* in, + size_t olinebits, size_t ilinebits, unsigned h) { + /* + After filtering there are still padding bits if scanlines have non multiple of 8 bit amounts. They need + to be removed (except at last scanline of (Adam7-reduced) image) before working with pure image buffers + for the Adam7 code, the color convert code and the output to the user. + in and out are allowed to be the same buffer, in may also be higher but still overlapping; in must + have >= ilinebits*h bits, out must have >= olinebits*h bits, olinebits must be <= ilinebits + also used to move bits after earlier such operations happened, e.g. in a sequence of reduced images from Adam7 + only useful if (ilinebits - olinebits) is a value in the range 1..7 + */ + unsigned y; + size_t diff = ilinebits - olinebits; + size_t ibp = 0, obp = 0; /*input and output bit pointers*/ + for(y = 0; y < h; ++y) { + size_t x; + for(x = 0; x < olinebits; ++x) { + unsigned char bit = readBitFromReversedStream(&ibp, in); + setBitOfReversedStream(&obp, out, bit); + } + ibp += diff; + } +} + +/*out must be buffer big enough to contain full image, and in must contain the full decompressed data from +the IDAT chunks (with filter index bytes and possible padding bits) +return value is error*/ +static unsigned postProcessScanlines(unsigned char* out, unsigned char* in, + unsigned w, unsigned h, const LodePNGInfo* info_png) { + /* + This function converts the filtered-padded-interlaced data into pure 2D image buffer with the PNG's colortype. + Steps: + *) if no Adam7: 1) unfilter 2) remove padding bits (= possible extra bits per scanline if bpp < 8) + *) if adam7: 1) 7x unfilter 2) 7x remove padding bits 3) Adam7_deinterlace + NOTE: the in buffer will be overwritten with intermediate data! + */ + unsigned bpp = lodepng_get_bpp(&info_png->color); + if(bpp == 0) return 31; /*error: invalid colortype*/ + + if(info_png->interlace_method == 0) { + if(bpp < 8 && w * bpp != ((w * bpp + 7u) / 8u) * 8u) { + CERROR_TRY_RETURN(unfilter(in, in, w, h, bpp)); + removePaddingBits(out, in, w * bpp, ((w * bpp + 7u) / 8u) * 8u, h); + } + /*we can immediately filter into the out buffer, no other steps needed*/ + else CERROR_TRY_RETURN(unfilter(out, in, w, h, bpp)); + } else /*interlace_method is 1 (Adam7)*/ { + unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned i; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + for(i = 0; i != 7; ++i) { + CERROR_TRY_RETURN(unfilter(&in[padded_passstart[i]], &in[filter_passstart[i]], passw[i], passh[i], bpp)); + /*TODO: possible efficiency improvement: if in this reduced image the bits fit nicely in 1 scanline, + move bytes instead of bits or move not at all*/ + if(bpp < 8) { + /*remove padding bits in scanlines; after this there still may be padding + bits between the different reduced images: each reduced image still starts nicely at a byte*/ + removePaddingBits(&in[passstart[i]], &in[padded_passstart[i]], passw[i] * bpp, + ((passw[i] * bpp + 7u) / 8u) * 8u, passh[i]); + } + } + + Adam7_deinterlace(out, in, w, h, bpp); + } + + return 0; +} + +static unsigned readChunk_PLTE(LodePNGColorMode* color, const unsigned char* data, size_t chunkLength) { + unsigned pos = 0, i; + color->palettesize = chunkLength / 3u; + if(color->palettesize == 0 || color->palettesize > 256) return 38; /*error: palette too small or big*/ + lodepng_color_mode_alloc_palette(color); + if(!color->palette && color->palettesize) { + color->palettesize = 0; + return 83; /*alloc fail*/ + } + + for(i = 0; i != color->palettesize; ++i) { + color->palette[4 * i + 0] = data[pos++]; /*R*/ + color->palette[4 * i + 1] = data[pos++]; /*G*/ + color->palette[4 * i + 2] = data[pos++]; /*B*/ + color->palette[4 * i + 3] = 255; /*alpha*/ + } + + return 0; /* OK */ +} + +static unsigned readChunk_tRNS(LodePNGColorMode* color, const unsigned char* data, size_t chunkLength) { + unsigned i; + if(color->colortype == LCT_PALETTE) { + /*error: more alpha values given than there are palette entries*/ + if(chunkLength > color->palettesize) return 39; + + for(i = 0; i != chunkLength; ++i) color->palette[4 * i + 3] = data[i]; + } else if(color->colortype == LCT_GREY) { + /*error: this chunk must be 2 bytes for grayscale image*/ + if(chunkLength != 2) return 30; + + color->key_defined = 1; + color->key_r = color->key_g = color->key_b = 256u * data[0] + data[1]; + } else if(color->colortype == LCT_RGB) { + /*error: this chunk must be 6 bytes for RGB image*/ + if(chunkLength != 6) return 41; + + color->key_defined = 1; + color->key_r = 256u * data[0] + data[1]; + color->key_g = 256u * data[2] + data[3]; + color->key_b = 256u * data[4] + data[5]; + } + else return 42; /*error: tRNS chunk not allowed for other color models*/ + + return 0; /* OK */ +} + + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +/*background color chunk (bKGD)*/ +static unsigned readChunk_bKGD(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { + if(info->color.colortype == LCT_PALETTE) { + /*error: this chunk must be 1 byte for indexed color image*/ + if(chunkLength != 1) return 43; + + /*error: invalid palette index, or maybe this chunk appeared before PLTE*/ + if(data[0] >= info->color.palettesize) return 103; + + info->background_defined = 1; + info->background_r = info->background_g = info->background_b = data[0]; + } else if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA) { + /*error: this chunk must be 2 bytes for grayscale image*/ + if(chunkLength != 2) return 44; + + /*the values are truncated to bitdepth in the PNG file*/ + info->background_defined = 1; + info->background_r = info->background_g = info->background_b = 256u * data[0] + data[1]; + } else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA) { + /*error: this chunk must be 6 bytes for grayscale image*/ + if(chunkLength != 6) return 45; + + /*the values are truncated to bitdepth in the PNG file*/ + info->background_defined = 1; + info->background_r = 256u * data[0] + data[1]; + info->background_g = 256u * data[2] + data[3]; + info->background_b = 256u * data[4] + data[5]; + } + + return 0; /* OK */ +} + +/*text chunk (tEXt)*/ +static unsigned readChunk_tEXt(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { + unsigned error = 0; + char *key = 0, *str = 0; + + while(!error) /*not really a while loop, only used to break on error*/ { + unsigned length, string2_begin; + + length = 0; + while(length < chunkLength && data[length] != 0) ++length; + /*even though it's not allowed by the standard, no error is thrown if + there's no null termination char, if the text is empty*/ + if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ + + key = (char*)lodepng_malloc(length + 1); + if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ + + lodepng_memcpy(key, data, length); + key[length] = 0; + + string2_begin = length + 1; /*skip keyword null terminator*/ + + length = (unsigned)(chunkLength < string2_begin ? 0 : chunkLength - string2_begin); + str = (char*)lodepng_malloc(length + 1); + if(!str) CERROR_BREAK(error, 83); /*alloc fail*/ + + lodepng_memcpy(str, data + string2_begin, length); + str[length] = 0; + + error = lodepng_add_text(info, key, str); + + break; + } + + lodepng_free(key); + lodepng_free(str); + + return error; +} + +/*compressed text chunk (zTXt)*/ +static unsigned readChunk_zTXt(LodePNGInfo* info, const LodePNGDecoderSettings* decoder, + const unsigned char* data, size_t chunkLength) { + unsigned error = 0; + + /*copy the object to change parameters in it*/ + LodePNGDecompressSettings zlibsettings = decoder->zlibsettings; + + unsigned length, string2_begin; + char *key = 0; + unsigned char* str = 0; + size_t size = 0; + + while(!error) /*not really a while loop, only used to break on error*/ { + for(length = 0; length < chunkLength && data[length] != 0; ++length) ; + if(length + 2 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/ + if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ + + key = (char*)lodepng_malloc(length + 1); + if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ + + lodepng_memcpy(key, data, length); + key[length] = 0; + + if(data[length + 1] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/ + + string2_begin = length + 2; + if(string2_begin > chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/ + + length = (unsigned)chunkLength - string2_begin; + zlibsettings.max_output_size = decoder->max_text_size; + /*will fail if zlib error, e.g. if length is too small*/ + error = zlib_decompress(&str, &size, 0, &data[string2_begin], + length, &zlibsettings); + /*error: compressed text larger than decoder->max_text_size*/ + if(error && size > zlibsettings.max_output_size) error = 112; + if(error) break; + error = lodepng_add_text_sized(info, key, (char*)str, size); + break; + } + + lodepng_free(key); + lodepng_free(str); + + return error; +} + +/*international text chunk (iTXt)*/ +static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecoderSettings* decoder, + const unsigned char* data, size_t chunkLength) { + unsigned error = 0; + unsigned i; + + /*copy the object to change parameters in it*/ + LodePNGDecompressSettings zlibsettings = decoder->zlibsettings; + + unsigned length, begin, compressed; + char *key = 0, *langtag = 0, *transkey = 0; + + while(!error) /*not really a while loop, only used to break on error*/ { + /*Quick check if the chunk length isn't too small. Even without check + it'd still fail with other error checks below if it's too short. This just gives a different error code.*/ + if(chunkLength < 5) CERROR_BREAK(error, 30); /*iTXt chunk too short*/ + + /*read the key*/ + for(length = 0; length < chunkLength && data[length] != 0; ++length) ; + if(length + 3 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination char, corrupt?*/ + if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ + + key = (char*)lodepng_malloc(length + 1); + if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ + + lodepng_memcpy(key, data, length); + key[length] = 0; + + /*read the compression method*/ + compressed = data[length + 1]; + if(data[length + 2] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/ + + /*even though it's not allowed by the standard, no error is thrown if + there's no null termination char, if the text is empty for the next 3 texts*/ + + /*read the langtag*/ + begin = length + 3; + length = 0; + for(i = begin; i < chunkLength && data[i] != 0; ++i) ++length; + + langtag = (char*)lodepng_malloc(length + 1); + if(!langtag) CERROR_BREAK(error, 83); /*alloc fail*/ + + lodepng_memcpy(langtag, data + begin, length); + langtag[length] = 0; + + /*read the transkey*/ + begin += length + 1; + length = 0; + for(i = begin; i < chunkLength && data[i] != 0; ++i) ++length; + + transkey = (char*)lodepng_malloc(length + 1); + if(!transkey) CERROR_BREAK(error, 83); /*alloc fail*/ + + lodepng_memcpy(transkey, data + begin, length); + transkey[length] = 0; + + /*read the actual text*/ + begin += length + 1; + + length = (unsigned)chunkLength < begin ? 0 : (unsigned)chunkLength - begin; + + if(compressed) { + unsigned char* str = 0; + size_t size = 0; + zlibsettings.max_output_size = decoder->max_text_size; + /*will fail if zlib error, e.g. if length is too small*/ + error = zlib_decompress(&str, &size, 0, &data[begin], + length, &zlibsettings); + /*error: compressed text larger than decoder->max_text_size*/ + if(error && size > zlibsettings.max_output_size) error = 112; + if(!error) error = lodepng_add_itext_sized(info, key, langtag, transkey, (char*)str, size); + lodepng_free(str); + } else { + error = lodepng_add_itext_sized(info, key, langtag, transkey, (const char*)(data + begin), length); + } + + break; + } + + lodepng_free(key); + lodepng_free(langtag); + lodepng_free(transkey); + + return error; +} + +static unsigned readChunk_tIME(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { + if(chunkLength != 7) return 73; /*invalid tIME chunk size*/ + + info->time_defined = 1; + info->time.year = 256u * data[0] + data[1]; + info->time.month = data[2]; + info->time.day = data[3]; + info->time.hour = data[4]; + info->time.minute = data[5]; + info->time.second = data[6]; + + return 0; /* OK */ +} + +static unsigned readChunk_pHYs(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { + if(chunkLength != 9) return 74; /*invalid pHYs chunk size*/ + + info->phys_defined = 1; + info->phys_x = 16777216u * data[0] + 65536u * data[1] + 256u * data[2] + data[3]; + info->phys_y = 16777216u * data[4] + 65536u * data[5] + 256u * data[6] + data[7]; + info->phys_unit = data[8]; + + return 0; /* OK */ +} + +static unsigned readChunk_gAMA(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { + if(chunkLength != 4) return 96; /*invalid gAMA chunk size*/ + + info->gama_defined = 1; + info->gama_gamma = 16777216u * data[0] + 65536u * data[1] + 256u * data[2] + data[3]; + + return 0; /* OK */ +} + +static unsigned readChunk_cHRM(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { + if(chunkLength != 32) return 97; /*invalid cHRM chunk size*/ + + info->chrm_defined = 1; + info->chrm_white_x = 16777216u * data[ 0] + 65536u * data[ 1] + 256u * data[ 2] + data[ 3]; + info->chrm_white_y = 16777216u * data[ 4] + 65536u * data[ 5] + 256u * data[ 6] + data[ 7]; + info->chrm_red_x = 16777216u * data[ 8] + 65536u * data[ 9] + 256u * data[10] + data[11]; + info->chrm_red_y = 16777216u * data[12] + 65536u * data[13] + 256u * data[14] + data[15]; + info->chrm_green_x = 16777216u * data[16] + 65536u * data[17] + 256u * data[18] + data[19]; + info->chrm_green_y = 16777216u * data[20] + 65536u * data[21] + 256u * data[22] + data[23]; + info->chrm_blue_x = 16777216u * data[24] + 65536u * data[25] + 256u * data[26] + data[27]; + info->chrm_blue_y = 16777216u * data[28] + 65536u * data[29] + 256u * data[30] + data[31]; + + return 0; /* OK */ +} + +static unsigned readChunk_sRGB(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { + if(chunkLength != 1) return 98; /*invalid sRGB chunk size (this one is never ignored)*/ + + info->srgb_defined = 1; + info->srgb_intent = data[0]; + + return 0; /* OK */ +} + +static unsigned readChunk_iCCP(LodePNGInfo* info, const LodePNGDecoderSettings* decoder, + const unsigned char* data, size_t chunkLength) { + unsigned error = 0; + unsigned i; + size_t size = 0; + /*copy the object to change parameters in it*/ + LodePNGDecompressSettings zlibsettings = decoder->zlibsettings; + + unsigned length, string2_begin; + + if(info->iccp_defined) lodepng_clear_icc(info); + + for(length = 0; length < chunkLength && data[length] != 0; ++length) ; + if(length + 2 >= chunkLength) return 75; /*no null termination, corrupt?*/ + if(length < 1 || length > 79) return 89; /*keyword too short or long*/ + + info->iccp_name = (char*)lodepng_malloc(length + 1); + if(!info->iccp_name) return 83; /*alloc fail*/ + + info->iccp_name[length] = 0; + for(i = 0; i != length; ++i) info->iccp_name[i] = (char)data[i]; + + if(data[length + 1] != 0) return 72; /*the 0 byte indicating compression must be 0*/ + + string2_begin = length + 2; + if(string2_begin > chunkLength) return 75; /*no null termination, corrupt?*/ + + length = (unsigned)chunkLength - string2_begin; + zlibsettings.max_output_size = decoder->max_icc_size; + error = zlib_decompress(&info->iccp_profile, &size, 0, + &data[string2_begin], + length, &zlibsettings); + /*error: ICC profile larger than decoder->max_icc_size*/ + if(error && size > zlibsettings.max_output_size) error = 113; + info->iccp_profile_size = (unsigned)size; + if(!error && !info->iccp_profile_size) error = 123; /*invalid ICC profile size*/ + + if(!error) info->iccp_defined = 1; + return error; +} + +static unsigned readChunk_cICP(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { + if(chunkLength != 4) return 117; /*invalid cICP chunk size*/ + + info->cicp_defined = 1; + /* No error checking for value ranges is done here, that is up to a CICP + handling library, not the PNG decoding. Just pass on the metadata. */ + info->cicp_color_primaries = data[0]; + info->cicp_transfer_function = data[1]; + info->cicp_matrix_coefficients = data[2]; + info->cicp_video_full_range_flag = data[3]; + + return 0; /* OK */ +} + +static unsigned readChunk_mDCV(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { + if(chunkLength != 24) return 119; /*invalid mDCV chunk size*/ + + info->mdcv_defined = 1; + info->mdcv_red_x = 256u * data[0] + data[1]; + info->mdcv_red_y = 256u * data[2] + data[3]; + info->mdcv_green_x = 256u * data[4] + data[5]; + info->mdcv_green_y = 256u * data[6] + data[7]; + info->mdcv_blue_x = 256u * data[8] + data[9]; + info->mdcv_blue_y = 256u * data[10] + data[11]; + info->mdcv_white_x = 256u * data[12] + data[13]; + info->mdcv_white_y = 256u * data[14] + data[15]; + info->mdcv_max_luminance = 16777216u * data[16] + 65536u * data[17] + 256u * data[18] + data[19]; + info->mdcv_min_luminance = 16777216u * data[20] + 65536u * data[21] + 256u * data[22] + data[23]; + + return 0; /* OK */ +} + +static unsigned readChunk_cLLI(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { + if(chunkLength != 8) return 120; /*invalid cLLI chunk size*/ + + info->clli_defined = 1; + info->clli_max_cll = 16777216u * data[0] + 65536u * data[1] + 256u * data[2] + data[3]; + info->clli_max_fall = 16777216u * data[4] + 65536u * data[5] + 256u * data[6] + data[7]; + + return 0; /* OK */ +} + +static unsigned readChunk_eXIf(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { + return lodepng_set_exif(info, data, (unsigned)chunkLength); +} + +/*significant bits chunk (sBIT)*/ +static unsigned readChunk_sBIT(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) { + unsigned bitdepth = (info->color.colortype == LCT_PALETTE) ? 8 : info->color.bitdepth; + if(info->color.colortype == LCT_GREY) { + /*error: this chunk must be 1 bytes for grayscale image*/ + if(chunkLength != 1) return 114; + if(data[0] == 0 || data[0] > bitdepth) return 115; + info->sbit_defined = 1; + info->sbit_r = info->sbit_g = info->sbit_b = data[0]; /*setting g and b is not required, but sensible*/ + } else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_PALETTE) { + /*error: this chunk must be 3 bytes for RGB and palette image*/ + if(chunkLength != 3) return 114; + if(data[0] == 0 || data[1] == 0 || data[2] == 0) return 115; + if(data[0] > bitdepth || data[1] > bitdepth || data[2] > bitdepth) return 115; + info->sbit_defined = 1; + info->sbit_r = data[0]; + info->sbit_g = data[1]; + info->sbit_b = data[2]; + } else if(info->color.colortype == LCT_GREY_ALPHA) { + /*error: this chunk must be 2 byte for grayscale with alpha image*/ + if(chunkLength != 2) return 114; + if(data[0] == 0 || data[1] == 0) return 115; + if(data[0] > bitdepth || data[1] > bitdepth) return 115; + info->sbit_defined = 1; + info->sbit_r = info->sbit_g = info->sbit_b = data[0]; /*setting g and b is not required, but sensible*/ + info->sbit_a = data[1]; + } else if(info->color.colortype == LCT_RGBA) { + /*error: this chunk must be 4 bytes for grayscale image*/ + if(chunkLength != 4) return 114; + if(data[0] == 0 || data[1] == 0 || data[2] == 0 || data[3] == 0) return 115; + if(data[0] > bitdepth || data[1] > bitdepth || data[2] > bitdepth || data[3] > bitdepth) return 115; + info->sbit_defined = 1; + info->sbit_r = data[0]; + info->sbit_g = data[1]; + info->sbit_b = data[2]; + info->sbit_a = data[3]; + } + + return 0; /* OK */ +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +unsigned lodepng_inspect_chunk(LodePNGState* state, size_t pos, + const unsigned char* in, size_t insize) { + const unsigned char* chunk = in + pos; + unsigned chunkLength; + const unsigned char* data; + unsigned unhandled = 0; + unsigned error = 0; + + if(pos + 4 > insize) return 30; + chunkLength = lodepng_chunk_length(chunk); + if(chunkLength > 2147483647) return 63; + data = lodepng_chunk_data_const(chunk); + if(chunkLength + 12 > insize - pos) return 30; + + if(lodepng_chunk_type_equals(chunk, "PLTE")) { + error = readChunk_PLTE(&state->info_png.color, data, chunkLength); + } else if(lodepng_chunk_type_equals(chunk, "tRNS")) { + error = readChunk_tRNS(&state->info_png.color, data, chunkLength); +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + } else if(lodepng_chunk_type_equals(chunk, "bKGD")) { + error = readChunk_bKGD(&state->info_png, data, chunkLength); + } else if(lodepng_chunk_type_equals(chunk, "tEXt")) { + error = readChunk_tEXt(&state->info_png, data, chunkLength); + } else if(lodepng_chunk_type_equals(chunk, "zTXt")) { + error = readChunk_zTXt(&state->info_png, &state->decoder, data, chunkLength); + } else if(lodepng_chunk_type_equals(chunk, "iTXt")) { + error = readChunk_iTXt(&state->info_png, &state->decoder, data, chunkLength); + } else if(lodepng_chunk_type_equals(chunk, "tIME")) { + error = readChunk_tIME(&state->info_png, data, chunkLength); + } else if(lodepng_chunk_type_equals(chunk, "pHYs")) { + error = readChunk_pHYs(&state->info_png, data, chunkLength); + } else if(lodepng_chunk_type_equals(chunk, "gAMA")) { + error = readChunk_gAMA(&state->info_png, data, chunkLength); + } else if(lodepng_chunk_type_equals(chunk, "cHRM")) { + error = readChunk_cHRM(&state->info_png, data, chunkLength); + } else if(lodepng_chunk_type_equals(chunk, "sRGB")) { + error = readChunk_sRGB(&state->info_png, data, chunkLength); + } else if(lodepng_chunk_type_equals(chunk, "iCCP")) { + error = readChunk_iCCP(&state->info_png, &state->decoder, data, chunkLength); + } else if(lodepng_chunk_type_equals(chunk, "cICP")) { + error = readChunk_cICP(&state->info_png, data, chunkLength); + } else if(lodepng_chunk_type_equals(chunk, "mDCV")) { + error = readChunk_mDCV(&state->info_png, data, chunkLength); + } else if(lodepng_chunk_type_equals(chunk, "cLLI")) { + error = readChunk_cLLI(&state->info_png, data, chunkLength); + } else if(lodepng_chunk_type_equals(chunk, "eXIf")) { + error = readChunk_eXIf(&state->info_png, data, chunkLength); + } else if(lodepng_chunk_type_equals(chunk, "sBIT")) { + error = readChunk_sBIT(&state->info_png, data, chunkLength); +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + } else { + /* unhandled chunk is ok (is not an error) */ + unhandled = 1; + } + + if(!error && !unhandled && !state->decoder.ignore_crc) { + if(lodepng_chunk_check_crc(chunk)) return 57; /*invalid CRC*/ + } + + return error; +} + +/*read a PNG, the result will be in the same color type as the PNG (hence "generic")*/ +static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize) { + unsigned char IEND = 0; + const unsigned char* chunk; /*points to beginning of next chunk*/ + unsigned char* idat; /*the data from idat chunks, zlib compressed*/ + size_t idatsize = 0; + unsigned char* scanlines = 0; + size_t scanlines_size = 0, expected_size = 0; + size_t outsize = 0; + + /*for unknown chunk order*/ + unsigned unknown = 0; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + unsigned critical_pos = 1; /*1 = after IHDR, 2 = after PLTE, 3 = after IDAT*/ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + + + /* safe output values in case error happens */ + *out = 0; + *w = *h = 0; + + state->error = lodepng_inspect(w, h, state, in, insize); /*reads header and resets other parameters in state->info_png*/ + if(state->error) return; + + if(lodepng_pixel_overflow(*w, *h, &state->info_png.color, &state->info_raw)) { + CERROR_RETURN(state->error, 92); /*overflow possible due to amount of pixels*/ + } + + /*the input filesize is a safe upper bound for the sum of idat chunks size*/ + idat = (unsigned char*)lodepng_malloc(insize); + if(!idat) CERROR_RETURN(state->error, 83); /*alloc fail*/ + + chunk = &in[33]; /*first byte of the first chunk after the header*/ + + /*loop through the chunks, ignoring unknown chunks and stopping at IEND chunk. + IDAT data is put at the start of the in buffer*/ + while(!IEND && !state->error) { + unsigned chunkLength; + const unsigned char* data; /*the data in the chunk*/ + size_t pos = (size_t)(chunk - in); + + /*error: next chunk out of bounds of the in buffer*/ + if(chunk < in || pos + 12 > insize) { + if(state->decoder.ignore_end) break; /*other errors may still happen though*/ + CERROR_BREAK(state->error, 30); + } + + /*length of the data of the chunk, excluding the 12 bytes for length, chunk type and CRC*/ + chunkLength = lodepng_chunk_length(chunk); + /*error: chunk length larger than the max PNG chunk size*/ + if(chunkLength > 2147483647) { + if(state->decoder.ignore_end) break; /*other errors may still happen though*/ + CERROR_BREAK(state->error, 63); + } + + if(pos + (size_t)chunkLength + 12 > insize || pos + (size_t)chunkLength + 12 < pos) { + CERROR_BREAK(state->error, 64); /*error: size of the in buffer too small to contain next chunk (or int overflow)*/ + } + + data = lodepng_chunk_data_const(chunk); + + unknown = 0; + + /*IDAT chunk, containing compressed image data*/ + if(lodepng_chunk_type_equals(chunk, "IDAT")) { + size_t newsize; + if(lodepng_addofl(idatsize, chunkLength, &newsize)) CERROR_BREAK(state->error, 95); + if(newsize > insize) CERROR_BREAK(state->error, 95); + lodepng_memcpy(idat + idatsize, data, chunkLength); + idatsize += chunkLength; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + critical_pos = 3; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + } else if(lodepng_chunk_type_equals(chunk, "IEND")) { + /*IEND chunk*/ + IEND = 1; + } else if(lodepng_chunk_type_equals(chunk, "PLTE")) { + /*palette chunk (PLTE)*/ + state->error = readChunk_PLTE(&state->info_png.color, data, chunkLength); + if(state->error) break; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + critical_pos = 2; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + } else if(lodepng_chunk_type_equals(chunk, "tRNS")) { + /*palette transparency chunk (tRNS). Even though this one is an ancillary chunk , it is still compiled + in without 'LODEPNG_COMPILE_ANCILLARY_CHUNKS' because it contains essential color information that + affects the alpha channel of pixels. */ + state->error = readChunk_tRNS(&state->info_png.color, data, chunkLength); + if(state->error) break; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*background color chunk (bKGD)*/ + } else if(lodepng_chunk_type_equals(chunk, "bKGD")) { + state->error = readChunk_bKGD(&state->info_png, data, chunkLength); + if(state->error) break; + } else if(lodepng_chunk_type_equals(chunk, "tEXt")) { + /*text chunk (tEXt)*/ + if(state->decoder.read_text_chunks) { + state->error = readChunk_tEXt(&state->info_png, data, chunkLength); + if(state->error) break; + } + } else if(lodepng_chunk_type_equals(chunk, "zTXt")) { + /*compressed text chunk (zTXt)*/ + if(state->decoder.read_text_chunks) { + state->error = readChunk_zTXt(&state->info_png, &state->decoder, data, chunkLength); + if(state->error) break; + } + } else if(lodepng_chunk_type_equals(chunk, "iTXt")) { + /*international text chunk (iTXt)*/ + if(state->decoder.read_text_chunks) { + state->error = readChunk_iTXt(&state->info_png, &state->decoder, data, chunkLength); + if(state->error) break; + } + } else if(lodepng_chunk_type_equals(chunk, "tIME")) { + state->error = readChunk_tIME(&state->info_png, data, chunkLength); + if(state->error) break; + } else if(lodepng_chunk_type_equals(chunk, "pHYs")) { + state->error = readChunk_pHYs(&state->info_png, data, chunkLength); + if(state->error) break; + } else if(lodepng_chunk_type_equals(chunk, "gAMA")) { + state->error = readChunk_gAMA(&state->info_png, data, chunkLength); + if(state->error) break; + } else if(lodepng_chunk_type_equals(chunk, "cHRM")) { + state->error = readChunk_cHRM(&state->info_png, data, chunkLength); + if(state->error) break; + } else if(lodepng_chunk_type_equals(chunk, "sRGB")) { + state->error = readChunk_sRGB(&state->info_png, data, chunkLength); + if(state->error) break; + } else if(lodepng_chunk_type_equals(chunk, "iCCP")) { + state->error = readChunk_iCCP(&state->info_png, &state->decoder, data, chunkLength); + if(state->error) break; + } else if(lodepng_chunk_type_equals(chunk, "cICP")) { + state->error = readChunk_cICP(&state->info_png, data, chunkLength); + if(state->error) break; + } else if(lodepng_chunk_type_equals(chunk, "mDCV")) { + state->error = readChunk_mDCV(&state->info_png, data, chunkLength); + if(state->error) break; + } else if(lodepng_chunk_type_equals(chunk, "cLLI")) { + state->error = readChunk_cLLI(&state->info_png, data, chunkLength); + if(state->error) break; + } else if(lodepng_chunk_type_equals(chunk, "eXIf")) { + state->error = readChunk_eXIf(&state->info_png, data, chunkLength); + if(state->error) break; + } else if(lodepng_chunk_type_equals(chunk, "sBIT")) { + state->error = readChunk_sBIT(&state->info_png, data, chunkLength); + if(state->error) break; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + } else /*it's not an implemented chunk type, so ignore it: skip over the data*/ { + if(!lodepng_chunk_type_name_valid(chunk)) { + CERROR_BREAK(state->error, 121); /* invalid chunk type name */ + } + if(lodepng_chunk_reserved(chunk)) { + CERROR_BREAK(state->error, 122); /* invalid third lowercase character */ + } + + /*error: unknown critical chunk (5th bit of first byte of chunk type is 0)*/ + if(!state->decoder.ignore_critical && !lodepng_chunk_ancillary(chunk)) { + CERROR_BREAK(state->error, 69); + } + + unknown = 1; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + if(state->decoder.remember_unknown_chunks) { + state->error = lodepng_chunk_append(&state->info_png.unknown_chunks_data[critical_pos - 1], + &state->info_png.unknown_chunks_size[critical_pos - 1], chunk); + if(state->error) break; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + } + + if(!state->decoder.ignore_crc && !unknown) /*check CRC if wanted, only on known chunk types*/ { + if(lodepng_chunk_check_crc(chunk)) CERROR_BREAK(state->error, 57); /*invalid CRC*/ + } + + if(!IEND) chunk = lodepng_chunk_next_const(chunk, in + insize); + } + + if(!state->error && state->info_png.color.colortype == LCT_PALETTE && !state->info_png.color.palette) { + state->error = 106; /* error: PNG file must have PLTE chunk if color type is palette */ + } + + if(!state->error) { + /*predict output size, to allocate exact size for output buffer to avoid more dynamic allocation. + If the decompressed size does not match the prediction, the image must be corrupt.*/ + if(state->info_png.interlace_method == 0) { + unsigned bpp = lodepng_get_bpp(&state->info_png.color); + expected_size = lodepng_get_raw_size_idat(*w, *h, bpp); + } else { + unsigned bpp = lodepng_get_bpp(&state->info_png.color); + /*Adam-7 interlaced: expected size is the sum of the 7 sub-images sizes*/ + expected_size = 0; + expected_size += lodepng_get_raw_size_idat((*w + 7) >> 3, (*h + 7) >> 3, bpp); + if(*w > 4) expected_size += lodepng_get_raw_size_idat((*w + 3) >> 3, (*h + 7) >> 3, bpp); + expected_size += lodepng_get_raw_size_idat((*w + 3) >> 2, (*h + 3) >> 3, bpp); + if(*w > 2) expected_size += lodepng_get_raw_size_idat((*w + 1) >> 2, (*h + 3) >> 2, bpp); + expected_size += lodepng_get_raw_size_idat((*w + 1) >> 1, (*h + 1) >> 2, bpp); + if(*w > 1) expected_size += lodepng_get_raw_size_idat((*w + 0) >> 1, (*h + 1) >> 1, bpp); + expected_size += lodepng_get_raw_size_idat((*w + 0), (*h + 0) >> 1, bpp); + } + + state->error = zlib_decompress(&scanlines, &scanlines_size, expected_size, idat, idatsize, &state->decoder.zlibsettings); + } + if(!state->error && scanlines_size != expected_size) state->error = 91; /*decompressed size doesn't match prediction*/ + lodepng_free(idat); + + if(!state->error) { + outsize = lodepng_get_raw_size(*w, *h, &state->info_png.color); + *out = (unsigned char*)lodepng_malloc(outsize); + if(!*out) state->error = 83; /*alloc fail*/ + } + if(!state->error) { + lodepng_memset(*out, 0, outsize); + state->error = postProcessScanlines(*out, scanlines, *w, *h, &state->info_png); + } + lodepng_free(scanlines); +} + +unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize) { + *out = 0; + decodeGeneric(out, w, h, state, in, insize); + if(state->error) return state->error; + if(!state->decoder.color_convert || lodepng_color_mode_equal(&state->info_raw, &state->info_png.color)) { + /*same color type, no copying or converting of data needed*/ + /*store the info_png color settings on the info_raw so that the info_raw still reflects what colortype + the raw image has to the end user*/ + if(!state->decoder.color_convert) { + state->error = lodepng_color_mode_copy(&state->info_raw, &state->info_png.color); + if(state->error) return state->error; + } + } else { /*color conversion needed*/ + unsigned char* data = *out; + size_t outsize; + + /*TODO: check if this works according to the statement in the documentation: "The converter can convert + from grayscale input color type, to 8-bit grayscale or grayscale with alpha"*/ + if(!(state->info_raw.colortype == LCT_RGB || state->info_raw.colortype == LCT_RGBA) + && !(state->info_raw.bitdepth == 8)) { + return 56; /*unsupported color mode conversion*/ + } + + outsize = lodepng_get_raw_size(*w, *h, &state->info_raw); + *out = (unsigned char*)lodepng_malloc(outsize); + if(!(*out)) { + state->error = 83; /*alloc fail*/ + } + else state->error = lodepng_convert(*out, data, &state->info_raw, + &state->info_png.color, *w, *h); + lodepng_free(data); + } + return state->error; +} + +unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, + size_t insize, LodePNGColorType colortype, unsigned bitdepth) { + unsigned error; + LodePNGState state; + lodepng_state_init(&state); + state.info_raw.colortype = colortype; + state.info_raw.bitdepth = bitdepth; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*disable reading things that this function doesn't output*/ + state.decoder.read_text_chunks = 0; + state.decoder.remember_unknown_chunks = 0; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + error = lodepng_decode(out, w, h, &state, in, insize); + lodepng_state_cleanup(&state); + return error; +} + +unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize) { + return lodepng_decode_memory(out, w, h, in, insize, LCT_RGBA, 8); +} + +unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize) { + return lodepng_decode_memory(out, w, h, in, insize, LCT_RGB, 8); +} + +#ifdef LODEPNG_COMPILE_DISK +unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename, + LodePNGColorType colortype, unsigned bitdepth) { + unsigned char* buffer = 0; + size_t buffersize; + unsigned error; + /* safe output values in case error happens */ + *out = 0; + *w = *h = 0; + error = lodepng_load_file(&buffer, &buffersize, filename); + if(!error) error = lodepng_decode_memory(out, w, h, buffer, buffersize, colortype, bitdepth); + lodepng_free(buffer); + return error; +} + +unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename) { + return lodepng_decode_file(out, w, h, filename, LCT_RGBA, 8); +} + +unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename) { + return lodepng_decode_file(out, w, h, filename, LCT_RGB, 8); +} +#endif /*LODEPNG_COMPILE_DISK*/ + +void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings) { + settings->color_convert = 1; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + settings->read_text_chunks = 1; + settings->remember_unknown_chunks = 0; + settings->max_text_size = 16777216; + settings->max_icc_size = 16777216; /* 16MB is much more than enough for any reasonable ICC profile */ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + settings->ignore_crc = 0; + settings->ignore_critical = 0; + settings->ignore_end = 0; + lodepng_decompress_settings_init(&settings->zlibsettings); +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +#if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) + +void lodepng_state_init(LodePNGState* state) { +#ifdef LODEPNG_COMPILE_DECODER + lodepng_decoder_settings_init(&state->decoder); +#endif /*LODEPNG_COMPILE_DECODER*/ +#ifdef LODEPNG_COMPILE_ENCODER + lodepng_encoder_settings_init(&state->encoder); +#endif /*LODEPNG_COMPILE_ENCODER*/ + lodepng_color_mode_init(&state->info_raw); + lodepng_info_init(&state->info_png); + state->error = 1; +} + +void lodepng_state_cleanup(LodePNGState* state) { + lodepng_color_mode_cleanup(&state->info_raw); + lodepng_info_cleanup(&state->info_png); +} + +unsigned lodepng_state_copy(LodePNGState* dest, const LodePNGState* source) { + lodepng_state_cleanup(dest); + *dest = *source; + lodepng_color_mode_init(&dest->info_raw); + lodepng_info_init(&dest->info_png); + dest->error = lodepng_color_mode_copy(&dest->info_raw, &source->info_raw); + if(dest->error) return dest->error; + dest->error = lodepng_info_copy(&dest->info_png, &source->info_png); + return dest->error; +} + +#endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */ + +#ifdef LODEPNG_COMPILE_ENCODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / PNG Encoder / */ +/* ////////////////////////////////////////////////////////////////////////// */ + + +static unsigned writeSignature(ucvector* out) { + size_t pos = out->size; + const unsigned char signature[] = {137, 80, 78, 71, 13, 10, 26, 10}; + /*8 bytes PNG signature, aka the magic bytes*/ + if(!ucvector_resize(out, out->size + 8)) return 83; /*alloc fail*/ + lodepng_memcpy(out->data + pos, signature, 8); + return 0; +} + +static unsigned addChunk_IHDR(ucvector* out, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth, unsigned interlace_method) { + unsigned char *chunk, *data; + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 13, "IHDR")); + data = chunk + 8; + + lodepng_set32bitInt(data + 0, w); /*width*/ + lodepng_set32bitInt(data + 4, h); /*height*/ + data[8] = (unsigned char)bitdepth; /*bit depth*/ + data[9] = (unsigned char)colortype; /*color type*/ + data[10] = 0; /*compression method*/ + data[11] = 0; /*filter method*/ + data[12] = interlace_method; /*interlace method*/ + + lodepng_chunk_generate_crc(chunk); + return 0; +} + +/* only adds the chunk if needed (there is a key or palette with alpha) */ +static unsigned addChunk_PLTE(ucvector* out, const LodePNGColorMode* info) { + unsigned char* chunk; + size_t i, j = 8; + + if(info->palettesize == 0 || info->palettesize > 256) { + return 68; /*invalid palette size, it is only allowed to be 1-256*/ + } + + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, info->palettesize * 3, "PLTE")); + + for(i = 0; i != info->palettesize; ++i) { + /*add all channels except alpha channel*/ + chunk[j++] = info->palette[i * 4 + 0]; + chunk[j++] = info->palette[i * 4 + 1]; + chunk[j++] = info->palette[i * 4 + 2]; + } + + lodepng_chunk_generate_crc(chunk); + return 0; +} + +static unsigned addChunk_tRNS(ucvector* out, const LodePNGColorMode* info) { + unsigned char* chunk = 0; + + if(info->colortype == LCT_PALETTE) { + size_t i, amount = info->palettesize; + /*the tail of palette values that all have 255 as alpha, does not have to be encoded*/ + for(i = info->palettesize; i != 0; --i) { + if(info->palette[4 * (i - 1) + 3] != 255) break; + --amount; + } + if(amount) { + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, amount, "tRNS")); + /*add the alpha channel values from the palette*/ + for(i = 0; i != amount; ++i) chunk[8 + i] = info->palette[4 * i + 3]; + } + } else if(info->colortype == LCT_GREY) { + if(info->key_defined) { + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 2, "tRNS")); + chunk[8] = (unsigned char)(info->key_r >> 8); + chunk[9] = (unsigned char)(info->key_r & 255); + } + } else if(info->colortype == LCT_RGB) { + if(info->key_defined) { + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 6, "tRNS")); + chunk[8] = (unsigned char)(info->key_r >> 8); + chunk[9] = (unsigned char)(info->key_r & 255); + chunk[10] = (unsigned char)(info->key_g >> 8); + chunk[11] = (unsigned char)(info->key_g & 255); + chunk[12] = (unsigned char)(info->key_b >> 8); + chunk[13] = (unsigned char)(info->key_b & 255); + } + } + + if(chunk) lodepng_chunk_generate_crc(chunk); + return 0; +} + +static unsigned addChunk_IDAT(ucvector* out, const unsigned char* data, size_t datasize, + const LodePNGCompressSettings* zlibsettings) { + unsigned error = 0; + unsigned char* zlib = 0; + size_t pos = 0; + size_t zlibsize = 0; + /* max chunk length allowed by the specification is 2147483647 bytes */ + const size_t max_chunk_length = 2147483647u; + + error = zlib_compress(&zlib, &zlibsize, data, datasize, zlibsettings); + while(!error) { + if(zlibsize - pos > max_chunk_length) { + error = lodepng_chunk_createv(out, max_chunk_length, "IDAT", zlib + pos); + pos += max_chunk_length; + } else { + error = lodepng_chunk_createv(out, zlibsize - pos, "IDAT", zlib + pos); + break; + } + } + lodepng_free(zlib); + return error; +} + +static unsigned addChunk_IEND(ucvector* out) { + return lodepng_chunk_createv(out, 0, "IEND", 0); +} + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + +static unsigned addChunk_tEXt(ucvector* out, const char* keyword, const char* textstring) { + unsigned char* chunk = 0; + size_t keysize = lodepng_strlen(keyword), textsize = lodepng_strlen(textstring); + size_t size = keysize + 1 + textsize; + if(keysize < 1 || keysize > 79) return 89; /*error: invalid keyword size*/ + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, size, "tEXt")); + lodepng_memcpy(chunk + 8, keyword, keysize); + chunk[8 + keysize] = 0; /*null termination char*/ + lodepng_memcpy(chunk + 9 + keysize, textstring, textsize); + lodepng_chunk_generate_crc(chunk); + return 0; +} + +static unsigned addChunk_zTXt(ucvector* out, const char* keyword, const char* textstring, + const LodePNGCompressSettings* zlibsettings) { + unsigned error = 0; + unsigned char* chunk = 0; + unsigned char* compressed = 0; + size_t compressedsize = 0; + size_t textsize = lodepng_strlen(textstring); + size_t keysize = lodepng_strlen(keyword); + if(keysize < 1 || keysize > 79) return 89; /*error: invalid keyword size*/ + + error = zlib_compress(&compressed, &compressedsize, + (const unsigned char*)textstring, textsize, zlibsettings); + if(!error) { + size_t size = keysize + 2 + compressedsize; + error = lodepng_chunk_init(&chunk, out, size, "zTXt"); + } + if(!error) { + lodepng_memcpy(chunk + 8, keyword, keysize); + chunk[8 + keysize] = 0; /*null termination char*/ + chunk[9 + keysize] = 0; /*compression method: 0*/ + lodepng_memcpy(chunk + 10 + keysize, compressed, compressedsize); + lodepng_chunk_generate_crc(chunk); + } + + lodepng_free(compressed); + return error; +} + +static unsigned addChunk_iTXt(ucvector* out, unsigned compress, const char* keyword, const char* langtag, + const char* transkey, const char* textstring, const LodePNGCompressSettings* zlibsettings) { + unsigned error = 0; + unsigned char* chunk = 0; + unsigned char* compressed = 0; + size_t compressedsize = 0; + size_t textsize = lodepng_strlen(textstring); + size_t keysize = lodepng_strlen(keyword), langsize = lodepng_strlen(langtag), transsize = lodepng_strlen(transkey); + + if(keysize < 1 || keysize > 79) return 89; /*error: invalid keyword size*/ + + if(compress) { + error = zlib_compress(&compressed, &compressedsize, + (const unsigned char*)textstring, textsize, zlibsettings); + } + if(!error) { + size_t size = keysize + 3 + langsize + 1 + transsize + 1 + (compress ? compressedsize : textsize); + error = lodepng_chunk_init(&chunk, out, size, "iTXt"); + } + if(!error) { + size_t pos = 8; + lodepng_memcpy(chunk + pos, keyword, keysize); + pos += keysize; + chunk[pos++] = 0; /*null termination char*/ + chunk[pos++] = (compress ? 1 : 0); /*compression flag*/ + chunk[pos++] = 0; /*compression method: 0*/ + lodepng_memcpy(chunk + pos, langtag, langsize); + pos += langsize; + chunk[pos++] = 0; /*null termination char*/ + lodepng_memcpy(chunk + pos, transkey, transsize); + pos += transsize; + chunk[pos++] = 0; /*null termination char*/ + if(compress) { + lodepng_memcpy(chunk + pos, compressed, compressedsize); + } else { + lodepng_memcpy(chunk + pos, textstring, textsize); + } + lodepng_chunk_generate_crc(chunk); + } + + lodepng_free(compressed); + return error; +} + +static unsigned addChunk_bKGD(ucvector* out, const LodePNGInfo* info) { + unsigned char* chunk = 0; + if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA) { + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 2, "bKGD")); + chunk[8] = (unsigned char)(info->background_r >> 8); + chunk[9] = (unsigned char)(info->background_r & 255); + } else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA) { + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 6, "bKGD")); + chunk[8] = (unsigned char)(info->background_r >> 8); + chunk[9] = (unsigned char)(info->background_r & 255); + chunk[10] = (unsigned char)(info->background_g >> 8); + chunk[11] = (unsigned char)(info->background_g & 255); + chunk[12] = (unsigned char)(info->background_b >> 8); + chunk[13] = (unsigned char)(info->background_b & 255); + } else if(info->color.colortype == LCT_PALETTE) { + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 1, "bKGD")); + chunk[8] = (unsigned char)(info->background_r & 255); /*palette index*/ + } + if(chunk) lodepng_chunk_generate_crc(chunk); + return 0; +} + +static unsigned addChunk_tIME(ucvector* out, const LodePNGTime* time) { + unsigned char* chunk; + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 7, "tIME")); + chunk[8] = (unsigned char)(time->year >> 8); + chunk[9] = (unsigned char)(time->year & 255); + chunk[10] = (unsigned char)time->month; + chunk[11] = (unsigned char)time->day; + chunk[12] = (unsigned char)time->hour; + chunk[13] = (unsigned char)time->minute; + chunk[14] = (unsigned char)time->second; + lodepng_chunk_generate_crc(chunk); + return 0; +} + +static unsigned addChunk_pHYs(ucvector* out, const LodePNGInfo* info) { + unsigned char* chunk; + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 9, "pHYs")); + lodepng_set32bitInt(chunk + 8, info->phys_x); + lodepng_set32bitInt(chunk + 12, info->phys_y); + chunk[16] = info->phys_unit; + lodepng_chunk_generate_crc(chunk); + return 0; +} + +static unsigned addChunk_gAMA(ucvector* out, const LodePNGInfo* info) { + unsigned char* chunk; + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 4, "gAMA")); + lodepng_set32bitInt(chunk + 8, info->gama_gamma); + lodepng_chunk_generate_crc(chunk); + return 0; +} + +static unsigned addChunk_cHRM(ucvector* out, const LodePNGInfo* info) { + unsigned char* chunk; + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 32, "cHRM")); + lodepng_set32bitInt(chunk + 8, info->chrm_white_x); + lodepng_set32bitInt(chunk + 12, info->chrm_white_y); + lodepng_set32bitInt(chunk + 16, info->chrm_red_x); + lodepng_set32bitInt(chunk + 20, info->chrm_red_y); + lodepng_set32bitInt(chunk + 24, info->chrm_green_x); + lodepng_set32bitInt(chunk + 28, info->chrm_green_y); + lodepng_set32bitInt(chunk + 32, info->chrm_blue_x); + lodepng_set32bitInt(chunk + 36, info->chrm_blue_y); + lodepng_chunk_generate_crc(chunk); + return 0; +} + +static unsigned addChunk_sRGB(ucvector* out, const LodePNGInfo* info) { + unsigned char data = info->srgb_intent; + return lodepng_chunk_createv(out, 1, "sRGB", &data); +} + +static unsigned addChunk_iCCP(ucvector* out, const LodePNGInfo* info, const LodePNGCompressSettings* zlibsettings) { + unsigned error = 0; + unsigned char* chunk = 0; + unsigned char* compressed = 0; + size_t compressedsize = 0; + size_t keysize = lodepng_strlen(info->iccp_name); + + if(keysize < 1 || keysize > 79) return 89; /*error: invalid keyword size*/ + error = zlib_compress(&compressed, &compressedsize, + info->iccp_profile, info->iccp_profile_size, zlibsettings); + if(!error) { + size_t size = keysize + 2 + compressedsize; + error = lodepng_chunk_init(&chunk, out, size, "iCCP"); + } + if(!error) { + lodepng_memcpy(chunk + 8, info->iccp_name, keysize); + chunk[8 + keysize] = 0; /*null termination char*/ + chunk[9 + keysize] = 0; /*compression method: 0*/ + lodepng_memcpy(chunk + 10 + keysize, compressed, compressedsize); + lodepng_chunk_generate_crc(chunk); + } + + lodepng_free(compressed); + return error; +} + +static unsigned addChunk_cICP(ucvector* out, const LodePNGInfo* info) { + unsigned char* chunk; + /* Allow up to 255 since they are bytes. The ITU-R-BT.709 spec has a more + restricted set of valid values for each field, but that's up to the error + handling of a CICP library, not the PNG encoding/decoding, to manage. */ + if(info->cicp_color_primaries > 255) return 116; + if(info->cicp_transfer_function > 255) return 116; + if(info->cicp_matrix_coefficients > 255) return 116; + if(info->cicp_video_full_range_flag > 255) return 116; + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 4, "cICP")); + chunk[8 + 0] = (unsigned char)info->cicp_color_primaries; + chunk[8 + 1] = (unsigned char)info->cicp_transfer_function; + chunk[8 + 2] = (unsigned char)info->cicp_matrix_coefficients; + chunk[8 + 3] = (unsigned char)info->cicp_video_full_range_flag; + lodepng_chunk_generate_crc(chunk); + return 0; +} + +static unsigned addChunk_mDCV(ucvector* out, const LodePNGInfo* info) { + unsigned char* chunk; + /* Allow up to 65535 since they are 16-bit ints. */ + if(info->mdcv_red_x > 65535) return 118; + if(info->mdcv_red_y > 65535) return 118; + if(info->mdcv_green_x > 65535) return 118; + if(info->mdcv_green_y > 65535) return 118; + if(info->mdcv_blue_x > 65535) return 118; + if(info->mdcv_blue_y > 65535) return 118; + if(info->mdcv_white_x > 65535) return 118; + if(info->mdcv_white_y > 65535) return 118; + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 24, "mDCV")); + chunk[8 + 0] = (unsigned char)((info->mdcv_red_x) >> 8u); + chunk[8 + 1] = (unsigned char)(info->mdcv_red_x); + chunk[8 + 2] = (unsigned char)((info->mdcv_red_y) >> 8u); + chunk[8 + 3] = (unsigned char)(info->mdcv_red_y); + chunk[8 + 4] = (unsigned char)((info->mdcv_green_x) >> 8u); + chunk[8 + 5] = (unsigned char)(info->mdcv_green_x); + chunk[8 + 6] = (unsigned char)((info->mdcv_green_y) >> 8u); + chunk[8 + 7] = (unsigned char)(info->mdcv_green_y); + chunk[8 + 8] = (unsigned char)((info->mdcv_blue_x) >> 8u); + chunk[8 + 9] = (unsigned char)(info->mdcv_blue_x); + chunk[8 + 10] = (unsigned char)((info->mdcv_blue_y) >> 8u); + chunk[8 + 11] = (unsigned char)(info->mdcv_blue_y); + chunk[8 + 12] = (unsigned char)((info->mdcv_white_x) >> 8u); + chunk[8 + 13] = (unsigned char)(info->mdcv_white_x); + chunk[8 + 14] = (unsigned char)((info->mdcv_white_y) >> 8u); + chunk[8 + 15] = (unsigned char)(info->mdcv_white_y); + lodepng_set32bitInt(chunk + 8 + 16, info->mdcv_max_luminance); + lodepng_set32bitInt(chunk + 8 + 20, info->mdcv_min_luminance); + lodepng_chunk_generate_crc(chunk); + return 0; +} + +static unsigned addChunk_cLLI(ucvector* out, const LodePNGInfo* info) { + unsigned char* chunk; + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 8, "cLLI")); + lodepng_set32bitInt(chunk + 8 + 0, info->clli_max_cll); + lodepng_set32bitInt(chunk + 8 + 4, info->clli_max_fall); + lodepng_chunk_generate_crc(chunk); + return 0; +} + +static unsigned addChunk_eXIf(ucvector* out, const LodePNGInfo* info) { + return lodepng_chunk_createv(out, info->exif_size, "eXIf", info->exif); +} + +static unsigned addChunk_sBIT(ucvector* out, const LodePNGInfo* info) { + unsigned bitdepth = (info->color.colortype == LCT_PALETTE) ? 8 : info->color.bitdepth; + unsigned char* chunk = 0; + if(info->color.colortype == LCT_GREY) { + if(info->sbit_r == 0 || info->sbit_r > bitdepth) return 115; + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 1, "sBIT")); + chunk[8] = info->sbit_r; + } else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_PALETTE) { + if(info->sbit_r == 0 || info->sbit_g == 0 || info->sbit_b == 0) return 115; + if(info->sbit_r > bitdepth || info->sbit_g > bitdepth || info->sbit_b > bitdepth) return 115; + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 3, "sBIT")); + chunk[8] = info->sbit_r; + chunk[9] = info->sbit_g; + chunk[10] = info->sbit_b; + } else if(info->color.colortype == LCT_GREY_ALPHA) { + if(info->sbit_r == 0 || info->sbit_a == 0) return 115; + if(info->sbit_r > bitdepth || info->sbit_a > bitdepth) return 115; + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 2, "sBIT")); + chunk[8] = info->sbit_r; + chunk[9] = info->sbit_a; + } else if(info->color.colortype == LCT_RGBA) { + if(info->sbit_r == 0 || info->sbit_g == 0 || info->sbit_b == 0 || info->sbit_a == 0 || + info->sbit_r > bitdepth || info->sbit_g > bitdepth || + info->sbit_b > bitdepth || info->sbit_a > bitdepth) { + return 115; + } + CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 4, "sBIT")); + chunk[8] = info->sbit_r; + chunk[9] = info->sbit_g; + chunk[10] = info->sbit_b; + chunk[11] = info->sbit_a; + } + if(chunk) lodepng_chunk_generate_crc(chunk); + return 0; +} + +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +static void filterScanline(unsigned char* out, const unsigned char* scanline, const unsigned char* prevline, + size_t length, size_t bytewidth, unsigned char filterType) { + size_t i; + switch(filterType) { + case 0: /*None*/ + for(i = 0; i != length; ++i) out[i] = scanline[i]; + break; + case 1: /*Sub*/ + for(i = 0; i != bytewidth; ++i) out[i] = scanline[i]; + for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - scanline[i - bytewidth]; + break; + case 2: /*Up*/ + if(prevline) { + for(i = 0; i != length; ++i) out[i] = scanline[i] - prevline[i]; + } else { + for(i = 0; i != length; ++i) out[i] = scanline[i]; + } + break; + case 3: /*Average*/ + if(prevline) { + for(i = 0; i != bytewidth; ++i) out[i] = scanline[i] - (prevline[i] >> 1); + for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - ((scanline[i - bytewidth] + prevline[i]) >> 1); + } else { + for(i = 0; i != bytewidth; ++i) out[i] = scanline[i]; + for(i = bytewidth; i < length; ++i) out[i] = scanline[i] - (scanline[i - bytewidth] >> 1); + } + break; + case 4: /*Paeth*/ + if(prevline) { + /*paethPredictor(0, prevline[i], 0) is always prevline[i]*/ + for(i = 0; i != bytewidth; ++i) out[i] = (scanline[i] - prevline[i]); + for(i = bytewidth; i < length; ++i) { + out[i] = (scanline[i] - paethPredictor(scanline[i - bytewidth], prevline[i], prevline[i - bytewidth])); + } + } else { + for(i = 0; i != bytewidth; ++i) out[i] = scanline[i]; + /*paethPredictor(scanline[i - bytewidth], 0, 0) is always scanline[i - bytewidth]*/ + for(i = bytewidth; i < length; ++i) out[i] = (scanline[i] - scanline[i - bytewidth]); + } + break; + default: return; /*invalid filter type given*/ + } +} + +/* integer binary logarithm, max return value is 31 */ +static size_t ilog2(size_t i) { + size_t result = 0; + if(i >= 65536) { result += 16; i >>= 16; } + if(i >= 256) { result += 8; i >>= 8; } + if(i >= 16) { result += 4; i >>= 4; } + if(i >= 4) { result += 2; i >>= 2; } + if(i >= 2) { result += 1; /*i >>= 1;*/ } + return result; +} + +/* integer approximation for i * log2(i), helper function for LFS_ENTROPY */ +static size_t ilog2i(size_t i) { + size_t l; + if(i == 0) return 0; + l = ilog2(i); + /* approximate i*log2(i): l is integer logarithm, ((i - (1u << l)) << 1u) + linearly approximates the missing fractional part multiplied by i */ + return i * l + ((i - (((size_t)1) << l)) << 1u); +} + +static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, + const LodePNGColorMode* color, const LodePNGEncoderSettings* settings) { + /* + For PNG filter method 0 + out must be a buffer with as size: h + (w * h * bpp + 7u) / 8u, because there are + the scanlines with 1 extra byte per scanline + */ + + unsigned bpp = lodepng_get_bpp(color); + /*the width of a scanline in bytes, not including the filter type*/ + size_t linebytes = lodepng_get_raw_size_idat(w, 1, bpp) - 1u; + + /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/ + size_t bytewidth = (bpp + 7u) / 8u; + const unsigned char* prevline = 0; + unsigned x, y; + unsigned error = 0; + LodePNGFilterStrategy strategy = settings->filter_strategy; + + if(settings->filter_palette_zero && (color->colortype == LCT_PALETTE || color->bitdepth < 8)) { + /*if the filter_palette_zero setting is enabled, override the filter strategy with + zero for all scanlines for palette and less-than-8-bitdepth images*/ + strategy = LFS_ZERO; + } + + if(bpp == 0) return 31; /*error: invalid color type*/ + + if(strategy >= LFS_ZERO && strategy <= LFS_FOUR) { + unsigned char type = (unsigned char)strategy; + for(y = 0; y != h; ++y) { + size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ + size_t inindex = linebytes * y; + out[outindex] = type; /*filter type byte*/ + filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, type); + prevline = &in[inindex]; + } + } else if(strategy == LFS_MINSUM) { + /*adaptive filtering: independently for each row, try all five filter types and select the one that produces the + smallest sum of absolute values per row.*/ + unsigned char* attempt[5]; /*five filtering attempts, one for each filter type*/ + size_t smallest = 0; + unsigned char type, bestType = 0; + + for(type = 0; type != 5; ++type) { + attempt[type] = (unsigned char*)lodepng_malloc(linebytes); + if(!attempt[type]) error = 83; /*alloc fail*/ + } + + if(!error) { + for(y = 0; y != h; ++y) { + /*try the 5 filter types*/ + for(type = 0; type != 5; ++type) { + size_t sum = 0; + filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, bytewidth, type); + + /*calculate the sum of the result*/ + if(type == 0) { + for(x = 0; x != linebytes; ++x) sum += (unsigned char)(attempt[type][x]); + } else { + for(x = 0; x != linebytes; ++x) { + /*For differences, each byte should be treated as signed, values above 127 are negative + (converted to signed char). Filtertype 0 isn't a difference though, so use unsigned there. + This means filtertype 0 is almost never chosen, but that is justified.*/ + unsigned char s = attempt[type][x]; + sum += s < 128 ? s : (255U - s); + } + } + + /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/ + if(type == 0 || sum < smallest) { + bestType = type; + smallest = sum; + } + } + + prevline = &in[y * linebytes]; + + /*now fill the out values*/ + out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ + for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType][x]; + } + } + + for(type = 0; type != 5; ++type) lodepng_free(attempt[type]); + } else if(strategy == LFS_ENTROPY) { + unsigned char* attempt[5]; /*five filtering attempts, one for each filter type*/ + size_t bestSum = 0; + unsigned type, bestType = 0; + unsigned count[256]; + + for(type = 0; type != 5; ++type) { + attempt[type] = (unsigned char*)lodepng_malloc(linebytes); + if(!attempt[type]) error = 83; /*alloc fail*/ + } + + if(!error) { + for(y = 0; y != h; ++y) { + /*try the 5 filter types*/ + for(type = 0; type != 5; ++type) { + size_t sum = 0; + filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, bytewidth, type); + lodepng_memset(count, 0, 256 * sizeof(*count)); + for(x = 0; x != linebytes; ++x) ++count[attempt[type][x]]; + ++count[type]; /*the filter type itself is part of the scanline*/ + for(x = 0; x != 256; ++x) { + sum += ilog2i(count[x]); + } + /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/ + if(type == 0 || sum > bestSum) { + bestType = type; + bestSum = sum; + } + } + + prevline = &in[y * linebytes]; + + /*now fill the out values*/ + out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ + for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType][x]; + } + } + + for(type = 0; type != 5; ++type) lodepng_free(attempt[type]); + } else if(strategy == LFS_PREDEFINED) { + for(y = 0; y != h; ++y) { + size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ + size_t inindex = linebytes * y; + unsigned char type = settings->predefined_filters[y]; + out[outindex] = type; /*filter type byte*/ + filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, type); + prevline = &in[inindex]; + } + } else if(strategy == LFS_BRUTE_FORCE) { + /*brute force filter chooser. + deflate the scanline after every filter attempt to see which one deflates best. + This is very slow and gives only slightly smaller, sometimes even larger, result*/ + size_t size[5]; + unsigned char* attempt[5]; /*five filtering attempts, one for each filter type*/ + size_t smallest = 0; + unsigned type = 0, bestType = 0; + unsigned char* dummy; + LodePNGCompressSettings zlibsettings; + lodepng_memcpy(&zlibsettings, &settings->zlibsettings, sizeof(LodePNGCompressSettings)); + /*use fixed tree on the attempts so that the tree is not adapted to the filtertype on purpose, + to simulate the true case where the tree is the same for the whole image. Sometimes it gives + better result with dynamic tree anyway. Using the fixed tree sometimes gives worse, but in rare + cases better compression. It does make this a bit less slow, so it's worth doing this.*/ + zlibsettings.btype = 1; + /*a custom encoder likely doesn't read the btype setting and is optimized for complete PNG + images only, so disable it*/ + zlibsettings.custom_zlib = 0; + zlibsettings.custom_deflate = 0; + for(type = 0; type != 5; ++type) { + attempt[type] = (unsigned char*)lodepng_malloc(linebytes); + if(!attempt[type]) error = 83; /*alloc fail*/ + } + if(!error) { + for(y = 0; y != h; ++y) /*try the 5 filter types*/ { + for(type = 0; type != 5; ++type) { + unsigned testsize = (unsigned)linebytes; + /*if(testsize > 8) testsize /= 8;*/ /*it already works good enough by testing a part of the row*/ + + filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, bytewidth, type); + size[type] = 0; + dummy = 0; + zlib_compress(&dummy, &size[type], attempt[type], testsize, &zlibsettings); + lodepng_free(dummy); + /*check if this is smallest size (or if type == 0 it's the first case so always store the values)*/ + if(type == 0 || size[type] < smallest) { + bestType = type; + smallest = size[type]; + } + } + prevline = &in[y * linebytes]; + out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ + for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType][x]; + } + } + for(type = 0; type != 5; ++type) lodepng_free(attempt[type]); + } + else return 88; /* unknown filter strategy */ + + return error; +} + +static void addPaddingBits(unsigned char* out, const unsigned char* in, + size_t olinebits, size_t ilinebits, unsigned h) { + /*The opposite of the removePaddingBits function + olinebits must be >= ilinebits*/ + unsigned y; + size_t diff = olinebits - ilinebits; + size_t obp = 0, ibp = 0; /*bit pointers*/ + for(y = 0; y != h; ++y) { + size_t x; + for(x = 0; x < ilinebits; ++x) { + unsigned char bit = readBitFromReversedStream(&ibp, in); + setBitOfReversedStream(&obp, out, bit); + } + /*obp += diff; --> no, fill in some value in the padding bits too, to avoid + "Use of uninitialised value of size ###" warning from valgrind*/ + for(x = 0; x != diff; ++x) setBitOfReversedStream(&obp, out, 0); + } +} + +/* +in: non-interlaced image with size w*h +out: the same pixels, but re-ordered according to PNG's Adam7 interlacing, with + no padding bits between scanlines, but between reduced images so that each + reduced image starts at a byte. +bpp: bits per pixel +there are no padding bits, not between scanlines, not between reduced images +in has the following size in bits: w * h * bpp. +out is possibly bigger due to padding bits between reduced images +NOTE: comments about padding bits are only relevant if bpp < 8 +*/ +static void Adam7_interlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) { + unsigned passw[7], passh[7]; + size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned i; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + if(bpp >= 8) { + for(i = 0; i != 7; ++i) { + unsigned x, y, b; + size_t bytewidth = bpp / 8u; + for(y = 0; y < passh[i]; ++y) + for(x = 0; x < passw[i]; ++x) { + size_t pixelinstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth; + size_t pixeloutstart = passstart[i] + (y * passw[i] + x) * bytewidth; + for(b = 0; b < bytewidth; ++b) { + out[pixeloutstart + b] = in[pixelinstart + b]; + } + } + } + } else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/ { + for(i = 0; i != 7; ++i) { + unsigned x, y, b; + unsigned ilinebits = bpp * passw[i]; + unsigned olinebits = bpp * w; + size_t obp, ibp; /*bit pointers (for out and in buffer)*/ + for(y = 0; y < passh[i]; ++y) + for(x = 0; x < passw[i]; ++x) { + ibp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp; + obp = (8 * passstart[i]) + (y * ilinebits + x * bpp); + for(b = 0; b < bpp; ++b) { + unsigned char bit = readBitFromReversedStream(&ibp, in); + setBitOfReversedStream(&obp, out, bit); + } + } + } + } +} + +/*out must be buffer big enough to contain uncompressed IDAT chunk data, and in must contain the full image. +return value is error**/ +static unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const unsigned char* in, + unsigned w, unsigned h, + const LodePNGInfo* info_png, const LodePNGEncoderSettings* settings) { + /* + This function converts the pure 2D image with the PNG's colortype, into filtered-padded-interlaced data. Steps: + *) if no Adam7: 1) add padding bits (= possible extra bits per scanline if bpp < 8) 2) filter + *) if adam7: 1) Adam7_interlace 2) 7x add padding bits 3) 7x filter + */ + size_t bpp = lodepng_get_bpp(&info_png->color); + unsigned error = 0; + if(info_png->interlace_method == 0) { + /*image size plus an extra byte per scanline + possible padding bits*/ + *outsize = (size_t)h + ((size_t)h * (((size_t)w * bpp + 7u) / 8u)); + *out = (unsigned char*)lodepng_malloc(*outsize); + if(!(*out) && (*outsize)) error = 83; /*alloc fail*/ + + if(!error) { + /*non multiple of 8 bits per scanline, padding bits needed per scanline*/ + if(bpp < 8 && (size_t)w * bpp != (((size_t)w * bpp + 7u) / 8u) * 8u) { + unsigned char* padded = (unsigned char*)lodepng_malloc(h * ((w * bpp + 7u) / 8u)); + if(!padded) error = 83; /*alloc fail*/ + if(!error) { + addPaddingBits(padded, in, (((size_t)w * bpp + 7u) / 8u) * 8u, (size_t)w * bpp, h); + error = filter(*out, padded, w, h, &info_png->color, settings); + } + lodepng_free(padded); + } else { + /*we can immediately filter into the out buffer, no other steps needed*/ + error = filter(*out, in, w, h, &info_png->color, settings); + } + } + } else /*interlace_method is 1 (Adam7)*/ { + unsigned passw[7], passh[7]; + size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned char* adam7; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, (unsigned)bpp); + + *outsize = filter_passstart[7]; /*image size plus an extra byte per scanline + possible padding bits*/ + *out = (unsigned char*)lodepng_malloc(*outsize); + if(!(*out)) error = 83; /*alloc fail*/ + + adam7 = (unsigned char*)lodepng_malloc(passstart[7]); + if(!adam7 && passstart[7]) error = 83; /*alloc fail*/ + + if(!error) { + unsigned i; + + Adam7_interlace(adam7, in, w, h, (unsigned)bpp); + for(i = 0; i != 7; ++i) { + if(bpp < 8) { + unsigned char* padded = (unsigned char*)lodepng_malloc(padded_passstart[i + 1] - padded_passstart[i]); + if(!padded) ERROR_BREAK(83); /*alloc fail*/ + addPaddingBits(padded, &adam7[passstart[i]], + (((size_t)passw[i] * bpp + 7u) / 8u) * 8u, (size_t)passw[i] * bpp, passh[i]); + error = filter(&(*out)[filter_passstart[i]], padded, + passw[i], passh[i], &info_png->color, settings); + lodepng_free(padded); + } else { + error = filter(&(*out)[filter_passstart[i]], &adam7[padded_passstart[i]], + passw[i], passh[i], &info_png->color, settings); + } + + if(error) break; + } + } + + lodepng_free(adam7); + } + + return error; +} + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +static unsigned addUnknownChunks(ucvector* out, unsigned char* data, size_t datasize) { + unsigned char* inchunk = data; + while((size_t)(inchunk - data) < datasize) { + CERROR_TRY_RETURN(lodepng_chunk_append(&out->data, &out->size, inchunk)); + out->allocsize = out->size; /*fix the allocsize again*/ + inchunk = lodepng_chunk_next(inchunk, data + datasize); + } + return 0; +} + +static unsigned isGrayICCProfile(const unsigned char* profile, unsigned size) { + /* + It is a gray profile if bytes 16-19 are "GRAY", rgb profile if bytes 16-19 + are "RGB ". We do not perform any full parsing of the ICC profile here, other + than check those 4 bytes to grayscale profile. Other than that, validity of + the profile is not checked. This is needed only because the PNG specification + requires using a non-gray color model if there is an ICC profile with "RGB " + (sadly limiting compression opportunities if the input data is grayscale RGB + data), and requires using a gray color model if it is "GRAY". + */ + if(size < 20) return 0; + return profile[16] == 'G' && profile[17] == 'R' && profile[18] == 'A' && profile[19] == 'Y'; +} + +static unsigned isRGBICCProfile(const unsigned char* profile, unsigned size) { + /* See comment in isGrayICCProfile*/ + if(size < 20) return 0; + return profile[16] == 'R' && profile[17] == 'G' && profile[18] == 'B' && profile[19] == ' '; +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +unsigned lodepng_encode(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h, + LodePNGState* state) { + unsigned char* data = 0; /*uncompressed version of the IDAT chunk data*/ + size_t datasize = 0; + ucvector outv = ucvector_init(NULL, 0); + LodePNGInfo info; + const LodePNGInfo* info_png = &state->info_png; + LodePNGColorMode auto_color; + unsigned error = 0; + + lodepng_info_init(&info); + lodepng_color_mode_init(&auto_color); + + /*provide some proper output values if error will happen*/ + *out = 0; + *outsize = 0; + + /*check input values validity*/ + if((info_png->color.colortype == LCT_PALETTE || state->encoder.force_palette) + && (info_png->color.palettesize == 0 || info_png->color.palettesize > 256)) { + /*this error is returned even if auto_convert is enabled and thus encoder could + generate the palette by itself: while allowing this could be possible in theory, + it may complicate the code or edge cases, and always requiring to give a palette + when setting this color type is a simpler contract*/ + error = 68; /*invalid palette size, it is only allowed to be 1-256*/ + goto cleanup; + } + if(state->encoder.zlibsettings.btype > 2) { + error = 61; /*error: invalid btype*/ + goto cleanup; + } + if(info_png->interlace_method > 1) { + error = 71; /*error: invalid interlace mode*/ + goto cleanup; + } + error = checkColorValidity(info_png->color.colortype, info_png->color.bitdepth); + if(error) goto cleanup; /*error: invalid color type given*/ + error = checkColorValidity(state->info_raw.colortype, state->info_raw.bitdepth); + if(error) goto cleanup; /*error: invalid color type given*/ + + /* color convert and compute scanline filter types */ + CERROR_TRY_RETURN(lodepng_info_copy(&info, &state->info_png)); + if(state->encoder.auto_convert) { + LodePNGColorStats stats; + unsigned allow_convert = 1; + lodepng_color_stats_init(&stats); +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + if(info_png->iccp_defined && + isGrayICCProfile(info_png->iccp_profile, info_png->iccp_profile_size)) { + /*the PNG specification does not allow to use palette with a GRAY ICC profile, even + if the palette has only gray colors, so disallow it.*/ + stats.allow_palette = 0; + } + if(info_png->iccp_defined && + isRGBICCProfile(info_png->iccp_profile, info_png->iccp_profile_size)) { + /*the PNG specification does not allow to use grayscale color with RGB ICC profile, so disallow gray.*/ + stats.allow_greyscale = 0; + } +#endif /* LODEPNG_COMPILE_ANCILLARY_CHUNKS */ + error = lodepng_compute_color_stats(&stats, image, w, h, &state->info_raw); + if(error) goto cleanup; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + if(info_png->background_defined) { + /*the background chunk's color must be taken into account as well*/ + unsigned r = 0, g = 0, b = 0; + LodePNGColorMode mode16 = lodepng_color_mode_make(LCT_RGB, 16); + lodepng_convert_rgb(&r, &g, &b, + info_png->background_r, info_png->background_g, info_png->background_b, &mode16, &info_png->color); + error = lodepng_color_stats_add(&stats, r, g, b, 65535); + if(error) goto cleanup; + } +#endif /* LODEPNG_COMPILE_ANCILLARY_CHUNKS */ + error = auto_choose_color(&auto_color, &state->info_raw, &stats); + if(error) goto cleanup; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + if(info_png->sbit_defined) { + /*if sbit is defined, due to strict requirements of which sbit values can be present for which color modes, + auto_convert can't be done in many cases. However, do support a few cases here. + TODO: more conversions may be possible, and it may also be possible to get a more appropriate color type out of + auto_choose_color if knowledge about sbit is used beforehand + */ + unsigned sbit_max = LODEPNG_MAX(LODEPNG_MAX(LODEPNG_MAX(info_png->sbit_r, info_png->sbit_g), + info_png->sbit_b), info_png->sbit_a); + unsigned equal = (!info_png->sbit_g || info_png->sbit_g == info_png->sbit_r) + && (!info_png->sbit_b || info_png->sbit_b == info_png->sbit_r) + && (!info_png->sbit_a || info_png->sbit_a == info_png->sbit_r); + allow_convert = 0; + if(info.color.colortype == LCT_PALETTE && + auto_color.colortype == LCT_PALETTE) { + /* input and output are palette, and in this case it may happen that palette data is + expected to be copied from info_raw into the info_png */ + allow_convert = 1; + } + /*going from 8-bit RGB to palette (or 16-bit as long as sbit_max <= 8) is possible + since both are 8-bit RGB for sBIT's purposes*/ + if(info.color.colortype == LCT_RGB && + auto_color.colortype == LCT_PALETTE && sbit_max <= 8) { + allow_convert = 1; + } + /*going from 8-bit RGBA to palette is also ok but only if sbit_a is exactly 8*/ + if(info.color.colortype == LCT_RGBA && auto_color.colortype == LCT_PALETTE && + info_png->sbit_a == 8 && sbit_max <= 8) { + allow_convert = 1; + } + /*going from 16-bit RGB(A) to 8-bit RGB(A) is ok if all sbit values are <= 8*/ + if((info.color.colortype == LCT_RGB || info.color.colortype == LCT_RGBA) && info.color.bitdepth == 16 && + auto_color.colortype == info.color.colortype && auto_color.bitdepth == 8 && + sbit_max <= 8) { + allow_convert = 1; + } + /*going to less channels is ok if all bit values are equal (all possible values in sbit, + as well as the chosen bitdepth of the result). Due to how auto_convert works, + we already know that auto_color.colortype has less than or equal amount of channels than + info.colortype. Palette is not used here. This conversion is not allowed if + info_png->sbit_r < auto_color.bitdepth, because specifically for alpha, non-presence of + an sbit value heavily implies that alpha's bit depth is equal to the PNG bit depth (rather + than the bit depths set in the r, g and b sbit values, by how the PNG specification describes + handling tRNS chunk case with sBIT), so be conservative here about ignoring user input.*/ + if(info.color.colortype != LCT_PALETTE && auto_color.colortype != LCT_PALETTE && + equal && info_png->sbit_r == auto_color.bitdepth) { + allow_convert = 1; + } + } +#endif + if(state->encoder.force_palette) { + if(info.color.colortype != LCT_GREY && info.color.colortype != LCT_GREY_ALPHA && + (auto_color.colortype == LCT_GREY || auto_color.colortype == LCT_GREY_ALPHA)) { + /*user specifically forced a PLTE palette, so cannot convert to grayscale types because + the PNG specification only allows writing a suggested palette in PLTE for truecolor types*/ + allow_convert = 0; + } + } + if(allow_convert) { + lodepng_color_mode_copy(&info.color, &auto_color); +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*also convert the background chunk*/ + if(info_png->background_defined) { + if(lodepng_convert_rgb(&info.background_r, &info.background_g, &info.background_b, + info_png->background_r, info_png->background_g, info_png->background_b, &info.color, &info_png->color)) { + error = 104; + goto cleanup; + } + } +#endif /* LODEPNG_COMPILE_ANCILLARY_CHUNKS */ + } + } +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + if(info_png->iccp_defined) { + unsigned gray_icc = isGrayICCProfile(info_png->iccp_profile, info_png->iccp_profile_size); + unsigned rgb_icc = isRGBICCProfile(info_png->iccp_profile, info_png->iccp_profile_size); + unsigned gray_png = info.color.colortype == LCT_GREY || info.color.colortype == LCT_GREY_ALPHA; + if(!gray_icc && !rgb_icc) { + error = 100; /* Disallowed profile color type for PNG */ + goto cleanup; + } + if(gray_icc != gray_png) { + /*Not allowed to use RGB/RGBA/palette with GRAY ICC profile or vice versa, + or in case of auto_convert, it wasn't possible to find appropriate model*/ + error = state->encoder.auto_convert ? 102 : 101; + goto cleanup; + } + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + if(!lodepng_color_mode_equal(&state->info_raw, &info.color)) { + unsigned char* converted; + size_t size = ((size_t)w * (size_t)h * (size_t)lodepng_get_bpp(&info.color) + 7u) / 8u; + + converted = (unsigned char*)lodepng_malloc(size); + if(!converted && size) error = 83; /*alloc fail*/ + if(!error) { + error = lodepng_convert(converted, image, &info.color, &state->info_raw, w, h); + } + if(!error) { + error = preProcessScanlines(&data, &datasize, converted, w, h, &info, &state->encoder); + } + lodepng_free(converted); + if(error) goto cleanup; + } else { + error = preProcessScanlines(&data, &datasize, image, w, h, &info, &state->encoder); + if(error) goto cleanup; + } + + /* output all PNG chunks */ { +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + size_t i; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + /*write signature and chunks*/ + error = writeSignature(&outv); + if(error) goto cleanup; + /*IHDR*/ + error = addChunk_IHDR(&outv, w, h, info.color.colortype, info.color.bitdepth, info.interlace_method); + if(error) goto cleanup; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*unknown chunks between IHDR and PLTE*/ + if(info.unknown_chunks_data[0]) { + error = addUnknownChunks(&outv, info.unknown_chunks_data[0], info.unknown_chunks_size[0]); + if(error) goto cleanup; + } + /*color profile chunks must come before PLTE */ + if(info.cicp_defined) { + error = addChunk_cICP(&outv, &info); + if(error) goto cleanup; + } + if(info.mdcv_defined) { + error = addChunk_mDCV(&outv, &info); + if(error) goto cleanup; + } + if(info.clli_defined) { + error = addChunk_cLLI(&outv, &info); + if(error) goto cleanup; + } + if(info.iccp_defined) { + error = addChunk_iCCP(&outv, &info, &state->encoder.zlibsettings); + if(error) goto cleanup; + } + if(info.srgb_defined) { + error = addChunk_sRGB(&outv, &info); + if(error) goto cleanup; + } + if(info.gama_defined) { + error = addChunk_gAMA(&outv, &info); + if(error) goto cleanup; + } + if(info.chrm_defined) { + error = addChunk_cHRM(&outv, &info); + if(error) goto cleanup; + } + if(info_png->sbit_defined) { + error = addChunk_sBIT(&outv, &info); + if(error) goto cleanup; + } + if(info.exif_defined) { + error = addChunk_eXIf(&outv, &info); + if(error) goto cleanup; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + /*PLTE*/ + if(info.color.colortype == LCT_PALETTE) { + error = addChunk_PLTE(&outv, &info.color); + if(error) goto cleanup; + } + if(state->encoder.force_palette && (info.color.colortype == LCT_RGB || info.color.colortype == LCT_RGBA)) { + /*force_palette means: write suggested palette for truecolor in PLTE chunk*/ + error = addChunk_PLTE(&outv, &info.color); + if(error) goto cleanup; + } + /*tRNS (this will only add if when necessary) */ + error = addChunk_tRNS(&outv, &info.color); + if(error) goto cleanup; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*bKGD (must come between PLTE and the IDAt chunks*/ + if(info.background_defined) { + error = addChunk_bKGD(&outv, &info); + if(error) goto cleanup; + } + /*pHYs (must come before the IDAT chunks)*/ + if(info.phys_defined) { + error = addChunk_pHYs(&outv, &info); + if(error) goto cleanup; + } + + /*unknown chunks between PLTE and IDAT*/ + if(info.unknown_chunks_data[1]) { + error = addUnknownChunks(&outv, info.unknown_chunks_data[1], info.unknown_chunks_size[1]); + if(error) goto cleanup; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + /*IDAT (multiple IDAT chunks must be consecutive)*/ + error = addChunk_IDAT(&outv, data, datasize, &state->encoder.zlibsettings); + if(error) goto cleanup; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*tIME*/ + if(info.time_defined) { + error = addChunk_tIME(&outv, &info.time); + if(error) goto cleanup; + } + /*tEXt and/or zTXt*/ + for(i = 0; i != info.text_num; ++i) { + if(lodepng_strlen(info.text_keys[i]) > 79) { + error = 66; /*text chunk too large*/ + goto cleanup; + } + if(lodepng_strlen(info.text_keys[i]) < 1) { + error = 67; /*text chunk too small*/ + goto cleanup; + } + if(state->encoder.text_compression) { + error = addChunk_zTXt(&outv, info.text_keys[i], info.text_strings[i], &state->encoder.zlibsettings); + if(error) goto cleanup; + } else { + error = addChunk_tEXt(&outv, info.text_keys[i], info.text_strings[i]); + if(error) goto cleanup; + } + } + /*LodePNG version id in text chunk*/ + if(state->encoder.add_id) { + unsigned already_added_id_text = 0; + for(i = 0; i != info.text_num; ++i) { + const char* k = info.text_keys[i]; + /* Could use strcmp, but we're not calling or reimplementing this C library function for this use only */ + if(k[0] == 'L' && k[1] == 'o' && k[2] == 'd' && k[3] == 'e' && + k[4] == 'P' && k[5] == 'N' && k[6] == 'G' && k[7] == '\0') { + already_added_id_text = 1; + break; + } + } + if(already_added_id_text == 0) { + error = addChunk_tEXt(&outv, "LodePNG", LODEPNG_VERSION_STRING); /*it's shorter as tEXt than as zTXt chunk*/ + if(error) goto cleanup; + } + } + /*iTXt*/ + for(i = 0; i != info.itext_num; ++i) { + if(lodepng_strlen(info.itext_keys[i]) > 79) { + error = 66; /*text chunk too large*/ + goto cleanup; + } + if(lodepng_strlen(info.itext_keys[i]) < 1) { + error = 67; /*text chunk too small*/ + goto cleanup; + } + error = addChunk_iTXt( + &outv, state->encoder.text_compression, + info.itext_keys[i], info.itext_langtags[i], info.itext_transkeys[i], info.itext_strings[i], + &state->encoder.zlibsettings); + if(error) goto cleanup; + } + + /*unknown chunks between IDAT and IEND*/ + if(info.unknown_chunks_data[2]) { + error = addUnknownChunks(&outv, info.unknown_chunks_data[2], info.unknown_chunks_size[2]); + if(error) goto cleanup; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + error = addChunk_IEND(&outv); + if(error) goto cleanup; + } + +cleanup: + lodepng_info_cleanup(&info); + lodepng_free(data); + lodepng_color_mode_cleanup(&auto_color); + + /*instead of cleaning the vector up, give it to the output*/ + *out = outv.data; + *outsize = outv.size; + + state->error = error; /*TODO: remove this and make input state const*/ + + return error; +} + +unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, const unsigned char* image, + unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) { + unsigned error; + LodePNGState state; + lodepng_state_init(&state); + state.info_raw.colortype = colortype; + state.info_raw.bitdepth = bitdepth; + state.info_png.color.colortype = colortype; + state.info_png.color.bitdepth = bitdepth; + error = lodepng_encode(out, outsize, image, w, h, &state); + lodepng_state_cleanup(&state); + return error; +} + +unsigned lodepng_encode32(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h) { + return lodepng_encode_memory(out, outsize, image, w, h, LCT_RGBA, 8); +} + +unsigned lodepng_encode24(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h) { + return lodepng_encode_memory(out, outsize, image, w, h, LCT_RGB, 8); +} + +#ifdef LODEPNG_COMPILE_DISK +unsigned lodepng_encode_file(const char* filename, const unsigned char* image, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) { + unsigned char* buffer; + size_t buffersize; + unsigned error = lodepng_encode_memory(&buffer, &buffersize, image, w, h, colortype, bitdepth); + if(!error) error = lodepng_save_file(buffer, buffersize, filename); + lodepng_free(buffer); + return error; +} + +unsigned lodepng_encode32_file(const char* filename, const unsigned char* image, unsigned w, unsigned h) { + return lodepng_encode_file(filename, image, w, h, LCT_RGBA, 8); +} + +unsigned lodepng_encode24_file(const char* filename, const unsigned char* image, unsigned w, unsigned h) { + return lodepng_encode_file(filename, image, w, h, LCT_RGB, 8); +} +#endif /*LODEPNG_COMPILE_DISK*/ + +void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings) { + lodepng_compress_settings_init(&settings->zlibsettings); + settings->filter_palette_zero = 1; + settings->filter_strategy = LFS_MINSUM; + settings->auto_convert = 1; + settings->force_palette = 0; + settings->predefined_filters = 0; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + settings->add_id = 0; + settings->text_compression = 1; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} + +#endif /*LODEPNG_COMPILE_ENCODER*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +#ifdef LODEPNG_COMPILE_ERROR_TEXT +/* +This returns the description of a numerical error code in English. This is also +the documentation of all the error codes. +*/ +const char* lodepng_error_text(unsigned code) { + switch(code) { + case 0: return "no error, everything went ok"; + case 1: return "nothing done yet"; /*the Encoder/Decoder has done nothing yet, error checking makes no sense yet*/ + case 10: return "end of input memory reached without huffman end code"; /*while huffman decoding*/ + case 11: return "error in code tree made it jump outside of huffman tree"; /*while huffman decoding*/ + case 13: return "problem while processing dynamic deflate block"; + case 14: return "problem while processing dynamic deflate block"; + case 15: return "problem while processing dynamic deflate block"; + /*this error could happen if there are only 0 or 1 symbols present in the huffman code:*/ + case 16: return "invalid code while processing dynamic deflate block"; + case 17: return "end of out buffer memory reached while inflating"; + case 18: return "invalid distance code while inflating"; + case 19: return "end of out buffer memory reached while inflating"; + case 20: return "invalid deflate block BTYPE encountered while decoding"; + case 21: return "NLEN is not ones complement of LEN in a deflate block"; + + /*end of out buffer memory reached while inflating: + This can happen if the inflated deflate data is longer than the amount of bytes required to fill up + all the pixels of the image, given the color depth and image dimensions. Something that doesn't + happen in a normal, well encoded, PNG image.*/ + case 22: return "end of out buffer memory reached while inflating"; + case 23: return "end of in buffer memory reached while inflating"; + case 24: return "invalid FCHECK in zlib header"; + case 25: return "invalid compression method in zlib header"; + case 26: return "FDICT encountered in zlib header while it's not used for PNG"; + case 27: return "PNG file is smaller than a PNG header"; + /*Checks the magic file header, the first 8 bytes of the PNG file*/ + case 28: return "incorrect PNG signature, it's no PNG or corrupted"; + case 29: return "first chunk is not the header chunk"; + case 30: return "chunk length too large, chunk broken off at end of file"; + case 31: return "illegal PNG color type or bpp"; + case 32: return "illegal PNG compression method"; + case 33: return "illegal PNG filter method"; + case 34: return "illegal PNG interlace method"; + case 35: return "chunk length of a chunk is too large or the chunk too small"; + case 36: return "illegal PNG filter type encountered"; + case 37: return "illegal bit depth for this color type given"; + case 38: return "the palette is too small or too big"; /*0, or more than 256 colors*/ + case 39: return "tRNS chunk before PLTE or has more entries than palette size"; + case 40: return "tRNS chunk has wrong size for grayscale image"; + case 41: return "tRNS chunk has wrong size for RGB image"; + case 42: return "tRNS chunk appeared while it was not allowed for this color type"; + case 43: return "bKGD chunk has wrong size for palette image"; + case 44: return "bKGD chunk has wrong size for grayscale image"; + case 45: return "bKGD chunk has wrong size for RGB image"; + case 48: return "empty input buffer given to decoder. Maybe caused by non-existing file?"; + case 49: return "jumped past memory while generating dynamic huffman tree"; + case 50: return "jumped past memory while generating dynamic huffman tree"; + case 51: return "jumped past memory while inflating huffman block"; + case 52: return "jumped past memory while inflating"; + case 53: return "size of zlib data too small"; + case 54: return "repeat symbol in tree while there was no value symbol yet"; + /*jumped past tree while generating huffman tree, this could be when the + tree will have more leaves than symbols after generating it out of the + given lengths. They call this an oversubscribed dynamic bit lengths tree in zlib.*/ + case 55: return "jumped past tree while generating huffman tree"; + case 56: return "given output image colortype or bitdepth not supported for color conversion"; + case 57: return "invalid CRC encountered (checking CRC can be disabled)"; + case 58: return "invalid ADLER32 encountered (checking ADLER32 can be disabled)"; + case 59: return "requested color conversion not supported"; + case 60: return "invalid window size given in the settings of the encoder (must be 0-32768)"; + case 61: return "invalid BTYPE given in the settings of the encoder (only 0, 1 and 2 are allowed)"; + /*LodePNG leaves the choice of RGB to grayscale conversion formula to the user.*/ + case 62: return "conversion from color to grayscale not supported"; + /*(2^31-1)*/ + case 63: return "length of a chunk too long, max allowed for PNG is 2147483647 bytes per chunk"; + /*this would result in the inability of a deflated block to ever contain an end code. It must be at least 1.*/ + case 64: return "the length of the END symbol 256 in the Huffman tree is 0"; + case 66: return "the length of a text chunk keyword given to the encoder is longer than the maximum of 79 bytes"; + case 67: return "the length of a text chunk keyword given to the encoder is smaller than the minimum of 1 byte"; + case 68: return "tried to encode a PLTE chunk with a palette that has less than 1 or more than 256 colors"; + case 69: return "unknown chunk type with 'critical' flag encountered by the decoder"; + case 71: return "invalid interlace mode given to encoder (must be 0 or 1)"; + case 72: return "while decoding, invalid compression method encountered in zTXt, iTXt or iCCP chunk (it must be 0)"; + case 73: return "invalid tIME chunk size"; + case 74: return "invalid pHYs chunk size"; + /*length could be wrong, or data chopped off*/ + case 75: return "no null termination char found while decoding text chunk"; + case 76: return "iTXt chunk too short to contain required bytes"; + case 77: return "integer overflow in buffer size"; + case 78: return "failed to open file for reading"; /*file doesn't exist or couldn't be opened for reading*/ + case 79: return "failed to open file for writing"; + case 80: return "tried creating a tree of 0 symbols"; + case 81: return "lazy matching at pos 0 is impossible"; + case 82: return "color conversion to palette requested while a color isn't in palette, or index out of bounds"; + case 83: return "memory allocation failed"; + case 84: return "given image too small to contain all pixels to be encoded"; + case 86: return "impossible offset in lz77 encoding (internal bug)"; + case 87: return "must provide custom zlib function pointer if LODEPNG_COMPILE_ZLIB is not defined"; + case 88: return "invalid filter strategy given for LodePNGEncoderSettings.filter_strategy"; + case 89: return "text chunk keyword too short or long: must have size 1-79"; + /*the windowsize in the LodePNGCompressSettings. Requiring POT(==> & instead of %) makes encoding 12% faster.*/ + case 90: return "windowsize must be a power of two"; + case 91: return "invalid decompressed idat size"; + case 92: return "integer overflow due to too many pixels"; + case 93: return "zero width or height is invalid"; + case 94: return "header chunk must have a size of 13 bytes"; + case 95: return "integer overflow with combined idat chunk size"; + case 96: return "invalid gAMA chunk size"; + case 97: return "invalid cHRM chunk size"; + case 98: return "invalid sRGB chunk size"; + case 99: return "invalid sRGB rendering intent"; + case 100: return "invalid ICC profile color type, the PNG specification only allows RGB or GRAY"; + case 101: return "PNG specification does not allow RGB ICC profile on gray color types and vice versa"; + case 102: return "not allowed to set grayscale ICC profile with colored pixels by PNG specification"; + case 103: return "invalid palette index in bKGD chunk. Maybe it came before PLTE chunk?"; + case 104: return "invalid bKGD color while encoding (e.g. palette index out of range)"; + case 105: return "integer overflow of bitsize"; + case 106: return "PNG file must have PLTE chunk if color type is palette"; + case 107: return "color convert from palette mode requested without setting the palette data in it"; + case 108: return "tried to add more than 256 values to a palette"; + /*this limit can be configured in LodePNGDecompressSettings*/ + case 109: return "tried to decompress zlib or deflate data larger than desired max_output_size"; + case 110: return "custom zlib or inflate decompression failed"; + case 111: return "custom zlib or deflate compression failed"; + /*max text size limit can be configured in LodePNGDecoderSettings. This error prevents + unreasonable memory consumption when decoding due to impossibly large text sizes.*/ + case 112: return "compressed text unreasonably large"; + /*max ICC size limit can be configured in LodePNGDecoderSettings. This error prevents + unreasonable memory consumption when decoding due to impossibly large ICC profile*/ + case 113: return "ICC profile unreasonably large"; + case 114: return "sBIT chunk has wrong size for the color type of the image"; + case 115: return "sBIT value out of range"; + case 116: return "cICP value out of range"; + case 117: return "invalid cICP chunk size"; + case 118: return "mDCV value out of range"; + case 119: return "invalid mDCV chunk size"; + case 120: return "invalid cLLI chunk size"; + case 121: return "invalid chunk type name: may only contain [a-zA-Z]"; + case 122: return "invalid chunk type name: third character must be uppercase"; + case 123: return "invalid ICC profile size"; + } + return "unknown error code"; +} +#endif /*LODEPNG_COMPILE_ERROR_TEXT*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* // C++ Wrapper // */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_CPP +namespace lodepng { + +#ifdef LODEPNG_COMPILE_DISK +/* Resizes the vector to the file size and reads the file into it. Returns error code.*/ +static unsigned load_file_(std::vector& buffer, FILE* file) { + long size = lodepng_filesize(file); + if(size < 0) return 78; + buffer.resize((size_t)size); + if(size == 0) return 0; /*ok*/ + if(fread(&buffer[0], 1, buffer.size(), file) != buffer.size()) return 78; + return 0; /*ok*/ +} + +unsigned load_file(std::vector& buffer, const std::string& filename) { + unsigned error; + FILE* file = fopen(filename.c_str(), "rb"); + if(!file) return 78; + error = load_file_(buffer, file); + fclose(file); + return error; +} + +/*write given buffer to the file, overwriting the file, it doesn't append to it.*/ +unsigned save_file(const std::vector& buffer, const std::string& filename) { + return lodepng_save_file(buffer.empty() ? 0 : &buffer[0], buffer.size(), filename.c_str()); +} +#endif /* LODEPNG_COMPILE_DISK */ + +#ifdef LODEPNG_COMPILE_ZLIB +#ifdef LODEPNG_COMPILE_DECODER +unsigned decompress(std::vector& out, const unsigned char* in, size_t insize, + const LodePNGDecompressSettings& settings) { + unsigned char* buffer = 0; + size_t buffersize = 0; + unsigned error = zlib_decompress(&buffer, &buffersize, 0, in, insize, &settings); + if(buffer) { + out.insert(out.end(), buffer, &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned decompress(std::vector& out, const std::vector& in, + const LodePNGDecompressSettings& settings) { + return decompress(out, in.empty() ? 0 : &in[0], in.size(), settings); +} +#endif /* LODEPNG_COMPILE_DECODER */ + +#ifdef LODEPNG_COMPILE_ENCODER +unsigned compress(std::vector& out, const unsigned char* in, size_t insize, + const LodePNGCompressSettings& settings) { + unsigned char* buffer = 0; + size_t buffersize = 0; + unsigned error = zlib_compress(&buffer, &buffersize, in, insize, &settings); + if(buffer) { + out.insert(out.end(), buffer, &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned compress(std::vector& out, const std::vector& in, + const LodePNGCompressSettings& settings) { + return compress(out, in.empty() ? 0 : &in[0], in.size(), settings); +} +#endif /* LODEPNG_COMPILE_ENCODER */ +#endif /* LODEPNG_COMPILE_ZLIB */ + + +#ifdef LODEPNG_COMPILE_PNG + +State::State() { + lodepng_state_init(this); +} + +State::State(const State& other) { + lodepng_state_init(this); + lodepng_state_copy(this, &other); +} + +State::~State() { + lodepng_state_cleanup(this); +} + +State& State::operator=(const State& other) { + lodepng_state_copy(this, &other); + return *this; +} + +#ifdef LODEPNG_COMPILE_DECODER + +unsigned decode(std::vector& out, unsigned& w, unsigned& h, const unsigned char* in, + size_t insize, LodePNGColorType colortype, unsigned bitdepth) { + unsigned char* buffer = 0; + unsigned error = lodepng_decode_memory(&buffer, &w, &h, in, insize, colortype, bitdepth); + if(buffer && !error) { + State state; + state.info_raw.colortype = colortype; + state.info_raw.bitdepth = bitdepth; + size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw); + out.insert(out.end(), buffer, &buffer[buffersize]); + } + lodepng_free(buffer); + return error; +} + +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + const std::vector& in, LodePNGColorType colortype, unsigned bitdepth) { + return decode(out, w, h, in.empty() ? 0 : &in[0], (unsigned)in.size(), colortype, bitdepth); +} + +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + State& state, + const unsigned char* in, size_t insize) { + unsigned char* buffer = NULL; + unsigned error = lodepng_decode(&buffer, &w, &h, &state, in, insize); + if(buffer && !error) { + size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw); + out.insert(out.end(), buffer, &buffer[buffersize]); + } + lodepng_free(buffer); + return error; +} + +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + State& state, + const std::vector& in) { + return decode(out, w, h, state, in.empty() ? 0 : &in[0], in.size()); +} + +#ifdef LODEPNG_COMPILE_DISK +unsigned decode(std::vector& out, unsigned& w, unsigned& h, const std::string& filename, + LodePNGColorType colortype, unsigned bitdepth) { + std::vector buffer; + /* safe output values in case error happens */ + w = h = 0; + unsigned error = load_file(buffer, filename); + if(error) return error; + return decode(out, w, h, buffer, colortype, bitdepth); +} +#endif /* LODEPNG_COMPILE_DECODER */ +#endif /* LODEPNG_COMPILE_DISK */ + +#ifdef LODEPNG_COMPILE_ENCODER +unsigned encode(std::vector& out, const unsigned char* in, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) { + unsigned char* buffer; + size_t buffersize; + unsigned error = lodepng_encode_memory(&buffer, &buffersize, in, w, h, colortype, bitdepth); + if(buffer) { + out.insert(out.end(), buffer, &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned encode(std::vector& out, + const std::vector& in, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) { + if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84; + return encode(out, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth); +} + +unsigned encode(std::vector& out, + const unsigned char* in, unsigned w, unsigned h, + State& state) { + unsigned char* buffer; + size_t buffersize; + unsigned error = lodepng_encode(&buffer, &buffersize, in, w, h, &state); + if(buffer) { + out.insert(out.end(), buffer, &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned encode(std::vector& out, + const std::vector& in, unsigned w, unsigned h, + State& state) { + if(lodepng_get_raw_size(w, h, &state.info_raw) > in.size()) return 84; + return encode(out, in.empty() ? 0 : &in[0], w, h, state); +} + +#ifdef LODEPNG_COMPILE_DISK +unsigned encode(const std::string& filename, + const unsigned char* in, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) { + std::vector buffer; + unsigned error = encode(buffer, in, w, h, colortype, bitdepth); + if(!error) error = save_file(buffer, filename); + return error; +} + +unsigned encode(const std::string& filename, + const std::vector& in, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) { + if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84; + return encode(filename, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth); +} +#endif /* LODEPNG_COMPILE_DISK */ +#endif /* LODEPNG_COMPILE_ENCODER */ +#endif /* LODEPNG_COMPILE_PNG */ +} /* namespace lodepng */ +#endif /*LODEPNG_COMPILE_CPP*/ diff --git a/Modules/lodepng-module/source/module.c b/Modules/lodepng-module/source/module.c new file mode 100644 index 000000000..40af020d3 --- /dev/null +++ b/Modules/lodepng-module/source/module.c @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: Apache-2.0 +#include +#include + +static const struct ModuleSymbol SYMBOLS[] = { + // decode + DEFINE_MODULE_SYMBOL(lodepng_decode_memory), + DEFINE_MODULE_SYMBOL(lodepng_decode32), + DEFINE_MODULE_SYMBOL(lodepng_decode24), + DEFINE_MODULE_SYMBOL(lodepng_decode_file), + DEFINE_MODULE_SYMBOL(lodepng_decode32_file), + DEFINE_MODULE_SYMBOL(lodepng_decode24_file), + // encode + DEFINE_MODULE_SYMBOL(lodepng_encode_memory), + DEFINE_MODULE_SYMBOL(lodepng_encode32), + DEFINE_MODULE_SYMBOL(lodepng_encode24), + DEFINE_MODULE_SYMBOL(lodepng_encode_file), + DEFINE_MODULE_SYMBOL(lodepng_encode32_file), + DEFINE_MODULE_SYMBOL(lodepng_encode24_file), + // utilities + DEFINE_MODULE_SYMBOL(lodepng_error_text), + DEFINE_MODULE_SYMBOL(lodepng_load_file), + DEFINE_MODULE_SYMBOL(lodepng_save_file), + DEFINE_MODULE_SYMBOL(lodepng_malloc), + DEFINE_MODULE_SYMBOL(lodepng_realloc), + DEFINE_MODULE_SYMBOL(lodepng_free), + MODULE_SYMBOL_TERMINATOR, +}; + +struct Module lodepng_module = { + .name = "lodepng", + .start = NULL, + .stop = NULL, + .drivers = NULL, + .symbols = SYMBOLS, + .internal = NULL, +}; diff --git a/Modules/lodepng-module/tests/CMakeLists.txt b/Modules/lodepng-module/tests/CMakeLists.txt new file mode 100644 index 000000000..585cb9e6a --- /dev/null +++ b/Modules/lodepng-module/tests/CMakeLists.txt @@ -0,0 +1,20 @@ +project(LodePngModuleTests) + +enable_language(C CXX ASM) + +file(GLOB_RECURSE TEST_SOURCES CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/source/*.cpp) +add_executable(LodePngModuleTests EXCLUDE_FROM_ALL ${TEST_SOURCES}) + +target_include_directories(LodePngModuleTests PRIVATE ${DOCTESTINC}) + +target_compile_definitions(LodePngModuleTests PRIVATE + "LODEPNG_TEST_LOGO=\"${CMAKE_SOURCE_DIR}/Data/system/app/Boot/assets/logo.png\"" +) + +add_test(NAME LodePngModuleTests COMMAND LodePngModuleTests) + +target_link_libraries(LodePngModuleTests PUBLIC + lodepng-module + TactilityKernel + freertos_kernel +) diff --git a/Modules/lodepng-module/tests/source/lodepng_test.cpp b/Modules/lodepng-module/tests/source/lodepng_test.cpp new file mode 100644 index 000000000..c132f47a3 --- /dev/null +++ b/Modules/lodepng-module/tests/source/lodepng_test.cpp @@ -0,0 +1,47 @@ +#include "doctest.h" + +#include + +#include + +TEST_CASE("lodepng decodes a PNG file") { + unsigned char* image = nullptr; + unsigned width = 0; + unsigned height = 0; + REQUIRE_EQ(lodepng_decode32_file(&image, &width, &height, LODEPNG_TEST_LOGO), 0); + CHECK_EQ(width, 80); + CHECK_EQ(height, 103); + lodepng_free(image); +} + +TEST_CASE("lodepng returns an error for a missing file") { + unsigned char* image = nullptr; + unsigned width = 0; + unsigned height = 0; + CHECK_NE(lodepng_decode32_file(&image, &width, &height, "missing.png"), 0); + lodepng_free(image); +} + +TEST_CASE("lodepng encodes and decodes an image without changes") { + constexpr unsigned width = 3; + constexpr unsigned height = 2; + const unsigned char pixels[width * height * 4] = { + 255, 0, 0, 255, 0, 255, 0, 255, 0, 0, 255, 255, + 0, 0, 0, 0, 255, 255, 255, 128, 10, 20, 30, 40, + }; + + unsigned char* png = nullptr; + size_t png_size = 0; + REQUIRE_EQ(lodepng_encode32(&png, &png_size, pixels, width, height), 0); + + unsigned char* decoded = nullptr; + unsigned decoded_width = 0; + unsigned decoded_height = 0; + REQUIRE_EQ(lodepng_decode32(&decoded, &decoded_width, &decoded_height, png, png_size), 0); + CHECK_EQ(decoded_width, width); + CHECK_EQ(decoded_height, height); + CHECK_EQ(memcmp(decoded, pixels, sizeof(pixels)), 0); + + lodepng_free(png); + lodepng_free(decoded); +} diff --git a/Modules/lodepng-module/tests/source/main.cpp b/Modules/lodepng-module/tests/source/main.cpp new file mode 100644 index 000000000..93a036fac --- /dev/null +++ b/Modules/lodepng-module/tests/source/main.cpp @@ -0,0 +1,64 @@ +#define DOCTEST_CONFIG_IMPLEMENT +#include "doctest.h" +#include +#include + +#include "FreeRTOS.h" +#include "task.h" + +typedef struct { + int argc; + char** argv; + int result; +} TestTaskData; + +void test_task(void* parameter) { + auto* data = (TestTaskData*)parameter; + + doctest::Context context; + + context.applyCommandLine(data->argc, data->argv); + + // overrides + context.setOption("no-breaks", true); // don't break in the debugger when assertions fail + + data->result = context.run(); + + vTaskEndScheduler(); + + vTaskDelete(nullptr); +} + +int main(int argc, char** argv) { + TestTaskData data = { + .argc = argc, + .argv = argv, + .result = 0 + }; + + BaseType_t task_result = xTaskCreate( + test_task, + "test_task", + 8192, + &data, + 1, + nullptr + ); + + if (task_result != pdPASS) { + return 1; + } + + vTaskStartScheduler(); + + return data.result; +} + +// NOTE: This is normally provided by the platform kernel module, but that's not loaded for lodepng-module +extern "C" { +// Required for FreeRTOS +void vAssertCalled(unsigned long line, const char* const file) { + std::fprintf(stderr, "assert failed at %s:%lu\n", file, line); + std::abort(); +} +} diff --git a/Modules/lvgl-module/CMakeLists.txt b/Modules/lvgl-module/CMakeLists.txt index 06337ee1d..93d09deb3 100644 --- a/Modules/lvgl-module/CMakeLists.txt +++ b/Modules/lvgl-module/CMakeLists.txt @@ -74,6 +74,7 @@ file(GLOB_RECURSE SOURCE_FILES "source/*.c*") list(APPEND REQUIRES_LIST TactilityKernel binfont-module + lodepng-module lvgl ) diff --git a/Modules/lvgl-module/private/png_decoder.h b/Modules/lvgl-module/private/png_decoder.h new file mode 100644 index 000000000..9fd13ba67 --- /dev/null +++ b/Modules/lvgl-module/private/png_decoder.h @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +/** Registers the PNG image decoder with LVGL. Must be called after lv_init(). */ +void lvgl_png_decoder_init(void); diff --git a/Modules/lvgl-module/source/arch/lvgl_esp32.c b/Modules/lvgl-module/source/arch/lvgl_esp32.c index 63d1134ce..45f95f6a3 100644 --- a/Modules/lvgl-module/source/arch/lvgl_esp32.c +++ b/Modules/lvgl-module/source/arch/lvgl_esp32.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -52,6 +53,10 @@ error_t lvgl_arch_start() { // devices and services. The latter might start adding widgets immediately. initialized = true; + lvgl_lock(); + lvgl_png_decoder_init(); + lvgl_unlock(); + // Must exist before devices/services are attached below, since those can // immediately try to assign an indev to this group (e.g. USB HID input). lvgl_keyboard_on_start_lvgl(); diff --git a/Modules/lvgl-module/source/arch/lvgl_posix.c b/Modules/lvgl-module/source/arch/lvgl_posix.c index 21a285144..673dd0b8e 100644 --- a/Modules/lvgl-module/source/arch/lvgl_posix.c +++ b/Modules/lvgl-module/source/arch/lvgl_posix.c @@ -13,6 +13,7 @@ #include #include #include +#include extern struct LvglModuleConfig lvgl_module_config; extern void lvgl_devices_attach(); @@ -129,6 +130,7 @@ error_t lvgl_arch_start() { lvgl_task_set_interrupted(false); lv_init(); + lvgl_png_decoder_init(); // Must exist before devices/services are attached from the lvgl task below, // since those can immediately try to assign an indev to this group. diff --git a/Modules/lvgl-module/source/png_decoder.c b/Modules/lvgl-module/source/png_decoder.c new file mode 100644 index 000000000..9553d606a --- /dev/null +++ b/Modules/lvgl-module/source/png_decoder.c @@ -0,0 +1,175 @@ +// SPDX-License-Identifier: MIT +// Based on LVGL's lv_lodepng.c (MIT license, Copyright (c) 2020 LVGL Kft), adapted to decode with lodepng-module. + +#include + +#include + +#include +#include +#include + +#define DECODER_NAME "LODEPNG" + +#define image_cache_draw_buf_handlers &(LV_GLOBAL_DEFAULT()->image_cache_draw_buf_handlers) + +static const uint8_t PNG_MAGIC[] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a }; + +static uint32_t read_u32_big_endian(const uint8_t* bytes) { + return ((uint32_t)bytes[0] << 24) | ((uint32_t)bytes[1] << 16) | ((uint32_t)bytes[2] << 8) | bytes[3]; +} + +static lv_result_t decoder_info(lv_image_decoder_t* decoder, lv_image_decoder_dsc_t* dsc, lv_image_header_t* header) { + LV_UNUSED(decoder); + + // Width and height are at bytes 16..23 of a PNG file, in big endian + uint8_t buffer[24]; + if (dsc->src_type == LV_IMAGE_SRC_FILE) { + uint32_t read_count; + lv_fs_read(&dsc->file, buffer, sizeof(buffer), &read_count); + if (read_count != sizeof(buffer)) return LV_RESULT_INVALID; + } else if (dsc->src_type == LV_IMAGE_SRC_VARIABLE) { + const lv_image_dsc_t* image_dsc = dsc->src; + if (image_dsc->data_size < sizeof(buffer)) return LV_RESULT_INVALID; + lv_memcpy(buffer, image_dsc->data, sizeof(buffer)); + } else { + return LV_RESULT_INVALID; + } + + if (lv_memcmp(buffer, PNG_MAGIC, sizeof(PNG_MAGIC)) != 0) return LV_RESULT_INVALID; + + header->cf = LV_COLOR_FORMAT_ARGB8888; + header->w = read_u32_big_endian(&buffer[16]); + header->h = read_u32_big_endian(&buffer[20]); + return LV_RESULT_OK; +} + +/** Reads a whole file through lv_fs, so LVGL drive letter paths ("A:...") work */ +static uint8_t* load_file(const char* path, size_t* out_size) { + lv_fs_file_t file; + if (lv_fs_open(&file, path, LV_FS_MODE_RD) != LV_FS_RES_OK) return NULL; + + uint8_t* data = NULL; + uint32_t size = 0; + if (lv_fs_seek(&file, 0, LV_FS_SEEK_END) == LV_FS_RES_OK && + lv_fs_tell(&file, &size) == LV_FS_RES_OK && + size > 0 && + lv_fs_seek(&file, 0, LV_FS_SEEK_SET) == LV_FS_RES_OK) { + data = lodepng_malloc(size); + uint32_t read_count = 0; + if (data != NULL && (lv_fs_read(&file, data, size, &read_count) != LV_FS_RES_OK || read_count != size)) { + lodepng_free(data); + data = NULL; + } + } + lv_fs_close(&file); + *out_size = size; + return data; +} + +/** Decodes a PNG into an ARGB8888 draw buffer */ +static lv_draw_buf_t* decode_png_data(const uint8_t* png_data, size_t png_data_size) { + unsigned char* rgba = NULL; + unsigned width; + unsigned height; + const unsigned error = lodepng_decode32(&rgba, &width, &height, png_data, png_data_size); + if (error) { + LV_LOG_WARN("error %u: %s", error, lodepng_error_text(error)); + lodepng_free(rgba); + return NULL; + } + + lv_draw_buf_t* decoded = lv_draw_buf_create_ex(image_cache_draw_buf_handlers, width, height, LV_COLOR_FORMAT_ARGB8888, LV_STRIDE_AUTO); + if (decoded != NULL) { + // lodepng outputs RGBA bytes, LVGL's ARGB8888 is BGRA in memory + for (unsigned y = 0; y < height; y++) { + const unsigned char* source = rgba + (size_t)y * width * 4; + lv_color32_t* target = (lv_color32_t*)(decoded->data + (size_t)y * decoded->header.stride); + for (unsigned x = 0; x < width; x++) { + target[x].red = source[x * 4]; + target[x].green = source[x * 4 + 1]; + target[x].blue = source[x * 4 + 2]; + target[x].alpha = source[x * 4 + 3]; + } + } + } + + lodepng_free(rgba); + return decoded; +} + +static lv_result_t decoder_open(lv_image_decoder_t* decoder, lv_image_decoder_dsc_t* dsc) { + LV_PROFILER_DECODER_BEGIN_TAG("png_decoder_open"); + + lv_draw_buf_t* decoded = NULL; + if (dsc->src_type == LV_IMAGE_SRC_FILE) { + size_t size = 0; + uint8_t* data = load_file(dsc->src, &size); + if (data == NULL) { + LV_LOG_WARN("Failed to load %s", (const char*)dsc->src); + LV_PROFILER_DECODER_END_TAG("png_decoder_open"); + return LV_RESULT_INVALID; + } + decoded = decode_png_data(data, size); + lodepng_free(data); + } else if (dsc->src_type == LV_IMAGE_SRC_VARIABLE) { + const lv_image_dsc_t* image_dsc = dsc->src; + decoded = decode_png_data(image_dsc->data, image_dsc->data_size); + } + + if (decoded == NULL) { + LV_LOG_WARN("Error decoding PNG"); + LV_PROFILER_DECODER_END_TAG("png_decoder_open"); + return LV_RESULT_INVALID; + } + + lv_draw_buf_t* adjusted = lv_image_decoder_post_process(dsc, decoded); + if (adjusted == NULL) { + lv_draw_buf_destroy(decoded); + LV_PROFILER_DECODER_END_TAG("png_decoder_open"); + return LV_RESULT_INVALID; + } + + // The adjusted draw buffer is newly allocated + if (adjusted != decoded) { + lv_draw_buf_destroy(decoded); + decoded = adjusted; + } + + dsc->decoded = decoded; + + if (dsc->args.no_cache || !lv_image_cache_is_enabled()) { + LV_PROFILER_DECODER_END_TAG("png_decoder_open"); + return LV_RESULT_OK; + } + + lv_image_cache_data_t search_key; + search_key.src_type = dsc->src_type; + search_key.src = dsc->src; + search_key.slot.size = decoded->data_size; + + lv_cache_entry_t* entry = lv_image_decoder_add_to_cache(decoder, &search_key, decoded, NULL); + if (entry == NULL) { + LV_PROFILER_DECODER_END_TAG("png_decoder_open"); + return LV_RESULT_INVALID; + } + dsc->cache_entry = entry; + + LV_PROFILER_DECODER_END_TAG("png_decoder_open"); + return LV_RESULT_OK; +} + +static void decoder_close(lv_image_decoder_t* decoder, lv_image_decoder_dsc_t* dsc) { + LV_UNUSED(decoder); + if (dsc->args.no_cache || !lv_image_cache_is_enabled()) { + lv_draw_buf_destroy((lv_draw_buf_t*)dsc->decoded); + } +} + +void lvgl_png_decoder_init(void) { + lv_image_decoder_t* decoder = lv_image_decoder_create(); + lv_image_decoder_set_info_cb(decoder, decoder_info); + lv_image_decoder_set_open_cb(decoder, decoder_open); + lv_image_decoder_set_close_cb(decoder, decoder_close); + decoder->name = DECODER_NAME; +} diff --git a/Tactility/CMakeLists.txt b/Tactility/CMakeLists.txt index bc07fde26..0f5f177ed 100644 --- a/Tactility/CMakeLists.txt +++ b/Tactility/CMakeLists.txt @@ -32,6 +32,7 @@ list(APPEND REQUIRES_LIST coreutils-module audio-decoder-module binfont-module + lodepng-module c-symbols-module cjson-module cpp-symbols-module diff --git a/Tactility/Include/Tactility/Tactility.h b/Tactility/Include/Tactility/Tactility.h index 1796c7b1c..35d21487a 100644 --- a/Tactility/Include/Tactility/Tactility.h +++ b/Tactility/Include/Tactility/Tactility.h @@ -38,11 +38,12 @@ class MainDispatcher final { }; /** - * @brief Main entry point for Tactility. + * @brief Initializes Tactility and starts the Boot app. * @param dtsModules List of modules from devicetree, null-terminated, non-null parameter * @param dtsDevices Array that is terminated with DTS_DEVICE_TERMINATOR + * @return false when the kernel failed to initialize */ -void run(Module* const dtsModules[], const DtsDevice dtsDevices[]); +bool init(Module* const dtsModules[], const DtsDevice dtsDevices[]); /** Provides access to the dispatcher that runs on the main task. * @warning This dispatcher is used for WiFi and might block for some time during WiFi connection. diff --git a/Tactility/Private/Tactility/TactilityPrivate.h b/Tactility/Private/Tactility/TactilityPrivate.h index 243edb95a..14815b4c2 100644 --- a/Tactility/Private/Tactility/TactilityPrivate.h +++ b/Tactility/Private/Tactility/TactilityPrivate.h @@ -1,8 +1,24 @@ #pragma once +#include + namespace tt { +/** @return the handle of the dispatcher that getMainDispatcher() wraps */ +DispatcherHandle_t getMainDispatcherHandle(); + void prepareFileSystems(); + +/** Starts the kernel modules that Tactility depends on. */ +void initModules(); + +/** Registers and starts the primary system services. */ +void registerAndStartServices(); + +/** Registers the internal apps and the apps installed on mounted file systems. */ void registerApps(); +/** Registers and starts the Boot app. */ +void startBootApp(); + } diff --git a/Tactility/Private/Tactility/app/boot/BootScreen.h b/Tactility/Private/Tactility/app/boot/BootScreen.h new file mode 100644 index 000000000..6351b4f51 --- /dev/null +++ b/Tactility/Private/Tactility/app/boot/BootScreen.h @@ -0,0 +1,61 @@ +#pragma once + +#include +#include + +struct Device; +struct PixelBuffer; + +namespace tt::app::boot { + +/** + * Draws boot screens directly to the display, for use while LVGL isn't running. + * Content is drawn in the orientation from the display settings. + */ +class BootScreen { + + Device* display = nullptr; + int panelWidth = 0; + int panelHeight = 0; + /** 0, 1, 2 or 3 for a rotation of 0, 90, 180 or 270 degrees */ + int rotation = 0; + PixelBuffer* target = nullptr; + /** Second hardware frame buffer, kept in sync with target */ + PixelBuffer* secondFrameBuffer = nullptr; + int bandHeight = 0; + + int logicalWidth() const { return (rotation % 2 == 0) ? panelWidth : panelHeight; } + int logicalHeight() const { return (rotation % 2 == 0) ? panelHeight : panelWidth; } + +public: + + ~BootScreen(); + + /** @return false when there is no usable display */ + bool begin(); + + /** Releases the display, so LVGL can take over. */ + void end(); + + /** @return the smallest logical display dimension, or 0 when there is no display */ + int getSmallestDimension() const; + + /** + * Shows a logo with text lines below it, centered on a black background. + * @param[in] logoPath path to a PNG file, or empty for no logo + * @param[in] lines text lines, wrapped when they're too long for the display + */ + void show(const std::string& logoPath, const std::vector& lines); +}; + +/** + * @param[in] action what happens on input, e.g. "reboot" + * @return "Press any key to " when a keyboard is available, otherwise + * "Touch the screen to " when a pointer is available, otherwise an empty string + */ +std::string getInputPrompt(const std::string& action); + +/** Blocks until any key is pressed on a keyboard or the screen is touched. */ +void waitForInput(); + +} diff --git a/Tactility/Private/Tactility/app/boot/BootSequence.h b/Tactility/Private/Tactility/app/boot/BootSequence.h new file mode 100644 index 000000000..849994e0c --- /dev/null +++ b/Tactility/Private/Tactility/app/boot/BootSequence.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +namespace tt::app::boot { + +/** + * Shows the splash, prepares the system and starts LVGL and the launcher. + * Halts on an error screen when the boot can't continue. + * @param[in] startTime the ticks at which the boot app started, for the minimal splash duration + * @return true when the boot completed and the next app was started + */ +bool runBootSequence(TickType_t startTime); + +} diff --git a/Tactility/Source/Init.cpp b/Tactility/Source/Init.cpp new file mode 100644 index 000000000..3866f2b27 --- /dev/null +++ b/Tactility/Source/Init.cpp @@ -0,0 +1,66 @@ +#ifdef ESP_PLATFORM +#include +#include +#endif + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace tt { + +constexpr auto* TAG = "Tactility"; + +void prepareFileSystems() { + char temp_path[FILE_MAX_PATH_STRING_LENGTH]; + if (paths_get_temp_path(temp_path, sizeof(temp_path)) != ERROR_NONE) { + LOG_E(TAG, "Failed to determine temp path"); + return; + } + if (!file::findOrCreateDirectory(temp_path, 0777)) { + LOG_E(TAG, "Failed to create %s", temp_path); + } +} + +bool init(Module* const dtsModules[], const DtsDevice dtsDevices[]) { + LOG_I(TAG, "Tactility v%s on %s (%s)", TT_VERSION, CONFIG_TT_DEVICE_NAME, CONFIG_TT_DEVICE_ID); + + LOG_I(TAG, "Initializing kernel"); + if (kernel_init(dtsModules, dtsDevices) != ERROR_NONE) { + LOG_E(TAG, "Failed to initialize kernel"); + return false; + } + + initModules(); + +#ifdef ESP_PLATFORM + initEsp(); +#endif + + settings::initTimeZone(); + + // Attempt to start all disabled SD cards (some require delayed init) + hal::sdcard::startAll(); + + network::ntp::init(); + bluetooth::systemStart(); + + registerAndStartServices(); + + LOG_I(TAG, "Core systems ready"); + + startBootApp(); + + return true; +} + +} // namespace diff --git a/Tactility/Source/InitApps.cpp b/Tactility/Source/InitApps.cpp new file mode 100644 index 000000000..d4c568759 --- /dev/null +++ b/Tactility/Source/InitApps.cpp @@ -0,0 +1,230 @@ +#include + +#ifdef ESP_PLATFORM +#include +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace tt { + +constexpr auto* TAG = "Tactility"; + +// region Default apps + +// All apps below are converted to the new app-module + window-manager model, so their manifest +// is the new, global ::AppManifest, not this namespace's old tt::app::AppManifest. +namespace app { + namespace addgps { extern const ::AppManifest manifest; } + namespace alertdialog { extern const ::AppManifest manifest; } + namespace apphub { extern const ::AppManifest manifest; } + namespace apphubdetails { extern const ::AppManifest manifest; } + namespace apppackagedetails { extern const ::AppManifest manifest; } + namespace applist { extern const ::AppManifest manifest; } + namespace apppackagelist { extern const ::AppManifest manifest; } + namespace audiosettings { extern const ::AppManifest manifest; } + namespace boot { extern const ::AppManifest manifest; } + namespace development { extern const ::AppManifest manifest; } + namespace display { extern const ::AppManifest manifest; } + namespace files { extern const ::AppManifest manifest; } + namespace fileselection { extern const ::AppManifest manifest; } + namespace gpssettings { extern const ::AppManifest manifest; } + namespace grovesettings { extern const ::AppManifest manifest; } + namespace i2cscanner { extern const ::AppManifest manifest; } + namespace imageviewer { extern const ::AppManifest manifest; } + namespace inputdialog { extern const ::AppManifest manifest; } + namespace launcher { extern const ::AppManifest manifest; } + namespace ledstripsettings { extern const ::AppManifest manifest; } + namespace localesettings { extern const ::AppManifest manifest; } + namespace notes { extern const ::AppManifest manifest; } + namespace power { extern const ::AppManifest manifest; } + namespace poweroff { extern const ::AppManifest manifest; } + namespace selectiondialog { extern const ::AppManifest manifest; } + namespace settings { extern const ::AppManifest manifest; } + namespace setup { extern const ::AppManifest manifest; } + namespace shell { extern const ::AppManifest manifest; extern const ::AppManifest sh_manifest; } + namespace systeminfo { extern const ::AppManifest manifest; } + namespace terminal { extern const ::AppManifest manifest; } + namespace timedatesettings { extern const ::AppManifest manifest; } +#ifdef CONFIG_TT_TOUCH_CALIBRATION_SUPPORTED + namespace touchcalibration { extern const ::AppManifest manifest; } +#endif + namespace timezone { extern const ::AppManifest manifest; } + namespace usbsettings { extern const ::AppManifest manifest; } + namespace btmanage { extern const ::AppManifest manifest; } + namespace btpeersettings { extern const ::AppManifest manifest; } + namespace wifiapsettings { extern const ::AppManifest manifest; } + namespace wificonnect { extern const ::AppManifest manifest; } + namespace wifimanage { extern const ::AppManifest manifest; } + + namespace webserversettings { extern const ::AppManifest manifest; } +#ifdef ESP_PLATFORM + namespace apwebserver { extern const ::AppManifest manifest; } + namespace camera { extern const ::AppManifest manifest; } + namespace crashdiagnostics { extern const ::AppManifest manifest; } +#if CONFIG_TT_TDECK_WORKAROUND == 1 + namespace keyboardsettings { extern const ::AppManifest manifest; } // T-Deck only for now +#endif +#endif + + namespace trackballsettings { extern const ::AppManifest manifest; } // T-Deck only for now + +#if TT_FEATURE_SCREENSHOT_ENABLED + namespace screenshot { extern const ::AppManifest manifest; } +#endif + +#if defined(CONFIG_SOC_WIFI_SUPPORTED) || defined(CONFIG_ESP_HOSTED_ENABLED) + namespace chat { extern const ::AppManifest manifest; } +#endif +} + +// endregion + +// List of all apps excluding Boot app (as Boot app calls this function indirectly) +static void registerInternalApps() { + LOG_I(TAG, "Registering internal apps"); + + app_manager_add(&app::alertdialog::manifest); + app_manager_add(&app::apppackagedetails::manifest); + app_manager_add(&app::apphub::manifest); + app_manager_add(&app::apphubdetails::manifest); + app_manager_add(&app::applist::manifest); + app_manager_add(&app::apppackagelist::manifest); + if (service::audio::isAvailable()) { + app_manager_add(&app::audiosettings::manifest); + } + if (device_exists_of_type(&DISPLAY_TYPE)) { + app_manager_add(&app::display::manifest); + } + if (device_exists_of_type(&LED_STRIP_TYPE)) { + app_manager_add(&app::ledstripsettings::manifest); + } + app_manager_add(&app::files::manifest); + app_manager_add(&app::fileselection::manifest); + app_manager_add(&app::i2cscanner::manifest); + app_manager_add(&app::imageviewer::manifest); + app_manager_add(&app::inputdialog::manifest); + app_manager_add(&app::launcher::manifest); + app_manager_add(&app::localesettings::manifest); + app_manager_add(&app::notes::manifest); + if (device_exists_of_type(&POWER_SUPPLY_TYPE)) { + app_manager_add(&app::poweroff::manifest); + } + app_manager_add(&app::settings::manifest); + app_manager_add(&app::selectiondialog::manifest); + app_manager_add(&app::setup::manifest); + app_manager_add(&app::shell::manifest); + app_manager_add(&app::shell::sh_manifest); + app_manager_add(&app::systeminfo::manifest); + app_manager_add(&app::timedatesettings::manifest); + app_manager_add(&app::terminal::manifest); +#ifdef CONFIG_TT_TOUCH_CALIBRATION_SUPPORTED + app_manager_add(&app::touchcalibration::manifest); +#endif + app_manager_add(&app::timezone::manifest); + app_manager_add(&app::wifiapsettings::manifest); + app_manager_add(&app::wificonnect::manifest); + app_manager_add(&app::wifimanage::manifest); + + app_manager_add(&app::development::manifest); + app_manager_add(&app::webserversettings::manifest); +#ifdef ESP_PLATFORM + app_manager_add(&app::apwebserver::manifest); + if (device_exists_of_type(&CAMERA_TYPE)) { + app_manager_add(&app::camera::manifest); + } + app_manager_add(&app::crashdiagnostics::manifest); +#if defined(CONFIG_TT_TDECK_WORKAROUND) + app_manager_add(&app::keyboardsettings::manifest); +#endif +#endif + + if (device_exists_of_type(&TRACKBALL_TYPE)) { + app_manager_add(&app::trackballsettings::manifest); + } + +#if defined(CONFIG_TINYUSB_MSC_ENABLED) && CONFIG_TINYUSB_MSC_ENABLED + app_manager_add(&app::usbsettings::manifest); +#endif + +#if TT_FEATURE_SCREENSHOT_ENABLED + app_manager_add(&app::screenshot::manifest); +#endif + +#if defined(CONFIG_SOC_WIFI_SUPPORTED) || defined(CONFIG_ESP_HOSTED_ENABLED) + app_manager_add(&app::chat::manifest); +#endif + + if (device_exists_of_type(&GROVE_TYPE)) { + app_manager_add(&app::grovesettings::manifest); + } + + if (device_exists_of_type(&UART_CONTROLLER_TYPE) || device_exists_of_type(&GROVE_TYPE)) { + app_manager_add(&app::addgps::manifest); + app_manager_add(&app::gpssettings::manifest); + } + + if (device_exists_of_type(&POWER_SUPPLY_TYPE)) { + app_manager_add(&app::power::manifest); + } + +#if defined(CONFIG_BT_ENABLED) && CONFIG_BT_ENABLED + app_manager_add(&app::btmanage::manifest); + app_manager_add(&app::btpeersettings::manifest); +#endif +} + +// Registers every mounted filesystem's app install directory with app-module (see +// app_manager_install_path_add()/app_manager_install_path_scan() in app/install.h), then scans +// them once to register whatever's already installed there. +static void registerInstalledAppsFromFileSystems() { + file_system_for_each(nullptr, [](auto* fs, void* context) { + if (!file_system_is_mounted(fs)) return true; + char path[128]; + if (file_system_get_path(fs, path, sizeof(path)) != ERROR_NONE) return true; + const auto app_path = std::format("{}/tactility/app", path); + if (!app_path.starts_with(file::MOUNT_POINT_SYSTEM) && file::isDirectory(app_path)) { + LOG_I(TAG, "Registering install path %s", app_path.c_str()); + app_manager_install_path_add(app_path.c_str()); + } + return true; + }); + app_manager_install_path_scan(); +} + +void registerApps() { + registerInternalApps(); + registerInstalledAppsFromFileSystems(); +} + +void startBootApp() { + LOG_I(TAG, "Starting boot app"); + // The boot app takes care of registering system apps, user services and user apps, and starts LVGL. + app_manager_add(&app::boot::manifest); + uint32_t boot_instance_id = 0; + AppStartContext boot_context = app_start_context_for_manifest(&app::boot::manifest); + app_start_with_context(&boot_context, &boot_instance_id); +} + +} // namespace diff --git a/Tactility/Source/InitModules.cpp b/Tactility/Source/InitModules.cpp new file mode 100644 index 000000000..ccf45dba6 --- /dev/null +++ b/Tactility/Source/InitModules.cpp @@ -0,0 +1,82 @@ +#include + +#ifdef ESP_PLATFORM +#include +#include +#endif + +#if __has_include() && not defined(ESP_PLATFORM) +#define TT_IS_POSIX 1 +#else +#define TT_IS_POSIX 0 +#endif + +#if TT_IS_POSIX or defined(ESP_PLATFORM) // esp-idf supports certain posix symbols +#include +#endif + +#if TT_IS_POSIX +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +// Audio service exports to external ELF apps (Source/service/audio/AudioExports.cpp). +extern "C" Module tactility_audio_module; + +namespace tt { + +void initModules() { + // The following groups of symbols are sorted by the estimated chance of them occurring + + // C/C++/Posix symbols + check(module_ensure_started(&c_symbols_module) == ERROR_NONE); + check(module_ensure_started(&cjson_module) == ERROR_NONE); +#if TT_IS_POSIX or defined(ESP_PLATFORM) // esp-idf supports certain posix symbols + check(module_ensure_started(&posix_symbols_module) == ERROR_NONE); +#endif + check(module_ensure_started(&cpp_symbols_module) == ERROR_NONE); + // OS level symbols + check(module_ensure_started(&freertos_module) == ERROR_NONE); + check(module_ensure_started(&pthread_module) == ERROR_NONE); + // Other libraries + check(module_ensure_started(&http_module) == ERROR_NONE); + check(module_ensure_started(&graphics_module) == ERROR_NONE); + check(module_ensure_started(&lodepng_module) == ERROR_NONE); + check(module_ensure_started(&binfont_module) == ERROR_NONE); + check(module_ensure_started(&app_module) == ERROR_NONE); + check(module_ensure_started(&coreutils_module) == ERROR_NONE); + check(module_ensure_started(&crypt_module) == ERROR_NONE); + check(module_ensure_started(&audio_decoder_module) == ERROR_NONE); + check(module_ensure_started(&mbedtls_module) == ERROR_NONE); + check(module_ensure_started(&gps_module) == ERROR_NONE); + check(module_ensure_started(&gps_generic_module) == ERROR_NONE); + check(module_ensure_started(&gps_meshtastic_module) == ERROR_NONE); +#ifdef ESP_PLATFORM + check(module_ensure_started(&app_esp32_module) == ERROR_NONE); +#elif TT_IS_POSIX + check(module_ensure_started(&app_posix_module) == ERROR_NONE); +#endif + check(module_ensure_started(&tactility_audio_module) == ERROR_NONE); +} + +} // namespace diff --git a/Tactility/Source/InitServices.cpp b/Tactility/Source/InitServices.cpp new file mode 100644 index 000000000..43ab55d37 --- /dev/null +++ b/Tactility/Source/InitServices.cpp @@ -0,0 +1,59 @@ +#include + +#ifdef ESP_PLATFORM +#include +#endif + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +namespace tt { + +constexpr auto* TAG = "Tactility"; + +// region Default services +namespace service { + // Primary + namespace audio { extern const ServiceManifest manifest; } + namespace development { extern const ServiceManifest manifest; } +#if defined(CONFIG_SOC_WIFI_SUPPORTED) || defined(CONFIG_ESP_HOSTED_ENABLED) + namespace espnow { extern const ServiceManifest manifest; } +#endif +#ifdef ESP_PLATFORM + namespace rtctime { extern const ServiceManifest manifest; } +#endif + namespace webserver { extern const ServiceManifest manifest; } + +} + +// endregion + +void registerAndStartServices() { + LOG_I(TAG, "Registering and starting primary system services"); + if (device_exists_of_type(&AUDIO_STREAM_TYPE)) { + addService(service::audio::manifest); + } + check(module_ensure_started(&wifi_module) == ERROR_NONE); + addService(service::development::manifest); + addService(service::webserver::manifest); + +#if defined(CONFIG_SOC_WIFI_SUPPORTED) || defined(CONFIG_ESP_HOSTED_ENABLED) + addService(service::espnow::manifest); +#endif +#if defined(ESP_PLATFORM) + if (device_exists_of_type(&RTC_TYPE)) { + addService(service::rtctime::manifest); + } +#endif +} + +} // namespace diff --git a/Tactility/Source/Main.cpp b/Tactility/Source/Main.cpp index cc861a429..d1f9b48da 100644 --- a/Tactility/Source/Main.cpp +++ b/Tactility/Source/Main.cpp @@ -1,15 +1,28 @@ #include +#include #include +#include + #ifndef ESP_PLATFORM #include #endif +constexpr auto* TAG = "Main"; + extern "C" { void app_main() { - tt::run(dts_modules, dts_devices); + if (!tt::init(dts_modules, dts_devices)) { + return; + } + + LOG_I(TAG, "Main dispatcher ready"); + const auto dispatcher = tt::getMainDispatcherHandle(); + while (true) { + dispatcher_consume(dispatcher); + } } -} // extern \ No newline at end of file +} // extern diff --git a/Tactility/Source/MainDispatcher.cpp b/Tactility/Source/MainDispatcher.cpp new file mode 100644 index 000000000..d0402b5d6 --- /dev/null +++ b/Tactility/Source/MainDispatcher.cpp @@ -0,0 +1,35 @@ +#include +#include + +namespace tt { + +static DispatcherHandle_t mainDispatcherHandle = dispatcher_alloc(); + +namespace { + +void mainDispatcherTrampoline(void* context) { + auto* function = static_cast(context); + (*function)(); + delete function; +} + +} // namespace + +bool MainDispatcher::dispatch(Function function, TickType_t timeout) const { + auto* boxed = new Function(std::move(function)); + if (dispatcher_dispatch_timed(handle, boxed, mainDispatcherTrampoline, timeout) != ERROR_NONE) { + delete boxed; + return false; + } + return true; +} + +MainDispatcher getMainDispatcher() { + return MainDispatcher(mainDispatcherHandle); +} + +DispatcherHandle_t getMainDispatcherHandle() { + return mainDispatcherHandle; +} + +} // namespace diff --git a/Tactility/Source/Tactility.cpp b/Tactility/Source/Tactility.cpp deleted file mode 100644 index c823fdc47..000000000 --- a/Tactility/Source/Tactility.cpp +++ /dev/null @@ -1,610 +0,0 @@ -#ifdef ESP_PLATFORM -#include -#include -#include -#endif - -#if __has_include() && not defined(ESP_PLATFORM) -#define TT_IS_POSIX 1 -#else -#define TT_IS_POSIX 0 -#endif - -#if TT_IS_POSIX or defined(ESP_PLATFORM) // esp-idf supports certain posix symbols -#include -#endif - -#if TT_IS_POSIX -#include -#endif - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_TT_TOUCH_CALIBRATION_SUPPORTED -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - - -// Audio service exports to external ELF apps (Source/service/audio/AudioExports.cpp). -extern "C" Module tactility_audio_module; -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace tt { - -constexpr auto* TAG = "Tactility"; - -static DispatcherHandle_t mainDispatcherHandle = dispatcher_alloc(); - -namespace { - -void mainDispatcherTrampoline(void* context) { - auto* function = static_cast(context); - (*function)(); - delete function; -} - -} // namespace - -bool MainDispatcher::dispatch(Function function, TickType_t timeout) const { - auto* boxed = new Function(std::move(function)); - if (dispatcher_dispatch_timed(handle, boxed, mainDispatcherTrampoline, timeout) != ERROR_NONE) { - delete boxed; - return false; - } - return true; -} - -// region Default services -namespace service { - // Primary - namespace audio { extern const ServiceManifest manifest; } - namespace autorotate { extern const ServiceManifest manifest; } - namespace development { extern const ServiceManifest manifest; } -#if defined(CONFIG_SOC_WIFI_SUPPORTED) || defined(CONFIG_ESP_HOSTED_ENABLED) - namespace espnow { extern const ServiceManifest manifest; } -#endif - // Secondary (UI) - namespace memorychecker { extern const ServiceManifest manifest; } - namespace statusbar { extern const ServiceManifest manifest; } -#ifdef ESP_PLATFORM - namespace displayidle { extern const ServiceManifest manifest; } - namespace keyboardidle { extern const ServiceManifest manifest; } - namespace rtctime { extern const ServiceManifest manifest; } -#endif -#if TT_FEATURE_SCREENSHOT_ENABLED - namespace screenshot { extern const ServiceManifest manifest; } -#endif - namespace webserver { extern const ServiceManifest manifest; } - -} - -// endregion - -// region Default apps - -// All apps below are converted to the new app-module + window-manager model, so their manifest -// is the new, global ::AppManifest, not this namespace's old tt::app::AppManifest. -namespace app { - namespace addgps { extern const ::AppManifest manifest; } - namespace alertdialog { extern const ::AppManifest manifest; } - namespace apphub { extern const ::AppManifest manifest; } - namespace apphubdetails { extern const ::AppManifest manifest; } - namespace apppackagedetails { extern const ::AppManifest manifest; } - namespace applist { extern const ::AppManifest manifest; } - namespace apppackagelist { extern const ::AppManifest manifest; } - namespace audiosettings { extern const ::AppManifest manifest; } - namespace boot { extern const ::AppManifest manifest; } - namespace development { extern const ::AppManifest manifest; } - namespace display { extern const ::AppManifest manifest; } - namespace files { extern const ::AppManifest manifest; } - namespace fileselection { extern const ::AppManifest manifest; } - namespace gpssettings { extern const ::AppManifest manifest; } - namespace grovesettings { extern const ::AppManifest manifest; } - namespace i2cscanner { extern const ::AppManifest manifest; } - namespace imageviewer { extern const ::AppManifest manifest; } - namespace inputdialog { extern const ::AppManifest manifest; } - namespace launcher { extern const ::AppManifest manifest; } - namespace ledstripsettings { extern const ::AppManifest manifest; } - namespace localesettings { extern const ::AppManifest manifest; } - namespace notes { extern const ::AppManifest manifest; } - namespace power { extern const ::AppManifest manifest; } - namespace poweroff { extern const ::AppManifest manifest; } - namespace selectiondialog { extern const ::AppManifest manifest; } - namespace settings { extern const ::AppManifest manifest; } - namespace setup { extern const ::AppManifest manifest; } - namespace shell { extern const ::AppManifest manifest; extern const ::AppManifest sh_manifest; } - namespace systeminfo { extern const ::AppManifest manifest; } - namespace terminal { extern const ::AppManifest manifest; } - namespace timedatesettings { extern const ::AppManifest manifest; } -#ifdef CONFIG_TT_TOUCH_CALIBRATION_SUPPORTED - namespace touchcalibration { extern const ::AppManifest manifest; } -#endif - namespace timezone { extern const ::AppManifest manifest; } - namespace usbsettings { extern const ::AppManifest manifest; } - namespace btmanage { extern const ::AppManifest manifest; } - namespace btpeersettings { extern const ::AppManifest manifest; } - namespace wifiapsettings { extern const ::AppManifest manifest; } - namespace wificonnect { extern const ::AppManifest manifest; } - namespace wifimanage { extern const ::AppManifest manifest; } - - namespace webserversettings { extern const ::AppManifest manifest; } -#ifdef ESP_PLATFORM - namespace apwebserver { extern const ::AppManifest manifest; } - namespace camera { extern const ::AppManifest manifest; } - namespace crashdiagnostics { extern const ::AppManifest manifest; } -#if CONFIG_TT_TDECK_WORKAROUND == 1 - namespace keyboardsettings { extern const ::AppManifest manifest; } // T-Deck only for now -#endif -#endif - - namespace trackballsettings { extern const ::AppManifest manifest; } // T-Deck only for now - -#if TT_FEATURE_SCREENSHOT_ENABLED - namespace screenshot { extern const ::AppManifest manifest; } -#endif - -#if defined(CONFIG_SOC_WIFI_SUPPORTED) || defined(CONFIG_ESP_HOSTED_ENABLED) - namespace chat { extern const ::AppManifest manifest; } -#endif -} - -// endregion - -// List of all apps excluding Boot app (as Boot app calls this function indirectly) -static void registerInternalApps() { - LOG_I(TAG, "Registering internal apps"); - - app_manager_add(&app::alertdialog::manifest); - app_manager_add(&app::apppackagedetails::manifest); - app_manager_add(&app::apphub::manifest); - app_manager_add(&app::apphubdetails::manifest); - app_manager_add(&app::applist::manifest); - app_manager_add(&app::apppackagelist::manifest); - if (service::audio::isAvailable()) { - app_manager_add(&app::audiosettings::manifest); - } - if (device_exists_of_type(&DISPLAY_TYPE)) { - app_manager_add(&app::display::manifest); - } - if (device_exists_of_type(&LED_STRIP_TYPE)) { - app_manager_add(&app::ledstripsettings::manifest); - } - app_manager_add(&app::files::manifest); - app_manager_add(&app::fileselection::manifest); - app_manager_add(&app::i2cscanner::manifest); - app_manager_add(&app::imageviewer::manifest); - app_manager_add(&app::inputdialog::manifest); - app_manager_add(&app::launcher::manifest); - app_manager_add(&app::localesettings::manifest); - app_manager_add(&app::notes::manifest); - if (device_exists_of_type(&POWER_SUPPLY_TYPE)) { - app_manager_add(&app::poweroff::manifest); - } - app_manager_add(&app::settings::manifest); - app_manager_add(&app::selectiondialog::manifest); - app_manager_add(&app::setup::manifest); - app_manager_add(&app::shell::manifest); - app_manager_add(&app::shell::sh_manifest); - app_manager_add(&app::systeminfo::manifest); - app_manager_add(&app::timedatesettings::manifest); - app_manager_add(&app::terminal::manifest); -#ifdef CONFIG_TT_TOUCH_CALIBRATION_SUPPORTED - app_manager_add(&app::touchcalibration::manifest); -#endif - app_manager_add(&app::timezone::manifest); - app_manager_add(&app::wifiapsettings::manifest); - app_manager_add(&app::wificonnect::manifest); - app_manager_add(&app::wifimanage::manifest); - - app_manager_add(&app::development::manifest); - app_manager_add(&app::webserversettings::manifest); -#ifdef ESP_PLATFORM - app_manager_add(&app::apwebserver::manifest); - if (device_exists_of_type(&CAMERA_TYPE)) { - app_manager_add(&app::camera::manifest); - } - app_manager_add(&app::crashdiagnostics::manifest); -#if defined(CONFIG_TT_TDECK_WORKAROUND) - app_manager_add(&app::keyboardsettings::manifest); -#endif -#endif - - if (device_exists_of_type(&TRACKBALL_TYPE)) { - app_manager_add(&app::trackballsettings::manifest); - } - -#if defined(CONFIG_TINYUSB_MSC_ENABLED) && CONFIG_TINYUSB_MSC_ENABLED - app_manager_add(&app::usbsettings::manifest); -#endif - -#if TT_FEATURE_SCREENSHOT_ENABLED - app_manager_add(&app::screenshot::manifest); -#endif - -#if defined(CONFIG_SOC_WIFI_SUPPORTED) || defined(CONFIG_ESP_HOSTED_ENABLED) - app_manager_add(&app::chat::manifest); -#endif - - if (device_exists_of_type(&GROVE_TYPE)) { - app_manager_add(&app::grovesettings::manifest); - } - - if (device_exists_of_type(&UART_CONTROLLER_TYPE) || device_exists_of_type(&GROVE_TYPE)) { - app_manager_add(&app::addgps::manifest); - app_manager_add(&app::gpssettings::manifest); - } - - if (device_exists_of_type(&POWER_SUPPLY_TYPE)) { - app_manager_add(&app::power::manifest); - } - -#if defined(CONFIG_BT_ENABLED) && CONFIG_BT_ENABLED - app_manager_add(&app::btmanage::manifest); - app_manager_add(&app::btpeersettings::manifest); -#endif -} - -// Registers every mounted filesystem's app install directory with app-module (see -// app_manager_install_path_add()/app_manager_install_path_scan() in app/install.h), then scans -// them once to register whatever's already installed there. -static void registerInstalledAppsFromFileSystems() { - file_system_for_each(nullptr, [](auto* fs, void* context) { - if (!file_system_is_mounted(fs)) return true; - char path[128]; - if (file_system_get_path(fs, path, sizeof(path)) != ERROR_NONE) return true; - const auto app_path = std::format("{}/tactility/app", path); - if (!app_path.starts_with(file::MOUNT_POINT_SYSTEM) && file::isDirectory(app_path)) { - LOG_I(TAG, "Registering install path %s", app_path.c_str()); - app_manager_install_path_add(app_path.c_str()); - } - return true; - }); - app_manager_install_path_scan(); -} - -static void registerAndStartServices() { - LOG_I(TAG, "Registering and starting primary system services"); - if (device_exists_of_type(&AUDIO_STREAM_TYPE)) { - addService(service::audio::manifest); - } - check(module_ensure_started(&wifi_module) == ERROR_NONE); - addService(service::development::manifest); - addService(service::webserver::manifest); - -#if defined(CONFIG_SOC_WIFI_SUPPORTED) || defined(CONFIG_ESP_HOSTED_ENABLED) - addService(service::espnow::manifest); -#endif -#if defined(ESP_PLATFORM) - if (device_exists_of_type(&RTC_TYPE)) { - addService(service::rtctime::manifest); - } -#endif -} - -void prepareFileSystems() { - char temp_path[FILE_MAX_PATH_STRING_LENGTH]; - if (paths_get_temp_path(temp_path, sizeof(temp_path)) != ERROR_NONE) { - LOG_E(TAG, "Failed to determine temp path"); - return; - } - if (!file::findOrCreateDirectory(temp_path, 0777)) { - LOG_E(TAG, "Failed to create %s", temp_path); - } -} - -void registerApps() { - registerInternalApps(); - registerInstalledAppsFromFileSystems(); -} - -static void stopAppFromToolbar(lv_event_t*) { - // Default nav action for any toolbar that doesn't override it itself. Prefer the topmost - // new-model app if one is showing; fall back to the old system otherwise (this is what - // every not-yet-converted app's toolbar still relies on). - AppInstanceId topmost = 0; - check(app_manager_get_topmost_instance_id(&topmost) == ERROR_NONE); - - app_event_emit_close(topmost); -} - -// The on-screen keyboard widget itself, constructed during windowManagerScreenInit -static LvglSoftwareKeyboard softwareKeyboard { .object = nullptr }; - -static lv_obj_t* windowManagerScreenInit(lv_obj_t* root) { - lv_obj_t* vertical_container = lv_obj_create(root); - lv_obj_set_size(vertical_container, LV_PCT(100), LV_PCT(100)); - lv_obj_set_flex_flow(vertical_container, LV_FLEX_FLOW_COLUMN); - lv_obj_set_style_pad_all(vertical_container, 0, LV_STATE_DEFAULT); - lv_obj_set_style_pad_gap(vertical_container, 0, LV_STATE_DEFAULT); - lv_obj_set_style_bg_color(vertical_container, lv_color_black(), LV_STATE_DEFAULT); - lv_obj_set_style_border_width(vertical_container, 0, LV_STATE_DEFAULT); - lv_obj_set_style_radius(vertical_container, 0, LV_STATE_DEFAULT); - lv_obj_remove_flag(vertical_container, LV_OBJ_FLAG_SCROLLABLE); - - lvgl::statusbar_create(vertical_container); - - auto* app_container = lv_obj_create(vertical_container); - lv_obj_set_style_pad_all(app_container, 0, LV_STATE_DEFAULT); - lv_obj_set_style_border_width(app_container, 0, LV_STATE_DEFAULT); - lv_obj_set_width(app_container, LV_PCT(100)); - lv_obj_set_flex_grow(app_container, 1); - lv_obj_set_flex_flow(app_container, LV_FLEX_FLOW_COLUMN); - lv_obj_remove_flag(app_container, LV_OBJ_FLAG_SCROLLABLE); - - // Parented to root (not app_container/vertical_container) so it overlays on top of - // everything, including the statusbar, regardless of which app is showing. Hidden until a - // focused textarea shows it (see lvgl_keyboard_add_textarea()/textarea_show_keyboard()). - lvgl_software_keyboard_construct(&softwareKeyboard, root); - - return app_container; -} - -#ifdef CONFIG_TT_TOUCH_CALIBRATION_SUPPORTED - -// Applies the calibration persisted by the touch calibration app to the live pointer indev. -// lvgl_devices_attach() runs before onLvglStarted(), so the default indev already exists here. -static void applySavedTouchCalibration() { - settings::touch::TouchCalibrationSettings settings = settings::touch::loadOrGetDefault(); - if (!settings.enabled || !settings::touch::isValid(settings)) { - return; - } - - LvglPointerCalibration calibration = { - .x_min = settings.xMin, - .x_max = settings.xMax, - .y_min = settings.yMin, - .y_max = settings.yMax, - }; - - lvgl_lock(); - auto* indev = lvgl_pointer_get_default(); - if (indev != nullptr) { - lvgl_pointer_set_calibration(indev, &calibration); - } - lvgl_unlock(); -} - -#endif // CONFIG_TT_TOUCH_CALIBRATION_SUPPORTED - -static void onLvglStarted() { - // lv_display_create() (inside lvgl_devices_attach(), which already ran by this point) always - // resets rotation to LV_DISPLAY_ROTATION_0. The only other code that ever applies a saved - // orientation is the display settings app's dropdown change handler, so without this, every - // LVGL restart (not just first boot) silently drops back to unrotated. Must run before - // window_manager_start() below builds the window tree against the display's current size. - lvgl_lock(); - if (auto* display = lv_display_get_default(); display != nullptr) { - auto displaySettings = settings::display::loadOrGetDefault(); - lv_display_set_rotation(display, settings::display::toLvglDisplayRotation(displaySettings.orientation)); - } - lvgl_unlock(); - - window_manager_configure(windowManagerScreenInit); - check(module_ensure_started(&lvgl_window_manager_module) == ERROR_NONE); - - ToolbarConfig toolbar_config = { .nav_action_callback = stopAppFromToolbar }; - lvgl_toolbar_configure(&toolbar_config); - - addService(service::statusbar::manifest); - addService(service::memorychecker::manifest); -#if defined(ESP_PLATFORM) - addService(service::displayidle::manifest); -#endif - if (device_exists_of_type(&IMU_TYPE)) { - addService(service::autorotate::manifest); - } -#if defined(CONFIG_TT_TDECK_WORKAROUND) - addService(service::keyboardidle::manifest); -#endif -#if TT_FEATURE_SCREENSHOT_ENABLED - addService(service::screenshot::manifest); -#endif - - lvgl::startUsbHidInput(); - lvgl::startKeyboardDeviceListener(); - lvgl::initTrackball(); - -#ifdef CONFIG_TT_TOUCH_CALIBRATION_SUPPORTED - applySavedTouchCalibration(); -#endif - - memory_log_stats(); -} - -static void onLvglStopped() { - lvgl::stopKeyboardDeviceListener(); - lvgl::stopUsbHidInput(); - - if (device_exists_of_type(&IMU_TYPE)) { - check(service::removeService(service::autorotate::manifest.id)); - } -#if TT_FEATURE_SCREENSHOT_ENABLED - check(service::removeService(service::screenshot::manifest.id)); -#endif -#if defined(CONFIG_TT_TDECK_WORKAROUND) - check(service::removeService(service::keyboardidle::manifest.id)); -#endif -#if defined(ESP_PLATFORM) - check(service::removeService(service::displayidle::manifest.id)); -#endif - check(service::removeService(service::memorychecker::manifest.id)); - check(service::removeService(service::statusbar::manifest.id)); - - if (softwareKeyboard.object != nullptr) { - // lv_obj_delete() walks/mutates the object graph (event lists, group membership, - // parent/child links). Without the LVGL lock this can race the LVGL port task's own - // concurrent traversal (input dispatch, timers, animations), producing an intermittent - // double-free/use-after-free inside lv_obj_destructor/lv_event_mark_deleted. - lvgl_lock(); - lvgl_software_keyboard_destruct(&softwareKeyboard); - lvgl_unlock(); - } - - module_stop(&lvgl_window_manager_module); - - memory_log_stats(); -} - -void run(Module* const dtsModules[], const DtsDevice dtsDevices[]) { - LOG_I(TAG, "Tactility v%s on %s (%s)", TT_VERSION, CONFIG_TT_DEVICE_NAME, CONFIG_TT_DEVICE_ID); - - LOG_I(TAG, "Initializing kernel"); - if (kernel_init(dtsModules, dtsDevices) != ERROR_NONE) { - LOG_E(TAG, "Failed to initialize kernel"); - return; - } - - // The following groups of symbols are sorted by the estimated chance of them occurring - - // C/C++/Posix symbols - check(module_ensure_started(&c_symbols_module) == ERROR_NONE); - check(module_ensure_started(&cjson_module) == ERROR_NONE); -#if TT_IS_POSIX or defined(ESP_PLATFORM) // esp-idf supports certain posix symbols - check(module_ensure_started(&posix_symbols_module) == ERROR_NONE); -#endif - check(module_ensure_started(&cpp_symbols_module) == ERROR_NONE); - // OS level symbols - check(module_ensure_started(&freertos_module) == ERROR_NONE); - check(module_ensure_started(&pthread_module) == ERROR_NONE); - // Other libraries - check(module_ensure_started(&http_module) == ERROR_NONE); - check(module_ensure_started(&graphics_module) == ERROR_NONE); - check(module_ensure_started(&binfont_module) == ERROR_NONE); - check(module_ensure_started(&app_module) == ERROR_NONE); - check(module_ensure_started(&coreutils_module) == ERROR_NONE); - check(module_ensure_started(&crypt_module) == ERROR_NONE); - check(module_ensure_started(&audio_decoder_module) == ERROR_NONE); - check(module_ensure_started(&mbedtls_module) == ERROR_NONE); - check(module_ensure_started(&gps_module) == ERROR_NONE); - check(module_ensure_started(&gps_generic_module) == ERROR_NONE); - check(module_ensure_started(&gps_meshtastic_module) == ERROR_NONE); -#ifdef ESP_PLATFORM - check(module_ensure_started(&app_esp32_module) == ERROR_NONE); -#elif TT_IS_POSIX - check(module_ensure_started(&app_posix_module) == ERROR_NONE); -#endif - check(module_ensure_started(&tactility_audio_module) == ERROR_NONE); - -#ifdef ESP_PLATFORM - initEsp(); -#endif - - settings::initTimeZone(); - - // Attempt to start all disabled SD cards (some require delayed init) - hal::sdcard::startAll(); - - network::ntp::init(); - bluetooth::systemStart(); - - registerAndStartServices(); - - lvgl::initIconFonts(); - - lvgl_module_configure((LvglModuleConfig) { - .on_start = onLvglStarted, - .on_stop = onLvglStopped, - .task_priority = THREAD_PRIORITY_HIGHER, - .task_stack_size = 9120, -#ifdef ESP_PLATFORM - .task_affinity = getCpuAffinityConfiguration().graphics -#endif - }); - check(module_ensure_started(&lvgl_module) == ERROR_NONE); - - LOG_I(TAG, "Core systems ready"); - - LOG_I(TAG, "Starting boot app"); - // The boot app takes care of registering system apps, user services and user apps. - // It's a new-model (app-module + window-manager) app now, replacing the old app::start(). - app_manager_add(&app::boot::manifest); - uint32_t boot_instance_id = 0; - AppStartContext boot_context = app_start_context_for_manifest(&app::boot::manifest); - app_start_with_context(&boot_context, &boot_instance_id); - - LOG_I(TAG, "Main dispatcher ready"); - while (true) { - dispatcher_consume(mainDispatcherHandle); - } -} - -MainDispatcher getMainDispatcher() { - return MainDispatcher(mainDispatcherHandle); -} - -} // namespace diff --git a/Tactility/Source/app/boot/Boot.cpp b/Tactility/Source/app/boot/Boot.cpp index 6e8fa1986..0cc7f56cf 100644 --- a/Tactility/Source/app/boot/Boot.cpp +++ b/Tactility/Source/app/boot/Boot.cpp @@ -1,381 +1,35 @@ -#include "Tactility/app/alertdialog/AlertDialog.h" -#include "tactility/memory.h" -#include "tactility/system_event.h" +#include #include -#include -#include -#include -#include +#include #include #include -#include #include #include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#ifdef ESP_PLATFORM -#include -#include -#include -#include -#else -#define CONFIG_TT_SPLASH_DURATION 0 -#endif namespace tt::app::boot { -constexpr auto* TAG = "Boot"; - extern const ::AppManifest manifest; namespace { -// Snapshot of hal::usb::isUsbBootMode(), taken before boot work starts and potentially clears -// the underlying flag via setupUsbBootMode()/resetUsbBootMode(). createSplashWidgets() reads -// this instead of the live flag to avoid a race between the two. -std::atomic isUsbBootSplash = false; - -// Set when CONFIG_TT_USER_DATA_LOCATION_SD is defined but no SD card is mounted. Switches the -// window to an error screen and halts before starting the next app. -std::atomic sdCardMissing = false; - -// Set when setupUsbBootMode() fails -std::atomic usbBootModeFailed = false; -std::string usbBootModeFailedReason; - -uint32_t bootAppInstanceId = 0; -WindowId bootWindowId = 0; - -#ifdef ESP_PLATFORM -constexpr auto PARTITION_PREFIX = std::string("/"); -#else -constexpr auto PARTITION_PREFIX = std::string(""); -#endif - -// Equivalent of AppPaths::getAssetsPath() for the internal "Boot" app id, without needing a -// live AppContext (which this app no longer has under the new app-module model). -std::string getBootAssetsPath(const std::string& childPath) { - return std::format("{}{}/app/Boot/assets/{}", PARTITION_PREFIX, file::SYSTEM_PARTITION_NAME, childPath); -} - -void setupDisplay() { - // TODO: Support for multiple displays - - Device* display = nullptr; - if (device_get_first_by_type(&DISPLAY_TYPE, &display) != ERROR_NONE) { - LOG_I(TAG, "No kernel display"); - return; - } - - // Set backlight brightness - Device* backlight; - if (display_get_backlight(display, &backlight) == ERROR_NONE) { - if (!device_is_ready(backlight)) { - if (device_start(backlight) != ERROR_NONE) { - LOG_E(TAG, "Failed to start %s", backlight->name); - } - } - - settings::display::DisplaySettings settings; - if (settings::display::load(settings)) { - } else { - settings = settings::display::getDefault(); - } - - if (backlight_set_brightness(backlight, settings.backlightDuty) == ERROR_NONE) { - LOG_I(TAG, "Backlight for %s set to %d", display->name, settings.backlightDuty); - } else { - LOG_E(TAG, "Failed to set brightness of %s", backlight->name); - } - device_put(backlight); - } else { - LOG_I(TAG, "No backlight for %s", display->name); - } - - device_put(display); -} - -// Returns true if either the MSC screen or the failure screen now owns the display, in which -// case the caller must not proceed to the normal boot path (registerApps()/startNextApp()). -bool setupUsbBootMode() { - if (!hal::usb::isUsbBootMode()) { - return false; - } - - LOG_I(TAG, "Rebooting into mass storage device mode"); - auto mode = hal::usb::getUsbBootMode(); // Get mode before reset - hal::usb::resetUsbBootMode(); - delay_millis(3000); - - bool started = false; - if (mode == hal::usb::BootMode::Flash) { - started = hal::usb::startMassStorageWithFlash(true); - } else if (mode == hal::usb::BootMode::Sdmmc) { - started = hal::usb::startMassStorageWithSdmmc(true); - } - - if (!started) { - usbBootModeFailedReason = hal::usb::getLastError(); - usbBootModeFailed = true; - } - - return true; -} - -void waitForMinimalSplashDuration(TickType_t startTime) { - const auto end_time = get_ticks(); - const auto ticks_passed = end_time - startTime; - constexpr auto minimum_ticks = (CONFIG_TT_SPLASH_DURATION / portTICK_PERIOD_MS); - if (minimum_ticks > ticks_passed) { - delay_ticks(minimum_ticks - ticks_passed); - } -} - -std::string getLauncherAppId() { - settings::BootSettings boot_properties; - // When boot.properties hasn't been overridden, return default - if (!settings::loadBootSettings(boot_properties)) { - return CONFIG_TT_LAUNCHER_APP_ID; - } - - // When boot properties didn't specify an override, return default - if (boot_properties.launcherAppId.empty()) { - LOG_E(TAG, "Failed to load launcher configuration, or launcher not configured"); - return CONFIG_TT_LAUNCHER_APP_ID; - } - - // If the app in the boot.properties does not exist, return default - AppManifest manifest; - if (app_manager_find_manifest(boot_properties.launcherAppId.c_str(), &manifest) != ERROR_NONE) { - LOG_E(TAG, "Launcher app %s not found", boot_properties.launcherAppId.c_str()); - return CONFIG_TT_LAUNCHER_APP_ID; - } - - // The boot.properties launcher app id is valid - return boot_properties.launcherAppId; -} - -int getSmallestDimension() { - auto* display = lv_display_get_default(); - int width = lv_display_get_horizontal_resolution(display); - int height = lv_display_get_vertical_resolution(display); - return std::min(width, height); -} - -void createSplashWidgets(lv_obj_t* root, void*) { - lvgl::obj_set_style_bg_blacken(root); - lv_obj_set_style_border_width(root, 0, LV_STATE_DEFAULT); - lv_obj_set_style_radius(root, 0, LV_STATE_DEFAULT); - - auto* image = lv_image_create(root); - lv_obj_set_size(image, LV_SIZE_CONTENT, LV_SIZE_CONTENT); - lv_obj_align(image, LV_ALIGN_CENTER, 0, 0); - - const char* logo; - // TODO: Replace with automatic asset buckets like on Android - if (getSmallestDimension() < 150) { // e.g. Cardputer - logo = isUsbBootSplash ? "logo_usb.png" : "logo_small.png"; - } else { - logo = isUsbBootSplash ? "logo_usb.png" : "logo.png"; - } - const auto logo_path = lvgl::PATH_PREFIX + getBootAssetsPath(logo); - LOG_I(TAG, "%s", logo_path.c_str()); - lv_image_set_src(image, logo_path.c_str()); - -#ifdef ESP_PLATFORM - if (isUsbBootSplash) { - auto* button = lv_button_create(root); - lv_obj_align(button, LV_ALIGN_BOTTOM_MID, 0, -16); - auto* label = lv_label_create(button); - lv_label_set_text(label, "Return to OS"); - lv_obj_add_event_cb(button, [](lv_event_t*) { - hal::usb::stop(); - esp_restart(); - }, LV_EVENT_SHORT_CLICKED, nullptr); - } -#endif -} - -void selectIfNoPointer(lv_obj_t* button) { - if (!lvgl_indev_exists(LV_INDEV_TYPE_POINTER)) { - lv_group_focus_obj(button); - lv_obj_add_state(button, LV_STATE_FOCUS_KEY); - } -} - -void createSdCardMissingWidgets(lv_obj_t* root, void*) { - lvgl::obj_set_style_bg_blacken(root); - lv_obj_set_style_border_width(root, 0, LV_STATE_DEFAULT); - lv_obj_set_style_radius(root, 0, LV_STATE_DEFAULT); - lv_obj_set_flex_flow(root, LV_FLEX_FLOW_COLUMN); - lv_obj_set_flex_align(root, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER); - - auto* label = lv_label_create(root); - lv_label_set_text(label, "SD card not found.\nPlease insert one and reboot."); - lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, LV_STATE_DEFAULT); - lv_obj_set_style_text_color(label, lv_color_white(), LV_STATE_DEFAULT); - - auto* button = lv_button_create(root); - lv_obj_set_style_margin_top(button, 16, LV_STATE_DEFAULT); - auto* button_label = lv_label_create(button); - lv_label_set_text(button_label, "Reboot"); - lv_obj_add_event_cb(button, [](lv_event_t*) { -#ifdef ESP_PLATFORM - esp_restart(); -#endif - }, LV_EVENT_SHORT_CLICKED, nullptr); - selectIfNoPointer(button); -} - -// Replaces the splash with a self-contained error screen (no dependency on the old alertdialog -// app - this app has no parent in the old App stack to deliver a result back to). -void showSdCardMissingScreen() { - if (bootWindowId != 0) { - window_manager_remove(bootWindowId); - } - bootWindowId = window_manager_create(bootAppInstanceId, createSdCardMissingWidgets, nullptr); -} - -void createUsbBootModeFailedWidgets(lv_obj_t* root, void*) { - lvgl::obj_set_style_bg_blacken(root); - lv_obj_set_style_border_width(root, 0, LV_STATE_DEFAULT); - lv_obj_set_style_radius(root, 0, LV_STATE_DEFAULT); - lv_obj_set_flex_flow(root, LV_FLEX_FLOW_COLUMN); - lv_obj_set_flex_align(root, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER); - - auto* label = lv_label_create(root); - lv_label_set_text(label, std::format("Failed to start USB mass storage:\n{}", usbBootModeFailedReason).c_str()); - lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, LV_STATE_DEFAULT); - lv_obj_set_style_text_color(label, lv_color_white(), LV_STATE_DEFAULT); - - auto* button = lv_button_create(root); - lv_obj_set_style_margin_top(button, 16, LV_STATE_DEFAULT); - auto* button_label = lv_label_create(button); - lv_label_set_text(button_label, "Reboot"); - lv_obj_add_event_cb(button, [](lv_event_t*) { -#ifdef ESP_PLATFORM - esp_restart(); -#endif - }, LV_EVENT_SHORT_CLICKED, nullptr); - selectIfNoPointer(button); -} - -void showUsbBootModeFailedScreen() { - if (bootWindowId != 0) { - window_manager_remove(bootWindowId); - } - bootWindowId = window_manager_create(bootAppInstanceId, createUsbBootModeFailedWidgets, nullptr); -} - -void startNextApp() { - if (sdCardMissing) { - showSdCardMissingScreen(); - return; - } - -#ifdef ESP_PLATFORM - if (esp_reset_reason() == ESP_RST_PANIC) { - crashdiagnostics::start(); // fire-and-forget; no result expected back - return; - } -#endif - - auto launcher_app_id = getLauncherAppId(); - uint32_t launcher_instance_id = 0; - AppStartContext context; - if (app_start_context_from_id(launcher_app_id.c_str(), &context) == ERROR_NONE) { - app_start_with_context(&context, &launcher_instance_id); - } -} - -void runBootSequence(TickType_t startTime) { - LOG_I(TAG, "Starting boot sequence"); - - // Give the UI some time to redraw - // If we don't do this, various init calls will read files and block SPI IO for the display - // This would result in a blank/black screen being shown during this phase of the boot process - // This works with 5 ms on a T-Lora Pager, so we give it 10 ms to be safe - delay_millis(10); - - LOG_I(TAG, "Setup display"); - setupDisplay(); - LOG_I(TAG, "Prepare file systems"); - prepareFileSystems(); - -#ifdef CONFIG_TT_USER_DATA_LOCATION_SD - std::string sd_path; - if (!findFirstMountedSdCardPath(sd_path)) { - LOG_E(TAG, "SD card not found"); - sdCardMissing = true; - } -#endif - - if (setupUsbBootMode()) { - if (usbBootModeFailed) { - showUsbBootModeFailedScreen(); - } - // Stay open: the splash's "Return to OS" button or the failure screen's "Reboot" button. - return; - } - - registerApps(); - waitForMinimalSplashDuration(startTime); - startNextApp(); - - if (sdCardMissing) { - // Stay open: the error screen's "Reboot" button is this app's only way to leave here. - return; - } - - // This event will likely block as other systems are initialized - // e.g. Wi-Fi reads AP configs from SD card - LOG_I(TAG, "Publish event"); - system_event_emit(KERNEL_EVENT_BOOT_COMPLETED, nullptr, 0); - - app_event_emit_close(app_scheduler_current_app_id()); -} - int32_t appMain(int argc, char* argv[]) { - uint32_t appInstanceId = app_scheduler_current_app_id(); - bootAppInstanceId = appInstanceId; const auto start_time = get_ticks(); - // Snapshot before runBootSequence() potentially clears the flag via setupUsbBootMode() - isUsbBootSplash = hal::usb::isUsbBootMode(); - sdCardMissing = false; - TaskEventGroup event_group {}; task_event_group_construct(&event_group); AppEventSubscription sub {}; check(app_event_subscribe(&sub, &event_group) == ERROR_NONE); - bootWindowId = window_manager_create(appInstanceId, createSplashWidgets, nullptr); - - runBootSequence(start_time); + if (runBootSequence(start_time)) { + app_event_emit_close(app_scheduler_current_app_id()); + } // Waits until app_start(launcher) (or a permanent stop) tells us to give up - // startNextApp() above is what triggers that, via app-module's "save the previously active - // app" policy, unless sdCardMissing halted before it. + // app" policy. When the boot halted on an error screen, this waits forever. while (true) { task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY); @@ -390,9 +44,6 @@ int32_t appMain(int argc, char* argv[]) { if (shouldClose) break; } - if (bootWindowId != 0) { - window_manager_remove(bootWindowId); - } check(app_event_unsubscribe(&sub) == ERROR_NONE); task_event_group_destruct(&event_group); @@ -407,7 +58,7 @@ extern const ::AppManifest manifest = { .category = APP_CATEGORY_SYSTEM, .location = { .type = APP_LOCATION_MEMORY, .location = reinterpret_cast(appMain) }, .flags = APP_MANIFEST_FLAG_HIDDEN, - .stack = { .depth = 4096, .desired_memory_capability = MEMORY_CAPABILITY_INTERNAL } + .stack = { .depth = 6144, .desired_memory_capability = MEMORY_CAPABILITY_INTERNAL } }; } // namespace diff --git a/Tactility/Source/app/boot/BootScreen.cpp b/Tactility/Source/app/boot/BootScreen.cpp new file mode 100644 index 000000000..b7ef775bb --- /dev/null +++ b/Tactility/Source/app/boot/BootScreen.cpp @@ -0,0 +1,303 @@ +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace tt::app::boot { + +constexpr auto* TAG = "BootScreen"; +constexpr int BAND_HEIGHT = 16; +constexpr uint16_t TEXT_COLOR = 0xFFFF; + +namespace { + +struct Logo { + unsigned char* rgba = nullptr; + unsigned width = 0; + unsigned height = 0; + + ~Logo() { lodepng_free(rgba); } +}; + +/** Splits text into lines of at most maxCharacters, breaking at spaces where possible */ +void wrapLine(const std::string& text, size_t maxCharacters, std::vector& output) { + size_t start = 0; + while (text.size() - start > maxCharacters) { + size_t end = text.rfind(' ', start + maxCharacters); + if (end == std::string::npos || end <= start) { + end = start + maxCharacters; + output.push_back(text.substr(start, end - start)); + start = end; + } else { + output.push_back(text.substr(start, end - start)); + start = end + 1; + } + } + output.push_back(text.substr(start)); +} + +uint16_t toRgb565(uint32_t red, uint32_t green, uint32_t blue) { + return static_cast(((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3)); +} + +bool collectReadyDevice(Device* device, void* context) { + if (device_is_ready(device) && device_get(device) == ERROR_NONE) { + static_cast*>(context)->push_back(device); + } + return true; +} + +std::vector getReadyKeyboards() { + std::vector keyboards; + device_for_each_of_type(&KEYBOARD_TYPE, &keyboards, collectReadyDevice); + return keyboards; +} + +} // namespace + +BootScreen::~BootScreen() { + end(); +} + +bool BootScreen::begin() { + if (device_get_first_by_type(&DISPLAY_TYPE, &display) != ERROR_NONE) { + LOG_I(TAG, "No display"); + display = nullptr; + return false; + } + + panelWidth = display_get_resolution_x(display); + panelHeight = display_get_resolution_y(display); + const auto orientation = settings::display::loadOrGetDefault().orientation; + rotation = static_cast(settings::display::toLvglDisplayRotation(orientation)); + + const auto color_format = display_get_color_format(display); + if (display_get_frame_buffer_count(display) > 0) { + // Drawing into the hardware frame buffer avoids a copy, and a partial update to a + // double-buffered panel would flip to a half-drawn frame + void* frame_buffers[2] = { nullptr, nullptr }; + display_get_frame_buffer(display, 0, &frame_buffers[0]); + if (display_get_frame_buffer_count(display) > 1) { + display_get_frame_buffer(display, 1, &frame_buffers[1]); + } + if (frame_buffers[0] != nullptr) { + target = pixel_buffer_wrap(frame_buffers[0], color_format, panelWidth, panelHeight, 0); + } + if (target != nullptr && frame_buffers[1] != nullptr) { + secondFrameBuffer = pixel_buffer_wrap(frame_buffers[1], color_format, panelWidth, panelHeight, 0); + } + bandHeight = panelHeight; + } + + if (target == nullptr) { + const bool full_frame = color_format == DISPLAY_COLOR_FORMAT_MONOCHROME || display_has_capability(display, DISPLAY_CAPABILITY_REQUIRES_FULL_FRAME); + bandHeight = full_frame ? panelHeight : std::min(BAND_HEIGHT, panelHeight); + target = pixel_buffer_create(color_format, panelWidth, bandHeight); + } + + if (target == nullptr) { + LOG_E(TAG, "Failed to allocate buffer"); + end(); + return false; + } + + return true; +} + +void BootScreen::end() { + pixel_buffer_free(target); + pixel_buffer_free(secondFrameBuffer); + target = nullptr; + secondFrameBuffer = nullptr; + if (display != nullptr) { + device_put(display); + display = nullptr; + } +} + +int BootScreen::getSmallestDimension() const { + return std::min(panelWidth, panelHeight); +} + +void BootScreen::show(const std::string& logoPath, const std::vector& lines) { + if (target == nullptr) { + return; + } + + Logo logo; + if (!logoPath.empty()) { + const unsigned error = lodepng_decode32_file(&logo.rgba, &logo.width, &logo.height, logoPath.c_str()); + if (error != 0) { + LOG_E(TAG, "Failed to load %s: %s", logoPath.c_str(), lodepng_error_text(error)); + lodepng_free(logo.rgba); + logo.rgba = nullptr; + logo.width = 0; + logo.height = 0; + } + } + + // Layout in logical (rotated) coordinates: logo with text below it, centered as a whole + const auto& font = TT_TERMINAL_FONT_SYMBOL; + const int logical_width = logicalWidth(); + const int logical_height = logicalHeight(); + const size_t max_characters = std::max(1, logical_width / font.glyph_width - 2); + std::vector wrapped_lines; + for (const auto& line : lines) { + wrapLine(line, max_characters, wrapped_lines); + } + const int text_height = static_cast(wrapped_lines.size()) * font.glyph_height; + const int gap = (logo.height > 0 && !wrapped_lines.empty()) ? font.glyph_height : 0; + const int content_top = (logical_height - static_cast(logo.height) - gap - text_height) / 2; + const int logo_left = (logical_width - static_cast(logo.width)) / 2; + const int text_top = content_top + static_cast(logo.height) + gap; + + for (int band_top = 0; band_top < panelHeight; band_top += bandHeight) { + const int band_rows = std::min(bandHeight, panelHeight - band_top); + pixel_buffer_clear(target); + + // Maps logical coordinates to the physical panel, like lv_display_rotate_area() + auto plot = [&](int x, int y, uint16_t color, PixelBufferConversion conversion) { + int physical_x; + int physical_y; + switch (rotation) { + case 1: physical_x = y; physical_y = panelHeight - 1 - x; break; + case 2: physical_x = panelWidth - 1 - x; physical_y = panelHeight - 1 - y; break; + case 3: physical_x = panelWidth - 1 - y; physical_y = x; break; + default: physical_x = x; physical_y = y; break; + } + if (physical_y >= band_top && physical_y < band_top + band_rows) { + pixel_buffer_set_pixel_rgb565(target, physical_x, physical_y - band_top, color, conversion); + } + }; + + for (unsigned y = 0; y < logo.height; y++) { + for (unsigned x = 0; x < logo.width; x++) { + const unsigned char* pixel = logo.rgba + (static_cast(y) * logo.width + x) * 4; + const uint32_t alpha = pixel[3]; + if (alpha != 0) { + // Blended onto the black background + const uint16_t color = toRgb565(pixel[0] * alpha / 255, pixel[1] * alpha / 255, pixel[2] * alpha / 255); + plot(logo_left + static_cast(x), content_top + static_cast(y), color, PIXEL_BUFFER_CONVERSION_LUMA_THRESHOLD); + } + } + } + + for (size_t line_index = 0; line_index < wrapped_lines.size(); line_index++) { + const auto& line = wrapped_lines[line_index]; + const int line_left = (logical_width - static_cast(line.size()) * font.glyph_width) / 2; + const int line_top = text_top + static_cast(line_index) * font.glyph_height; + for (size_t character_index = 0; character_index < line.size(); character_index++) { + const auto character = static_cast(line[character_index]); + if (character < font.first_codepoint || character > font.last_codepoint) { + continue; + } + const uint8_t* glyph = &font.glyph_bitmap[(character - font.first_codepoint) * font.glyph_height * font.glyph_bytes_per_row]; + const int glyph_left = line_left + static_cast(character_index) * font.glyph_width; + for (int row = 0; row < font.glyph_height; row++) { + const uint8_t* bits = &glyph[row * font.glyph_bytes_per_row]; + for (int column = 0; column < font.glyph_width; column++) { + if (bits[column / 8] & (0x80U >> (column % 8))) { + plot(glyph_left + column, line_top + row, TEXT_COLOR, PIXEL_BUFFER_CONVERSION_EXACT_BLACK); + } + } + } + } + } + + pixel_buffer_msync(target, 0, 0, panelWidth, band_rows); + display_draw_bitmap(display, 0, band_top, panelWidth, band_top + band_rows, pixel_buffer_get_data(target)); + } + + if (secondFrameBuffer != nullptr) { + pixel_buffer_blit(secondFrameBuffer, 0, 0, target, 0, 0, panelWidth, panelHeight, PIXEL_BUFFER_CONVERSION_EXACT_BLACK); + pixel_buffer_msync(secondFrameBuffer, 0, 0, panelWidth, panelHeight); + } +} + +std::string getInputPrompt(const std::string& action) { + auto keyboards = getReadyKeyboards(); + const bool has_keyboard = !keyboards.empty(); + for (auto* keyboard : keyboards) { + device_put(keyboard); + } + if (has_keyboard) { + return "Press any key to " + action; + } + + Device* pointer = nullptr; + if (device_get_first_active_by_type(&POINTER_TYPE, &pointer) == ERROR_NONE) { + device_put(pointer); + return "Touch the screen to " + action; + } + + return ""; +} + +void waitForInput() { + auto keyboards = getReadyKeyboards(); + // Subscriptions must stay at the same address while subscribed + auto subscriptions = std::make_unique(keyboards.size()); + for (size_t i = 0; i < keyboards.size(); i++) { + keyboard_subscribe(keyboards[i], &subscriptions[i]); + } + + Device* pointer = nullptr; + if (device_get_first_active_by_type(&POINTER_TYPE, &pointer) != ERROR_NONE) { + pointer = nullptr; + } + + // A touch only counts when it starts after the screen was seen untouched + bool pointer_released = false; + bool done = false; + while (!done) { + for (size_t i = 0; i < keyboards.size() && !done; i++) { + // Drivers that implement read_key only deliver events to subscribers when polled + KeyboardKeyData data; + while (keyboard_read_key(keyboards[i], &data) == ERROR_NONE && data.key != 0 && data.continue_reading) {} + + while (keyboard_poll(keyboards[i], &subscriptions[i], &data) == ERROR_NONE) { + if (data.pressed) { + done = true; + } + } + } + + if (pointer != nullptr && !done && pointer_read_data(pointer, 0) == ERROR_NONE) { + uint16_t x, y, strength; + uint8_t point_count = 0; + const bool touched = pointer_get_touched_points(pointer, &x, &y, &strength, &point_count, 1) && point_count > 0; + if (!touched) { + pointer_released = true; + } else if (pointer_released) { + done = true; + } + } + + if (!done) { + delay_millis(20); + } + } + + for (size_t i = 0; i < keyboards.size(); i++) { + keyboard_unsubscribe(keyboards[i], &subscriptions[i]); + device_put(keyboards[i]); + } + if (pointer != nullptr) { + device_put(pointer); + } +} + +} diff --git a/Tactility/Source/app/boot/BootSequence.cpp b/Tactility/Source/app/boot/BootSequence.cpp new file mode 100644 index 000000000..805d2a467 --- /dev/null +++ b/Tactility/Source/app/boot/BootSequence.cpp @@ -0,0 +1,265 @@ +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef ESP_PLATFORM +#include +#include +#include +#else +#define CONFIG_TT_SPLASH_DURATION 0 +#endif + +namespace tt::app::boot { + +constexpr auto* TAG = "Boot"; + +namespace { + +#ifdef ESP_PLATFORM +constexpr auto PARTITION_PREFIX = std::string("/"); +#else +constexpr auto PARTITION_PREFIX = std::string(""); +#endif + +// Equivalent of AppPaths::getAssetsPath() for the internal "Boot" app id, without needing a +// live AppContext (which this app no longer has under the new app-module model). +std::string getBootAssetsPath(const std::string& childPath) { + return std::format("{}{}/app/Boot/assets/{}", PARTITION_PREFIX, file::SYSTEM_PARTITION_NAME, childPath); +} + +// TODO: Replace with automatic asset buckets like on Android +std::string getSizedAssetPath(const BootScreen& screen, const char* small, const char* medium, const char* large) { + const int smallest_dimension = screen.getSmallestDimension(); + if (smallest_dimension < 150) { // e.g. Cardputer + return getBootAssetsPath(small); + } else if (smallest_dimension >= 320) { + return getBootAssetsPath(large); + } else { + return getBootAssetsPath(medium); + } +} + +std::string getLogoPath(const BootScreen& screen) { + return getSizedAssetPath(screen, "logo_small.png", "logo.png", "logo_large.png"); +} + +std::string getUsbLogoPath(const BootScreen& screen) { + return getSizedAssetPath(screen, "logo_usb_small.png", "logo_usb.png", "logo_usb_large.png"); +} + +void setupDisplay() { + // TODO: Support for multiple displays + + Device* display = nullptr; + if (device_get_first_by_type(&DISPLAY_TYPE, &display) != ERROR_NONE) { + LOG_I(TAG, "No kernel display"); + return; + } + + // Set backlight brightness + Device* backlight; + if (display_get_backlight(display, &backlight) == ERROR_NONE) { + if (!device_is_ready(backlight)) { + if (device_start(backlight) != ERROR_NONE) { + LOG_E(TAG, "Failed to start %s", backlight->name); + } + } + + settings::display::DisplaySettings settings; + if (settings::display::load(settings)) { + } else { + settings = settings::display::getDefault(); + } + + if (backlight_set_brightness(backlight, settings.backlightDuty) == ERROR_NONE) { + LOG_I(TAG, "Backlight for %s set to %d", display->name, settings.backlightDuty); + } else { + LOG_E(TAG, "Failed to set brightness of %s", backlight->name); + } + device_put(backlight); + } else { + LOG_I(TAG, "No backlight for %s", display->name); + } + + device_put(display); +} + +enum class UsbBootResult { + /** Not booting into USB mass storage mode */ + None, + Started, + Failed +}; + +UsbBootResult setupUsbBootMode() { + if (!hal::usb::isUsbBootMode()) { + return UsbBootResult::None; + } + + LOG_I(TAG, "Rebooting into mass storage device mode"); + auto mode = hal::usb::getUsbBootMode(); // Get mode before reset + hal::usb::resetUsbBootMode(); + delay_millis(3000); + + bool started = false; + if (mode == hal::usb::BootMode::Flash) { + started = hal::usb::startMassStorageWithFlash(true); + } else if (mode == hal::usb::BootMode::Sdmmc) { + started = hal::usb::startMassStorageWithSdmmc(true); + } + + return started ? UsbBootResult::Started : UsbBootResult::Failed; +} + +void waitForMinimalSplashDuration(TickType_t startTime) { + const auto end_time = get_ticks(); + const auto ticks_passed = end_time - startTime; + constexpr auto minimum_ticks = (CONFIG_TT_SPLASH_DURATION / portTICK_PERIOD_MS); + if (minimum_ticks > ticks_passed) { + delay_ticks(minimum_ticks - ticks_passed); + } +} + +std::string getLauncherAppId() { + settings::BootSettings boot_properties; + // When boot.properties hasn't been overridden, return default + if (!settings::loadBootSettings(boot_properties)) { + return CONFIG_TT_LAUNCHER_APP_ID; + } + + // When boot properties didn't specify an override, return default + if (boot_properties.launcherAppId.empty()) { + LOG_E(TAG, "Failed to load launcher configuration, or launcher not configured"); + return CONFIG_TT_LAUNCHER_APP_ID; + } + + // If the app in the boot.properties does not exist, return default + AppManifest manifest; + if (app_manager_find_manifest(boot_properties.launcherAppId.c_str(), &manifest) != ERROR_NONE) { + LOG_E(TAG, "Launcher app %s not found", boot_properties.launcherAppId.c_str()); + return CONFIG_TT_LAUNCHER_APP_ID; + } + + // The boot.properties launcher app id is valid + return boot_properties.launcherAppId; +} + +void reboot() { +#ifdef ESP_PLATFORM + esp_restart(); +#else + LOG_W(TAG, "Reboot is not supported on this platform"); +#endif +} + +void waitForInputAndReboot() { + waitForInput(); + reboot(); +} + +void startNextApp() { +#ifdef ESP_PLATFORM + if (esp_reset_reason() == ESP_RST_PANIC) { + crashdiagnostics::start(); // fire-and-forget; no result expected back + return; + } +#endif + + auto launcher_app_id = getLauncherAppId(); + uint32_t launcher_instance_id = 0; + AppStartContext context; + if (app_start_context_from_id(launcher_app_id.c_str(), &context) == ERROR_NONE) { + app_start_with_context(&context, &launcher_instance_id); + } +} + +} // namespace + +bool runBootSequence(TickType_t startTime) { + LOG_I(TAG, "Starting boot sequence"); + + const bool is_usb_boot = hal::usb::isUsbBootMode(); + + BootScreen screen; + if (screen.begin()) { + screen.show(is_usb_boot ? getUsbLogoPath(screen) : getLogoPath(screen), {}); + } + + LOG_I(TAG, "Setup display"); + setupDisplay(); + LOG_I(TAG, "Prepare file systems"); + prepareFileSystems(); + + bool sd_card_missing = false; +#ifdef CONFIG_TT_USER_DATA_LOCATION_SD + std::string sd_path; + if (!findFirstMountedSdCardPath(sd_path)) { + LOG_E(TAG, "SD card not found"); + sd_card_missing = true; + } +#endif + + switch (setupUsbBootMode()) { + case UsbBootResult::None: + break; + case UsbBootResult::Started: +#ifdef ESP_PLATFORM + screen.show(getUsbLogoPath(screen), { getInputPrompt("return to OS") }); + waitForInput(); + hal::usb::stop(); + esp_restart(); +#endif + return false; + case UsbBootResult::Failed: + screen.show("", { "Failed to start USB mass storage:", hal::usb::getLastError(), getInputPrompt("reboot") }); + waitForInputAndReboot(); + return false; + } + + registerApps(); + waitForMinimalSplashDuration(startTime); + + if (sd_card_missing) { + screen.show("", { "SD card not found.", "Please insert one and reboot.", getInputPrompt("reboot") }); + waitForInputAndReboot(); + return false; + } + + LOG_I(TAG, "Loading icon fonts"); + lvgl::initIconFonts(); + + screen.end(); + LOG_I(TAG, "Starting LVGL"); + lvgl::start(); + startNextApp(); + + // This event will likely block as other systems are initialized + // e.g. Wi-Fi reads AP configs from SD card + LOG_I(TAG, "Publish event"); + system_event_emit(KERNEL_EVENT_BOOT_COMPLETED, nullptr, 0); + return true; +} + +} diff --git a/Tactility/Source/app/usbsettings/UsbSettings.cpp b/Tactility/Source/app/usbsettings/UsbSettings.cpp index dd38b6b66..bda8f4822 100644 --- a/Tactility/Source/app/usbsettings/UsbSettings.cpp +++ b/Tactility/Source/app/usbsettings/UsbSettings.cpp @@ -55,6 +55,7 @@ void createWidgets(lv_obj_t* parent, void* userData) { lv_obj_align(wrapper, LV_ALIGN_CENTER, 0, 0); // Ensures showing selection state for keyboard/encoder devices lv_obj_set_style_pad_all(wrapper, 6, LV_ALIGN_DEFAULT); + lv_obj_set_style_border_width(wrapper, 0, LV_STATE_DEFAULT); bool hasSd = hal::usb::canRebootIntoMassStorageSdmmc(); bool hasFlash = hal::usb::canRebootIntoMassStorageFlash(); diff --git a/Tactility/Source/lvgl/Lvgl.cpp b/Tactility/Source/lvgl/Lvgl.cpp new file mode 100644 index 000000000..6bf3d4bc8 --- /dev/null +++ b/Tactility/Source/lvgl/Lvgl.cpp @@ -0,0 +1,232 @@ +#include + +#ifdef ESP_PLATFORM +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_TT_TOUCH_CALIBRATION_SUPPORTED +#include +#endif + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace tt { + +namespace service { + namespace autorotate { extern const ServiceManifest manifest; } + namespace memorychecker { extern const ServiceManifest manifest; } + namespace statusbar { extern const ServiceManifest manifest; } +#ifdef ESP_PLATFORM + namespace displayidle { extern const ServiceManifest manifest; } + namespace keyboardidle { extern const ServiceManifest manifest; } +#endif +#if TT_FEATURE_SCREENSHOT_ENABLED + namespace screenshot { extern const ServiceManifest manifest; } +#endif +} + +namespace lvgl { + +static void stopAppFromToolbar(lv_event_t*) { + // Default nav action for any toolbar that doesn't override it itself. Prefer the topmost + // new-model app if one is showing; fall back to the old system otherwise (this is what + // every not-yet-converted app's toolbar still relies on). + AppInstanceId topmost = 0; + check(app_manager_get_topmost_instance_id(&topmost) == ERROR_NONE); + + app_event_emit_close(topmost); +} + +// The on-screen keyboard widget itself, constructed during windowManagerScreenInit +static LvglSoftwareKeyboard softwareKeyboard { .object = nullptr }; + +static lv_obj_t* windowManagerScreenInit(lv_obj_t* root) { + lv_obj_t* vertical_container = lv_obj_create(root); + lv_obj_set_size(vertical_container, LV_PCT(100), LV_PCT(100)); + lv_obj_set_flex_flow(vertical_container, LV_FLEX_FLOW_COLUMN); + lv_obj_set_style_pad_all(vertical_container, 0, LV_STATE_DEFAULT); + lv_obj_set_style_pad_gap(vertical_container, 0, LV_STATE_DEFAULT); + lv_obj_set_style_bg_color(vertical_container, lv_color_black(), LV_STATE_DEFAULT); + lv_obj_set_style_border_width(vertical_container, 0, LV_STATE_DEFAULT); + lv_obj_set_style_radius(vertical_container, 0, LV_STATE_DEFAULT); + lv_obj_remove_flag(vertical_container, LV_OBJ_FLAG_SCROLLABLE); + + lvgl::statusbar_create(vertical_container); + + auto* app_container = lv_obj_create(vertical_container); + lv_obj_set_style_pad_all(app_container, 0, LV_STATE_DEFAULT); + lv_obj_set_style_border_width(app_container, 0, LV_STATE_DEFAULT); + lv_obj_set_width(app_container, LV_PCT(100)); + lv_obj_set_flex_grow(app_container, 1); + lv_obj_set_flex_flow(app_container, LV_FLEX_FLOW_COLUMN); + lv_obj_remove_flag(app_container, LV_OBJ_FLAG_SCROLLABLE); + + // Parented to root (not app_container/vertical_container) so it overlays on top of + // everything, including the statusbar, regardless of which app is showing. Hidden until a + // focused textarea shows it (see lvgl_keyboard_add_textarea()/textarea_show_keyboard()). + lvgl_software_keyboard_construct(&softwareKeyboard, root); + + return app_container; +} + +#ifdef CONFIG_TT_TOUCH_CALIBRATION_SUPPORTED + +// Applies the calibration persisted by the touch calibration app to the live pointer indev. +// lvgl_devices_attach() runs before onLvglStarted(), so the default indev already exists here. +static void applySavedTouchCalibration() { + settings::touch::TouchCalibrationSettings settings = settings::touch::loadOrGetDefault(); + if (!settings.enabled || !settings::touch::isValid(settings)) { + return; + } + + LvglPointerCalibration calibration = { + .x_min = settings.xMin, + .x_max = settings.xMax, + .y_min = settings.yMin, + .y_max = settings.yMax, + }; + + lvgl_lock(); + auto* indev = lvgl_pointer_get_default(); + if (indev != nullptr) { + lvgl_pointer_set_calibration(indev, &calibration); + } + lvgl_unlock(); +} + +#endif // CONFIG_TT_TOUCH_CALIBRATION_SUPPORTED + +static void onLvglStarted() { + // lv_display_create() (inside lvgl_devices_attach(), which already ran by this point) always + // resets rotation to LV_DISPLAY_ROTATION_0. The only other code that ever applies a saved + // orientation is the display settings app's dropdown change handler, so without this, every + // LVGL restart (not just first boot) silently drops back to unrotated. Must run before + // window_manager_start() below builds the window tree against the display's current size. + lvgl_lock(); + if (auto* display = lv_display_get_default(); display != nullptr) { + auto displaySettings = settings::display::loadOrGetDefault(); + lv_display_set_rotation(display, settings::display::toLvglDisplayRotation(displaySettings.orientation)); + } + lvgl_unlock(); + + window_manager_configure(windowManagerScreenInit); + check(module_ensure_started(&lvgl_window_manager_module) == ERROR_NONE); + + ToolbarConfig toolbar_config = { .nav_action_callback = stopAppFromToolbar }; + lvgl_toolbar_configure(&toolbar_config); + + addService(service::statusbar::manifest); + addService(service::memorychecker::manifest); +#if defined(ESP_PLATFORM) + addService(service::displayidle::manifest); +#endif + if (device_exists_of_type(&IMU_TYPE)) { + addService(service::autorotate::manifest); + } +#if defined(CONFIG_TT_TDECK_WORKAROUND) + addService(service::keyboardidle::manifest); +#endif +#if TT_FEATURE_SCREENSHOT_ENABLED + addService(service::screenshot::manifest); +#endif + + lvgl::startUsbHidInput(); + lvgl::startKeyboardDeviceListener(); + lvgl::initTrackball(); + +#ifdef CONFIG_TT_TOUCH_CALIBRATION_SUPPORTED + applySavedTouchCalibration(); +#endif + + memory_log_stats(); +} + +static void onLvglStopped() { + lvgl::stopKeyboardDeviceListener(); + lvgl::stopUsbHidInput(); + + if (device_exists_of_type(&IMU_TYPE)) { + check(service::removeService(service::autorotate::manifest.id)); + } +#if TT_FEATURE_SCREENSHOT_ENABLED + check(service::removeService(service::screenshot::manifest.id)); +#endif +#if defined(CONFIG_TT_TDECK_WORKAROUND) + check(service::removeService(service::keyboardidle::manifest.id)); +#endif +#if defined(ESP_PLATFORM) + check(service::removeService(service::displayidle::manifest.id)); +#endif + check(service::removeService(service::memorychecker::manifest.id)); + check(service::removeService(service::statusbar::manifest.id)); + + if (softwareKeyboard.object != nullptr) { + // lv_obj_delete() walks/mutates the object graph (event lists, group membership, + // parent/child links). Without the LVGL lock this can race the LVGL port task's own + // concurrent traversal (input dispatch, timers, animations), producing an intermittent + // double-free/use-after-free inside lv_obj_destructor/lv_event_mark_deleted. + lvgl_lock(); + lvgl_software_keyboard_destruct(&softwareKeyboard); + lvgl_unlock(); + } + + module_stop(&lvgl_window_manager_module); + + memory_log_stats(); +} + +bool isStarted() { + return module_is_started(&lvgl_module); +} + +void start() { + static bool configured = false; + if (!configured) { + lvgl_module_configure((LvglModuleConfig) { + .on_start = onLvglStarted, + .on_stop = onLvglStopped, + .task_priority = THREAD_PRIORITY_HIGHER, + .task_stack_size = 9120, +#ifdef ESP_PLATFORM + .task_affinity = getCpuAffinityConfiguration().graphics +#endif + }); + configured = true; + } + check(module_ensure_started(&lvgl_module) == ERROR_NONE); +} + +void stop() { + module_stop(&lvgl_module); +} + +} // namespace lvgl + +} // namespace tt diff --git a/Tactility/Source/service/audio/Audio.cpp b/Tactility/Source/service/audio/Audio.cpp index 81623946f..0c7d85074 100644 --- a/Tactility/Source/service/audio/Audio.cpp +++ b/Tactility/Source/service/audio/Audio.cpp @@ -9,7 +9,7 @@ namespace tt::service::audio { extern const ServiceManifest manifest; -// The service is only registered when audio hardware is present (see Tactility.cpp); +// The service is only registered when audio hardware is present (see InitServices.cpp); // treat "not registered" as "no device bound" rather than asserting via findAudioService(). static std::shared_ptr tryFindAudioService() { return findServiceById(manifest.id); diff --git a/Tactility/Source/service/rtctime/RtcTime.cpp b/Tactility/Source/service/rtctime/RtcTime.cpp index b251eb1cd..aa91d32e2 100644 --- a/Tactility/Source/service/rtctime/RtcTime.cpp +++ b/Tactility/Source/service/rtctime/RtcTime.cpp @@ -14,7 +14,7 @@ extern const ServiceManifest manifest; bool isAvailable() { #ifdef ESP_PLATFORM - // The service is only registered when an RTC device is present (see Tactility.cpp); + // The service is only registered when an RTC device is present (see InitServices.cpp); // treat "not registered" the same as "no device bound" rather than asserting. auto service = findServiceById(manifest.id); return service != nullptr && service->isAvailable(); diff --git a/Tactility/Source/service/webserver/WebServerService.cpp b/Tactility/Source/service/webserver/WebServerService.cpp index 44f1bba04..d0dd196c0 100644 --- a/Tactility/Source/service/webserver/WebServerService.cpp +++ b/Tactility/Source/service/webserver/WebServerService.cpp @@ -1525,7 +1525,7 @@ error_t WebServerService::handleApiScreenshot(HttpServerRequest* request, void*) LOG_I(TAG, "Screenshot will be saved to: %s", screenshot_path.c_str()); - // LVGL's lodepng uses lv_fs which requires the "A:" prefix + // lv_screenshot writes through lv_fs, which requires the "A:" prefix std::string lvgl_screenshot_path = lvgl::PATH_PREFIX + screenshot_path; // Capture screenshot using LVGL diff --git a/Tactility/Source/settings/DisplaySettings.cpp b/Tactility/Source/settings/DisplaySettings.cpp index bd992e485..c6b6201db 100644 --- a/Tactility/Source/settings/DisplaySettings.cpp +++ b/Tactility/Source/settings/DisplaySettings.cpp @@ -5,6 +5,9 @@ #include +#include +#include + #include #include #include @@ -28,17 +31,19 @@ constexpr auto* SETTINGS_KEY_SCREENSAVER_TYPE = "screensaverType"; constexpr auto* SETTINGS_KEY_AUTO_ROTATE_ENABLED = "autoRotateEnabled"; constexpr auto* SETTINGS_KEY_AUTO_ROTATE_MOUNT_ROTATION = "autoRotateMountRotation"; -static Orientation getDefaultOrientation() { - auto* display = lv_display_get_default(); - if (display == nullptr) { - return Orientation::Landscape; +// Uses the kernel display, so it also works while LVGL isn't running +static bool isOriginallyLandscape() { + Device* display = nullptr; + if (device_get_first_by_type(&DISPLAY_TYPE, &display) != ERROR_NONE) { + return true; } + const bool landscape = display_get_resolution_x(display) > display_get_resolution_y(display); + device_put(display); + return landscape; +} - if (lv_display_get_physical_horizontal_resolution(display) > lv_display_get_physical_vertical_resolution(display)) { - return Orientation::Landscape; - } else { - return Orientation::Portrait; - } +static Orientation getDefaultOrientation() { + return isOriginallyLandscape() ? Orientation::Landscape : Orientation::Portrait; } static std::string toString(Orientation orientation) { @@ -226,12 +231,6 @@ bool save(const DisplaySettings& settings) { return file::savePropertiesFile(settings_path, map); } -static bool isOriginallyLandscape() { - auto* lvgl_display = lv_display_get_default(); - return lv_display_get_original_horizontal_resolution(lvgl_display) > - lv_display_get_original_vertical_resolution(lvgl_display); -} - lv_display_rotation_t toLvglDisplayRotation(Orientation orientation) { if (isOriginallyLandscape()) { // Landscape display diff --git a/TactilityKernel/source/driver.cpp b/TactilityKernel/source/driver.cpp index 9df0cb4fa..31a18a867 100644 --- a/TactilityKernel/source/driver.cpp +++ b/TactilityKernel/source/driver.cpp @@ -9,9 +9,12 @@ #include #include #include +#include #define TAG "driver" +constexpr TickType_t SLOW_START_WARNING_TICKS = pdMS_TO_TICKS(100); + struct DriverInternal { int use_count = 0; bool destroying = false; @@ -59,7 +62,7 @@ error_t driver_destruct(Driver* driver) { } error_t driver_add(Driver* driver) { - LOG_I(TAG, "add %s", driver->name); + LOG_D(TAG, "add %s", driver->name); ledger.lock(); ledger.drivers.push_back(driver); ledger.unlock(); @@ -67,7 +70,7 @@ error_t driver_add(Driver* driver) { } error_t driver_remove(Driver* driver) { - LOG_I(TAG, "remove %s", driver->name); + LOG_D(TAG, "remove %s", driver->name); if (driver->owner == nullptr) return ERROR_NOT_ALLOWED; @@ -135,7 +138,12 @@ error_t driver_bind(Driver* driver, Device* device) { } if (driver->start_device != nullptr) { + const TickType_t start_ticks = get_ticks(); error = driver->start_device(device); + const TickType_t elapsed_ticks = get_ticks() - start_ticks; + if (elapsed_ticks > SLOW_START_WARNING_TICKS) { + LOG_W(TAG, "starting %s with %s took %u ms", device->name, driver->name, static_cast(elapsed_ticks * portTICK_PERIOD_MS)); + } if (error != ERROR_NONE) { goto error; } diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 0fa2547a0..e68b63ee0 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -13,6 +13,7 @@ add_subdirectory(${CMAKE_SOURCE_DIR}/Modules/app-module/tests ${CMAKE_CURRENT_BI add_subdirectory(${CMAKE_SOURCE_DIR}/Modules/app-posix-module/tests ${CMAKE_CURRENT_BINARY_DIR}/app-posix-module) add_subdirectory(${CMAKE_SOURCE_DIR}/Modules/http-module/tests ${CMAKE_CURRENT_BINARY_DIR}/http-module) add_subdirectory(${CMAKE_SOURCE_DIR}/Modules/binfont-module/tests ${CMAKE_CURRENT_BINARY_DIR}/binfont-module) +add_subdirectory(${CMAKE_SOURCE_DIR}/Modules/lodepng-module/tests ${CMAKE_CURRENT_BINARY_DIR}/lodepng-module) add_custom_target(build-tests) add_dependencies(build-tests ServiceModuleTests) @@ -25,3 +26,4 @@ add_dependencies(build-tests AppModuleTests) add_dependencies(build-tests AppPosixModuleTests) add_dependencies(build-tests HttpModuleTests) add_dependencies(build-tests BinFontModuleTests) +add_dependencies(build-tests LodePngModuleTests) diff --git a/device.py b/device.py index 1dc1fdac9..edec31043 100755 --- a/device.py +++ b/device.py @@ -91,7 +91,7 @@ def safe_float(value: str, error_message: str): exit_with_error(error_message) def write_defaults(output_file): - default_properties_path = os.path.join("Buildscripts", "sdkconfig", "default.properties") + default_properties_path = os.path.join("Buildscripts", "sdkconfig-default.properties") default_properties = read_file(default_properties_path) output_file.write(default_properties) diff --git a/lv_conf.h b/lv_conf.h index 15b352692..3ad79800c 100644 --- a/lv_conf.h +++ b/lv_conf.h @@ -631,7 +631,7 @@ #endif /*LODEPNG decoder library*/ -#define LV_USE_LODEPNG 1 +#define LV_USE_LODEPNG 0 /*PNG decoder(libpng) library*/ #define LV_USE_LIBPNG 0 From 5803c7cfe0c571ab31e3e2f1e702fd485e9d9776 Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Sun, 4 Oct 2026 16:37:09 +0200 Subject: [PATCH 3/5] binfont: load into IRAM as fallback instead of file streaming --- .../binfont-module/include/binfont/binfont.h | 18 +- .../binfont-module/private/binfont_private.h | 19 +++ Modules/binfont-module/source/binfont.cpp | 159 ++++++++++++++---- Modules/binfont-module/source/module.c | 2 + Modules/binfont-module/source/render.cpp | 5 + Modules/binfont-module/tests/CMakeLists.txt | 3 +- .../tests/source/binfont_test.cpp | 56 +++++- 7 files changed, 221 insertions(+), 41 deletions(-) create mode 100644 Modules/binfont-module/private/binfont_private.h diff --git a/Modules/binfont-module/include/binfont/binfont.h b/Modules/binfont-module/include/binfont/binfont.h index 413e14989..019d84c90 100644 --- a/Modules/binfont-module/include/binfont/binfont.h +++ b/Modules/binfont-module/include/binfont/binfont.h @@ -48,8 +48,10 @@ typedef struct BinFontGlyph { /** * @brief Opens a font file. - * The whole file is loaded into external memory (PSRAM) when available. Otherwise only the lookup - * tables are loaded and glyph data is read from the file on demand. + * The whole file is loaded into external memory (PSRAM) when available, otherwise into internal memory. + * When that allocation fails, only the lookup tables are loaded and glyph data is read from the file + * on demand: the file is opened and closed for every glyph lookup, unless it's kept open with + * binfont_begin()/binfont_end(). * @param[in] path the file path * @param[out] out the opened font * @retval ERROR_NONE on success @@ -74,6 +76,18 @@ error_t binfont_open_memory(const void* data, size_t size, bool take_ownership, /** Releases the font and all its resources. */ void binfont_close(struct BinFont* font); +/** + * @brief Keeps the font file open until the matching binfont_end(), so rendering many glyphs + * doesn't open and close the file for each of them. Calls can be nested and used from multiple tasks. + * Does nothing for fonts that are fully loaded in memory. + * @retval ERROR_NONE on success + * @retval ERROR_NOT_FOUND when the file can't be opened + */ +error_t binfont_begin(struct BinFont* font); + +/** Ends a binfont_begin() session. The file is closed when no sessions remain. */ +void binfont_end(struct BinFont* font); + void binfont_get_metrics(const struct BinFont* font, BinFontMetrics* out); /** diff --git a/Modules/binfont-module/private/binfont_private.h b/Modules/binfont-module/private/binfont_private.h new file mode 100644 index 000000000..aca4b0d8c --- /dev/null +++ b/Modules/binfont-module/private/binfont_private.h @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Opens a font file without loading it into memory: only the lookup tables are loaded and + * glyph data is read from the file on demand. binfont_open_file() falls back to this when the file + * doesn't fit in memory. + */ +error_t binfont_open_file_streaming(const char* path, struct BinFont** out); + +#ifdef __cplusplus +} +#endif diff --git a/Modules/binfont-module/source/binfont.cpp b/Modules/binfont-module/source/binfont.cpp index 8cc4af230..732bea9c3 100644 --- a/Modules/binfont-module/source/binfont.cpp +++ b/Modules/binfont-module/source/binfont.cpp @@ -1,5 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 #include +#include #include #include @@ -162,8 +163,10 @@ struct BinFont { /** The whole file in memory mode, nullptr in stream mode */ const uint8_t* data; bool ownsData; - /** Stream mode only */ + /** Stream mode only: the file path, and the file while it's open (guarded by mutex) */ + char* path; FILE* file; + uint32_t sessionCount; Mutex mutex; /** Owned copy of the cmap/loca/kern records in stream mode */ uint8_t* tables; @@ -450,6 +453,22 @@ bool get_glyph_location(const BinFont* font, uint32_t glyphId, size_t& offset, s return true; } +/** Reads from the font file in stream mode. Outside of a session, the file is opened for this read only. */ +bool read_glyph_data(BinFont* font, size_t offset, uint8_t* out, size_t size) { + mutex_lock(&font->mutex); + const bool temporary = font->file == nullptr; + if (temporary) { + font->file = fopen(font->path, "rb"); + } + const bool success = font->file != nullptr && read_at(font, offset, out, size); + if (temporary && font->file != nullptr) { + fclose(font->file); + font->file = nullptr; + } + mutex_unlock(&font->mutex); + return success; +} + /** * Provides the record of a glyph. In memory mode it points into the font data, in stream mode it * is read into buffer (bufferSize bytes) or, when that is too small, into an allocation returned @@ -478,9 +497,7 @@ bool get_glyph_record(BinFont* font, uint32_t glyphId, size_t maxSize, uint8_t* target = allocated; } - mutex_lock(&font->mutex); - const bool success = read_at(font, font->glyfOffset + offset, target, size); - mutex_unlock(&font->mutex); + const bool success = read_glyph_data(font, font->glyfOffset + offset, target, size); if (!success) { memory_free(allocated); @@ -504,6 +521,53 @@ void parse_glyph(const Header& header, BitReader& reader, uint32_t glyphId, BinF out->height = static_cast(reader.read(header.whBits)); } +/** Opens a file for reading and determines its size */ +error_t open_file(const char* path, FILE*& file, size_t& size) { + file = fopen(path, "rb"); + if (file == nullptr) { + return ERROR_NOT_FOUND; + } + if (fseek(file, 0, SEEK_END) != 0) { + fclose(file); + return ERROR_NOT_SUPPORTED; + } + const long file_size = ftell(file); + if (file_size <= 0 || fseek(file, 0, SEEK_SET) != 0) { + fclose(file); + return ERROR_NOT_SUPPORTED; + } + size = static_cast(file_size); + return ERROR_NONE; +} + +/** Loads the lookup tables from an open file, then closes it. Glyph data is read on demand. */ +error_t open_streaming(const char* path, FILE* file, size_t size, BinFont** out) { + BinFont* font = create_font(); + if (font == nullptr) { + fclose(file); + return ERROR_OUT_OF_MEMORY; + } + font->file = file; + + const size_t path_size = strlen(path) + 1; + font->path = static_cast(memory_alloc(path_size)); + if (font->path == nullptr) { + binfont_close(font); + return ERROR_OUT_OF_MEMORY; + } + memcpy(font->path, path, path_size); + + const error_t error = parse_layout(font, size); + fclose(font->file); + font->file = nullptr; + if (error != ERROR_NONE) { + binfont_close(font); + return error; + } + *out = font; + return ERROR_NONE; +} + } // namespace extern "C" { @@ -529,51 +593,71 @@ error_t binfont_open_memory(const void* data, size_t size, bool take_ownership, } error_t binfont_open_file(const char* path, BinFont** out) { - FILE* file = fopen(path, "rb"); - if (file == nullptr) { - return ERROR_NOT_FOUND; + FILE* file; + size_t size; + const error_t open_error = open_file(path, file, size); + if (open_error != ERROR_NONE) { + return open_error; } - if (fseek(file, 0, SEEK_END) != 0) { - fclose(file); - return ERROR_NOT_SUPPORTED; + + const uint16_t memory_capability = memory_external_total() > 0 ? MEMORY_CAPABILITY_EXTERNAL : MEMORY_CAPABILITY_INTERNAL; + const MemoryPolicy policy = { .required = memory_capability, .desired = 0, .alignment = 0 }; + auto* data = static_cast(memory_alloc_with_policy(size, &policy)); + if (data == nullptr) { + return open_streaming(path, file, size, out); } - const long file_size = ftell(file); - if (file_size <= 0 || fseek(file, 0, SEEK_SET) != 0) { - fclose(file); + + const bool success = fread(data, 1, size, file) == size; + fclose(file); + if (!success) { + memory_free(data); return ERROR_NOT_SUPPORTED; } - const auto size = static_cast(file_size); + return binfont_open_memory(data, size, true, out); +} - if (memory_external_total() > 0) { - constexpr MemoryPolicy policy = { .required = MEMORY_CAPABILITY_EXTERNAL, .desired = 0, .alignment = 0 }; - auto* data = static_cast(memory_alloc_with_policy(size, &policy)); - if (data != nullptr) { - const bool success = fread(data, 1, size, file) == size; - fclose(file); - if (!success) { - memory_free(data); - return ERROR_NOT_SUPPORTED; - } - return binfont_open_memory(data, size, true, out); - } +error_t binfont_open_file_streaming(const char* path, BinFont** out) { + FILE* file; + size_t size; + const error_t open_error = open_file(path, file, size); + if (open_error != ERROR_NONE) { + return open_error; } + return open_streaming(path, file, size, out); +} - BinFont* font = create_font(); - if (font == nullptr) { - fclose(file); - return ERROR_OUT_OF_MEMORY; +error_t binfont_begin(BinFont* font) { + if (font->data != nullptr) { + return ERROR_NONE; } - font->file = file; - - const error_t error = parse_layout(font, size); - if (error != ERROR_NONE) { - binfont_close(font); - return error; + mutex_lock(&font->mutex); + if (font->sessionCount == 0) { + font->file = fopen(font->path, "rb"); + if (font->file == nullptr) { + mutex_unlock(&font->mutex); + return ERROR_NOT_FOUND; + } } - *out = font; + font->sessionCount++; + mutex_unlock(&font->mutex); return ERROR_NONE; } +void binfont_end(BinFont* font) { + if (font->data != nullptr) { + return; + } + mutex_lock(&font->mutex); + if (font->sessionCount > 0) { + font->sessionCount--; + if (font->sessionCount == 0) { + fclose(font->file); + font->file = nullptr; + } + } + mutex_unlock(&font->mutex); +} + void binfont_close(BinFont* font) { if (font->ownsData) { memory_free(const_cast(font->data)); @@ -581,6 +665,7 @@ void binfont_close(BinFont* font) { if (font->file != nullptr) { fclose(font->file); } + memory_free(font->path); memory_free(font->tables); mutex_destruct(&font->mutex); memory_free(font); diff --git a/Modules/binfont-module/source/module.c b/Modules/binfont-module/source/module.c index b570fdcb1..6a4740eb7 100644 --- a/Modules/binfont-module/source/module.c +++ b/Modules/binfont-module/source/module.c @@ -9,6 +9,8 @@ static const struct ModuleSymbol SYMBOLS[] = { DEFINE_MODULE_SYMBOL(binfont_open_file), DEFINE_MODULE_SYMBOL(binfont_open_memory), DEFINE_MODULE_SYMBOL(binfont_close), + DEFINE_MODULE_SYMBOL(binfont_begin), + DEFINE_MODULE_SYMBOL(binfont_end), DEFINE_MODULE_SYMBOL(binfont_get_metrics), DEFINE_MODULE_SYMBOL(binfont_get_glyph), DEFINE_MODULE_SYMBOL(binfont_get_kerning_x16), diff --git a/Modules/binfont-module/source/render.cpp b/Modules/binfont-module/source/render.cpp index f91f25c78..1d3adc81d 100644 --- a/Modules/binfont-module/source/render.cpp +++ b/Modules/binfont-module/source/render.cpp @@ -100,6 +100,8 @@ int binfont_draw_glyph_rgb565(PixelBuffer* buffer, int x, int baseline_y, BinFon } int binfont_draw_text_rgb565(PixelBuffer* buffer, int x, int baseline_y, BinFont* font, const char* text, uint16_t color, PixelBufferConversion conversion) { + // When the file can't be kept open, every glyph lookup opens it by itself + const bool session = binfont_begin(font) == ERROR_NONE; int32_t pen_x16 = 0; uint32_t previous_glyph_id = 0; while (*text != '\0') { @@ -115,6 +117,9 @@ int binfont_draw_text_rgb565(PixelBuffer* buffer, int x, int baseline_y, BinFont pen_x16 += static_cast(glyph.advance_x16); previous_glyph_id = glyph.glyph_id; } + if (session) { + binfont_end(font); + } return (pen_x16 + 8) >> 4; } diff --git a/Modules/binfont-module/tests/CMakeLists.txt b/Modules/binfont-module/tests/CMakeLists.txt index 5059cff9c..cad3d7a20 100644 --- a/Modules/binfont-module/tests/CMakeLists.txt +++ b/Modules/binfont-module/tests/CMakeLists.txt @@ -5,10 +5,11 @@ enable_language(C CXX ASM) file(GLOB_RECURSE TEST_SOURCES CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/source/*.cpp) add_executable(BinFontModuleTests EXCLUDE_FROM_ALL ${TEST_SOURCES}) -target_include_directories(BinFontModuleTests PRIVATE ${DOCTESTINC}) +target_include_directories(BinFontModuleTests PRIVATE ${DOCTESTINC} ${PROJECT_SOURCE_DIR}/../private) target_compile_definitions(BinFontModuleTests PRIVATE "BINFONT_TEST_FIXTURES_DIR=\"${PROJECT_SOURCE_DIR}/fixtures\"" + "BINFONT_TEST_TEMP_DIR=\"${CMAKE_CURRENT_BINARY_DIR}\"" "BINFONT_TEST_ICON_TTF=\"${CMAKE_SOURCE_DIR}/Data/system/fonts/MaterialSymbolsRounded.ttf\"" ) diff --git a/Modules/binfont-module/tests/source/binfont_test.cpp b/Modules/binfont-module/tests/source/binfont_test.cpp index 073fe1e25..a5bb2bc0c 100644 --- a/Modules/binfont-module/tests/source/binfont_test.cpp +++ b/Modules/binfont-module/tests/source/binfont_test.cpp @@ -1,6 +1,7 @@ #include "doctest.h" #include +#include #include #include #include @@ -174,7 +175,7 @@ TEST_CASE("binfont decodes identical bitmaps for raw, RLE and RLE with prefilter TEST_CASE("binfont gives the same results when streaming from a file") { BinFont* memory_font = open_fixture_in_memory("icons_rlepf_4.bin"); BinFont* file_font = nullptr; - REQUIRE(binfont_open_file(fixture("icons_rlepf_4.bin").c_str(), &file_font) == ERROR_NONE); + REQUIRE(binfont_open_file_streaming(fixture("icons_rlepf_4.bin").c_str(), &file_font) == ERROR_NONE); for (uint32_t codepoint : ICON_CODEPOINTS) { BinFontGlyph memory_glyph, file_glyph; @@ -188,6 +189,59 @@ TEST_CASE("binfont gives the same results when streaming from a file") { binfont_close(file_font); } +TEST_CASE("binfont_open_file loads the font into memory") { + const std::string path = std::string(BINFONT_TEST_TEMP_DIR) + "/binfont_memory_test.bin"; + size_t size; + uint8_t* data = load_file(fixture("icons_rlepf_4.bin"), size); + FILE* copy = fopen(path.c_str(), "wb"); + REQUIRE(copy != nullptr); + REQUIRE(fwrite(data, 1, size, copy) == size); + fclose(copy); + memory_free(data); + + BinFont* font = nullptr; + REQUIRE(binfont_open_file(path.c_str(), &font) == ERROR_NONE); + REQUIRE(remove(path.c_str()) == 0); + + BinFontGlyph glyph; + CHECK(binfont_get_glyph(font, ICON_CODEPOINTS[0], &glyph)); + CHECK(sum(decode(font, glyph)) > 0); + + binfont_close(font); +} + +TEST_CASE("binfont only keeps a streamed font file open during a session") { + // An open file stays readable after it's deleted, so deleting it shows whether it's kept open + const std::string path = std::string(BINFONT_TEST_TEMP_DIR) + "/binfont_session_test.bin"; + size_t size; + uint8_t* data = load_file(fixture("icons_rlepf_4.bin"), size); + FILE* copy = fopen(path.c_str(), "wb"); + REQUIRE(copy != nullptr); + REQUIRE(fwrite(data, 1, size, copy) == size); + fclose(copy); + memory_free(data); + + BinFont* font = nullptr; + REQUIRE(binfont_open_file_streaming(path.c_str(), &font) == ERROR_NONE); + BinFontGlyph glyph; + REQUIRE(binfont_get_glyph(font, ICON_CODEPOINTS[0], &glyph)); + + REQUIRE(binfont_begin(font) == ERROR_NONE); + REQUIRE(binfont_begin(font) == ERROR_NONE); + REQUIRE(remove(path.c_str()) == 0); + binfont_end(font); + // Still open: one session remains + CHECK(binfont_get_glyph(font, ICON_CODEPOINTS[1], &glyph)); + CHECK_FALSE(decode(font, glyph).empty()); + binfont_end(font); + + // Closed: the deleted file can't be opened again + CHECK_FALSE(binfont_get_glyph(font, ICON_CODEPOINTS[2], &glyph)); + CHECK_EQ(binfont_begin(font), ERROR_NOT_FOUND); + + binfont_close(font); +} + TEST_CASE("binfont_get_glyph_bitmap rejects a stride smaller than the glyph width") { BinFont* font = open_fixture_in_memory("icons_raw_2.bin"); BinFontGlyph glyph; From c859328e6a223b532f014541ff18db6a62949d46 Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Sun, 4 Oct 2026 16:55:24 +0200 Subject: [PATCH 4/5] Reduce memory usage with BLE - reduce when not in use (don't alloc scan list) - place data in external memory when possible --- .../private/bluetooth/esp32_ble_internal.h | 8 +++-- .../source/drivers/bluetooth/esp32_ble.cpp | 32 +++++++++++++++++-- .../drivers/bluetooth/esp32_ble_scan.cpp | 6 ++-- 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/Platforms/platform-esp32/private/bluetooth/esp32_ble_internal.h b/Platforms/platform-esp32/private/bluetooth/esp32_ble_internal.h index 09520de68..829d246df 100644 --- a/Platforms/platform-esp32/private/bluetooth/esp32_ble_internal.h +++ b/Platforms/platform-esp32/private/bluetooth/esp32_ble_internal.h @@ -24,6 +24,8 @@ #include +constexpr size_t BLE_SCAN_RESULTS_MAX = 64; + // ---- Per-module headers (structs, accessors, sub-API externs) ---- #include @@ -91,10 +93,10 @@ struct BleCtx { // BLE device name (set before or after radio enable; applied in dispatch_enable) char device_name[BLE_DEVICE_NAME_MAX + 1]; - // Scan data (guarded by scan_mutex) + // Scan data (guarded by scan_mutex), allocated only while the radio is on SemaphoreHandle_t scan_mutex; - BtPeerRecord scan_results[64]; - ble_addr_t scan_addrs[64]; + BtPeerRecord* scan_results; + ble_addr_t* scan_addrs; size_t scan_count; // Device reference (passed to subscribers via BtEvent delivery) diff --git a/Platforms/platform-esp32/source/drivers/bluetooth/esp32_ble.cpp b/Platforms/platform-esp32/source/drivers/bluetooth/esp32_ble.cpp index 91ca4863b..bf5179bac 100644 --- a/Platforms/platform-esp32/source/drivers/bluetooth/esp32_ble.cpp +++ b/Platforms/platform-esp32/source/drivers/bluetooth/esp32_ble.cpp @@ -27,6 +27,7 @@ constexpr auto* TAG = "esp32_ble"; #include +#include #include #if defined(CONFIG_ESP_HOSTED_ENABLED) @@ -665,6 +666,16 @@ void ble_start_advertising_hid(struct Device* device, uint16_t appearance) { // ---- Dispatch helpers ---- +static void free_scan_buffers(BleCtx* ctx) { + xSemaphoreTake(ctx->scan_mutex, portMAX_DELAY); + memory_free(ctx->scan_results); + memory_free(ctx->scan_addrs); + ctx->scan_results = nullptr; + ctx->scan_addrs = nullptr; + ctx->scan_count = 0; + xSemaphoreGive(ctx->scan_mutex); +} + static void dispatch_enable(BleCtx* ctx) { LOG_I(TAG, "dispatch_enable()"); @@ -693,9 +704,22 @@ static void dispatch_enable(BleCtx* ctx) { } #endif - int rc = nimble_port_init(); + constexpr MemoryPolicy scan_policy = { .required = 0, .desired = MEMORY_CAPABILITY_EXTERNAL, .alignment = 0 }; + xSemaphoreTake(ctx->scan_mutex, portMAX_DELAY); + ctx->scan_results = static_cast(memory_calloc_with_policy(BLE_SCAN_RESULTS_MAX, sizeof(BtPeerRecord), &scan_policy)); + ctx->scan_addrs = static_cast(memory_calloc_with_policy(BLE_SCAN_RESULTS_MAX, sizeof(ble_addr_t), &scan_policy)); + ctx->scan_count = 0; + bool scan_alloc_failed = ctx->scan_results == nullptr || ctx->scan_addrs == nullptr; + xSemaphoreGive(ctx->scan_mutex); + + int rc = scan_alloc_failed ? -1 : nimble_port_init(); if (rc != 0) { - LOG_E(TAG, "nimble_port_init failed (rc=%d)", rc); + if (scan_alloc_failed) { + LOG_E(TAG, "Scan buffer allocation failed"); + } else { + LOG_E(TAG, "nimble_port_init failed (rc=%d)", rc); + } + free_scan_buffers(ctx); ctx->radio_state.store(BT_RADIO_STATE_OFF); struct BtEvent e = {}; e.type = BT_EVENT_RADIO_STATE_CHANGED; @@ -820,6 +844,7 @@ static void dispatch_disable(BleCtx* ctx) { } #endif nimble_port_deinit(); + free_scan_buffers(ctx); #if defined(CONFIG_ESP_HOSTED_ENABLED) // Symmetric with the enable-side esp_hosted_bt_controller_init/enable() calls. @@ -1152,8 +1177,9 @@ static error_t esp32_ble_start_device(struct Device* device) { ctx->midi_child = nullptr; ctx->hid_device_child = nullptr; ctx->scan_mutex = xSemaphoreCreateMutex(); + ctx->scan_results = nullptr; + ctx->scan_addrs = nullptr; ctx->scan_count = 0; - memset(ctx->scan_results, 0, sizeof(ctx->scan_results)); ctx->host_task_done_sem = xSemaphoreCreateBinary(); if (ctx->host_task_done_sem == nullptr) { LOG_E(TAG, "start_device: host_task_done_sem create failed"); diff --git a/Platforms/platform-esp32/source/drivers/bluetooth/esp32_ble_scan.cpp b/Platforms/platform-esp32/source/drivers/bluetooth/esp32_ble_scan.cpp index 53449a8b1..cb9ade881 100644 --- a/Platforms/platform-esp32/source/drivers/bluetooth/esp32_ble_scan.cpp +++ b/Platforms/platform-esp32/source/drivers/bluetooth/esp32_ble_scan.cpp @@ -27,7 +27,9 @@ void ble_scan_clear_results(struct Device* device) { BleCtx* ctx = ble_get_ctx(device); xSemaphoreTake(ctx->scan_mutex, portMAX_DELAY); ctx->scan_count = 0; - memset(ctx->scan_results, 0, sizeof(ctx->scan_results)); + if (ctx->scan_results != nullptr) { + memset(ctx->scan_results, 0, BLE_SCAN_RESULTS_MAX * sizeof(BtPeerRecord)); + } xSemaphoreGive(ctx->scan_mutex); } @@ -71,7 +73,7 @@ int ble_gap_disc_event_handler(struct ble_gap_event* event, void* arg) { break; } } - if (!found && ctx->scan_count < 64) { + if (!found && ctx->scan_count < BLE_SCAN_RESULTS_MAX) { ctx->scan_results[ctx->scan_count] = record; ctx->scan_addrs[ctx->scan_count] = disc.addr; // full addr (type+val) ctx->scan_count++; From 4595af48bea853169a53ecfc85915bfbea5afaa2 Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Sun, 4 Oct 2026 17:37:25 +0200 Subject: [PATCH 5/5] Move more init code to Boot.cpp and rename BootSequence to BootInit --- Tactility/Include/Tactility/MainDispatcher.h | 41 +++++++++++++++++++ Tactility/Include/Tactility/Tactility.h | 36 +--------------- .../app/boot/{BootSequence.h => BootInit.h} | 2 +- Tactility/Source/Init.cpp | 12 ------ Tactility/Source/InitServices.cpp | 4 -- Tactility/Source/MainDispatcher.cpp | 8 +++- Tactility/Source/TactilityEsp.cpp | 9 ++-- Tactility/Source/app/boot/Boot.cpp | 4 +- .../boot/{BootSequence.cpp => BootInit.cpp} | 39 +++++++++++++++--- 9 files changed, 90 insertions(+), 65 deletions(-) create mode 100644 Tactility/Include/Tactility/MainDispatcher.h rename Tactility/Private/Tactility/app/boot/{BootSequence.h => BootInit.h} (89%) rename Tactility/Source/app/boot/{BootSequence.cpp => BootInit.cpp} (90%) diff --git a/Tactility/Include/Tactility/MainDispatcher.h b/Tactility/Include/Tactility/MainDispatcher.h new file mode 100644 index 000000000..d7e9ccba7 --- /dev/null +++ b/Tactility/Include/Tactility/MainDispatcher.h @@ -0,0 +1,41 @@ +#pragma once + +#include + +#include + +namespace tt { + +/** + * A thin C++ wrapper around the TactilityKernel dispatcher, allowing + * std::function (and therefore capturing lambdas) to be dispatched. + */ +class [[deprecated("Use an app task's stack or a custom task with its own stack")]] MainDispatcher final { + +public: + + using Function = std::function; + + explicit MainDispatcher(DispatcherHandle_t handle) : handle(handle) {} + + /** + * Queue a function to be consumed on the main task. + * @param[in] function the function to execute elsewhere + * @param[in] timeout lock acquisition timeout + * @return true if dispatching was successful (timeout not reached) + */ + bool dispatch(Function function, TickType_t timeout = portMAX_DELAY) const; + +private: + + DispatcherHandle_t handle; +}; + +/** Provides access to the dispatcher that runs on the main task. + * @warning This dispatcher is used for WiFi and might block for some time during WiFi connection. + * @return the dispatcher + */ +[[deprecated("Use an app task's stack or a custom task with its own stack")]] +MainDispatcher getMainDispatcher(); + +} // namespace tt diff --git a/Tactility/Include/Tactility/Tactility.h b/Tactility/Include/Tactility/Tactility.h index 35d21487a..7dc0e7eff 100644 --- a/Tactility/Include/Tactility/Tactility.h +++ b/Tactility/Include/Tactility/Tactility.h @@ -1,42 +1,16 @@ #pragma once -#include +#include // Included for backwards compatibility + #include #include -#include - extern "C" { struct DtsDevice; } namespace tt { -/** - * A thin C++ wrapper around the TactilityKernel dispatcher, allowing - * std::function (and therefore capturing lambdas) to be dispatched. - */ -class MainDispatcher final { - -public: - - using Function = std::function; - - explicit MainDispatcher(DispatcherHandle_t handle) : handle(handle) {} - - /** - * Queue a function to be consumed on the main task. - * @param[in] function the function to execute elsewhere - * @param[in] timeout lock acquisition timeout - * @return true if dispatching was successful (timeout not reached) - */ - bool dispatch(Function function, TickType_t timeout = portMAX_DELAY) const; - -private: - - DispatcherHandle_t handle; -}; - /** * @brief Initializes Tactility and starts the Boot app. * @param dtsModules List of modules from devicetree, null-terminated, non-null parameter @@ -45,10 +19,4 @@ class MainDispatcher final { */ bool init(Module* const dtsModules[], const DtsDevice dtsDevices[]); -/** Provides access to the dispatcher that runs on the main task. - * @warning This dispatcher is used for WiFi and might block for some time during WiFi connection. - * @return the dispatcher - */ -MainDispatcher getMainDispatcher(); - } // namespace tt diff --git a/Tactility/Private/Tactility/app/boot/BootSequence.h b/Tactility/Private/Tactility/app/boot/BootInit.h similarity index 89% rename from Tactility/Private/Tactility/app/boot/BootSequence.h rename to Tactility/Private/Tactility/app/boot/BootInit.h index 849994e0c..3da8b891c 100644 --- a/Tactility/Private/Tactility/app/boot/BootSequence.h +++ b/Tactility/Private/Tactility/app/boot/BootInit.h @@ -10,6 +10,6 @@ namespace tt::app::boot { * @param[in] startTime the ticks at which the boot app started, for the minimal splash duration * @return true when the boot completed and the next app was started */ -bool runBootSequence(TickType_t startTime); +bool bootInit(TickType_t startTime); } diff --git a/Tactility/Source/Init.cpp b/Tactility/Source/Init.cpp index 3866f2b27..c9c8b2c91 100644 --- a/Tactility/Source/Init.cpp +++ b/Tactility/Source/Init.cpp @@ -46,18 +46,6 @@ bool init(Module* const dtsModules[], const DtsDevice dtsDevices[]) { initEsp(); #endif - settings::initTimeZone(); - - // Attempt to start all disabled SD cards (some require delayed init) - hal::sdcard::startAll(); - - network::ntp::init(); - bluetooth::systemStart(); - - registerAndStartServices(); - - LOG_I(TAG, "Core systems ready"); - startBootApp(); return true; diff --git a/Tactility/Source/InitServices.cpp b/Tactility/Source/InitServices.cpp index 43ab55d37..5b9f20876 100644 --- a/Tactility/Source/InitServices.cpp +++ b/Tactility/Source/InitServices.cpp @@ -13,13 +13,10 @@ #include #include #include -#include #include namespace tt { -constexpr auto* TAG = "Tactility"; - // region Default services namespace service { // Primary @@ -38,7 +35,6 @@ namespace service { // endregion void registerAndStartServices() { - LOG_I(TAG, "Registering and starting primary system services"); if (device_exists_of_type(&AUDIO_STREAM_TYPE)) { addService(service::audio::manifest); } diff --git a/Tactility/Source/MainDispatcher.cpp b/Tactility/Source/MainDispatcher.cpp index d0402b5d6..06e4ba04b 100644 --- a/Tactility/Source/MainDispatcher.cpp +++ b/Tactility/Source/MainDispatcher.cpp @@ -1,6 +1,10 @@ -#include +#include #include +// Implements the deprecated MainDispatcher API +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + namespace tt { static DispatcherHandle_t mainDispatcherHandle = dispatcher_alloc(); @@ -33,3 +37,5 @@ DispatcherHandle_t getMainDispatcherHandle() { } } // namespace + +#pragma GCC diagnostic pop diff --git a/Tactility/Source/TactilityEsp.cpp b/Tactility/Source/TactilityEsp.cpp index 802289f18..f16f19493 100644 --- a/Tactility/Source/TactilityEsp.cpp +++ b/Tactility/Source/TactilityEsp.cpp @@ -10,16 +10,13 @@ constexpr auto* TAG = "Tactility"; namespace tt { -static void initNetwork() { - LOG_I(TAG, "Init network"); +void initEsp() { + LOG_I(TAG, "Init esp_netif"); ESP_ERROR_CHECK(esp_netif_init()); + LOG_I(TAG, "Init esp_event_loop"); ESP_ERROR_CHECK(esp_event_loop_create_default()); } -void initEsp() { - initNetwork(); -} - } // namespace #endif diff --git a/Tactility/Source/app/boot/Boot.cpp b/Tactility/Source/app/boot/Boot.cpp index 0cc7f56cf..b8fbb807b 100644 --- a/Tactility/Source/app/boot/Boot.cpp +++ b/Tactility/Source/app/boot/Boot.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -23,7 +23,7 @@ int32_t appMain(int argc, char* argv[]) { AppEventSubscription sub {}; check(app_event_subscribe(&sub, &event_group) == ERROR_NONE); - if (runBootSequence(start_time)) { + if (bootInit(start_time)) { app_event_emit_close(app_scheduler_current_app_id()); } diff --git a/Tactility/Source/app/boot/BootSequence.cpp b/Tactility/Source/app/boot/BootInit.cpp similarity index 90% rename from Tactility/Source/app/boot/BootSequence.cpp rename to Tactility/Source/app/boot/BootInit.cpp index 805d2a467..e4df53403 100644 --- a/Tactility/Source/app/boot/BootSequence.cpp +++ b/Tactility/Source/app/boot/BootInit.cpp @@ -1,4 +1,9 @@ -#include +#include + +#include "Tactility/bluetooth/Bluetooth.h" +#include "Tactility/hal/SdCard.h" +#include "Tactility/network/NtpPrivate.h" +#include "Tactility/settings/TimePrivate.h" #include #include @@ -197,18 +202,36 @@ void startNextApp() { } // namespace -bool runBootSequence(TickType_t startTime) { +bool bootInit(TickType_t startTime) { LOG_I(TAG, "Starting boot sequence"); - const bool is_usb_boot = hal::usb::isUsbBootMode(); + auto start_time = get_millis(); + BootScreen screen; if (screen.begin()) { screen.show(is_usb_boot ? getUsbLogoPath(screen) : getLogoPath(screen), {}); } - LOG_I(TAG, "Setup display"); + LOG_I(TAG, "Init display"); setupDisplay(); + + LOG_I(TAG, "Init timezone"); + settings::initTimeZone(); + + // Attempt to start all disabled SD cards (some require delayed init) + LOG_I(TAG, "Init SDMMC"); + hal::sdcard::startAll(); + + LOG_I(TAG, "Init NTP"); + network::ntp::init(); + + LOG_I(TAG, "Init BLE"); + bluetooth::systemStart(); + + LOG_I(TAG, "Init Services"); + registerAndStartServices(); + LOG_I(TAG, "Prepare file systems"); prepareFileSystems(); @@ -239,7 +262,6 @@ bool runBootSequence(TickType_t startTime) { } registerApps(); - waitForMinimalSplashDuration(startTime); if (sd_card_missing) { screen.show("", { "SD card not found.", "Please insert one and reboot.", getInputPrompt("reboot") }); @@ -251,6 +273,12 @@ bool runBootSequence(TickType_t startTime) { lvgl::initIconFonts(); screen.end(); + + size_t total_time = get_millis() - start_time; + LOG_I(TAG, "Finished in %lu ms", static_cast(total_time)); + + waitForMinimalSplashDuration(startTime); + LOG_I(TAG, "Starting LVGL"); lvgl::start(); startNextApp(); @@ -259,6 +287,7 @@ bool runBootSequence(TickType_t startTime) { // e.g. Wi-Fi reads AP configs from SD card LOG_I(TAG, "Publish event"); system_event_emit(KERNEL_EVENT_BOOT_COMPLETED, nullptr, 0); + return true; }