From 47e2d58b221cb19d3e793a134301fb1840dec51c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0irhoe=20Biazhkovi=C4=8D?= Date: Sun, 7 Nov 2021 22:19:53 +0300 Subject: [PATCH 1/7] Initial work on alpha channel for gif --- gif.h | 2 +- lottie_export.cpp | 201 ++++++++++++++++++++++++++-------------------- lottie_export.h | 2 + 3 files changed, 119 insertions(+), 86 deletions(-) diff --git a/gif.h b/gif.h index a941bf9..94d445c 100644 --- a/gif.h +++ b/gif.h @@ -602,7 +602,7 @@ static void GifWriteLzwImage(FILE* f, uint8_t* image, uint32_t left, uint32_t to fputc(0x21, f); fputc(0xf9, f); fputc(0x04, f); - fputc(0x05, f); // leave prev frame in place, this frame has transparency + fputc(0x0d, f); // leave prev frame in place, this frame has transparency if (delaypos) *delaypos = ftell(f); fputc(delay & 0xff, f); fputc((delay >> 8) & 0xff, f); diff --git a/lottie_export.cpp b/lottie_export.cpp index 3222d92..cc8590a 100644 --- a/lottie_export.cpp +++ b/lottie_export.cpp @@ -27,10 +27,10 @@ #include "lottie_export.h" #include "gif.h" -int write_png(byte * buffer, size_t w, size_t h, FILE * out_file) { +int write_png(byte *buffer, size_t w, size_t h, FILE *out_file) { png_structp png_ptr = NULL; png_infop info_ptr = NULL; - png_byte ** row_pointers = NULL; + png_byte **row_pointers = NULL; png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); @@ -52,17 +52,18 @@ int write_png(byte * buffer, size_t w, size_t h, FILE * out_file) { return EXIT_FAILURE; } - png_set_IHDR(png_ptr, info_ptr, w, h, lp_COLOR_DEPTH, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, - PNG_FILTER_TYPE_DEFAULT); + png_set_IHDR(png_ptr, info_ptr, w, h, lp_COLOR_DEPTH, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); - row_pointers = (png_byte **) png_malloc(png_ptr, h * sizeof (png_byte *)); + row_pointers = (png_byte **) png_malloc(png_ptr, h * sizeof(png_byte *)); if (row_pointers == NULL) { png_destroy_write_struct(&png_ptr, &info_ptr); perror("PNG export failed\n"); return EXIT_FAILURE; } for (int y = 0; y < h; ++y) { - png_byte * row = (png_byte *) png_malloc(png_ptr, sizeof (byte) * w * lp_COLOR_BYTES); + png_byte *row = (png_byte *) png_malloc(png_ptr, sizeof(byte) * w * lp_COLOR_BYTES); if (row == NULL) { perror("PNG export failed\n"); for (int yy = 0; yy < y; ++yy) { @@ -97,64 +98,63 @@ int write_png(byte * buffer, size_t w, size_t h, FILE * out_file) { return EXIT_SUCCESS; } -int convert_and_write_to(byte * in_file_data, uint8_t convert_to, size_t w, size_t h, uint32_t param, file out_file) { - string data(reinterpret_cast (in_file_data)); +int convert_and_write_to(byte *in_file_data, uint8_t convert_to, size_t w, size_t h, uint32_t param, file out_file) { + string data(reinterpret_cast (in_file_data)); unique_ptr animation = Animation::loadFromData(data, "", "", false); if (!animation) { fputs("Unable to load animation\n", stderr); return EXIT_FAILURE; } size_t frame_count = animation->totalFrame(); - unique_ptr < uint32_t[] > buffer = unique_ptr < uint32_t[]>(new uint32_t[w * h]); - if(buffer == nullptr || buffer.get() == nullptr){ + unique_ptr buffer = unique_ptr(new uint32_t[w * h]); + if (buffer == nullptr || buffer.get() == nullptr) { fputs("Unable to init frame buffer\n", stderr); return EXIT_FAILURE; } switch (convert_to) { - case li_OUT_PNG: - { + case li_OUT_PNG: { size_t frame_to_extract = frame_count * param / 100; if (frame_to_extract > frame_count - 1) frame_to_extract = frame_count - 1; Surface surface(buffer.get(), w, h, w * lp_COLOR_BYTES); animation->renderSync(frame_to_extract, surface); - return write_png(reinterpret_cast (buffer.get()), w, h, out_file.file_pointer); + return write_png(reinterpret_cast (buffer.get()), w, h, out_file.file_pointer); } - case li_OUT_PNGS: - { - float ratio = (float)animation->frameRate()/param; - size_t frame_count_out = frame_count/ratio, file_template_len = strlen(out_file.path) + strlen(ls_OUT_PNGS_SUFFIX) + 1; + case li_OUT_PNGS: { + float ratio = (float) animation->frameRate() / param; + size_t frame_count_out = frame_count / ratio, file_template_len = + strlen(out_file.path) + strlen(ls_OUT_PNGS_SUFFIX) + 1; size_t frame_count_out_t = frame_count_out; unsigned int digit_count = 1, frame_number = 0; - while(frame_count_out_t > 9){ + while (frame_count_out_t > 9) { frame_count_out_t /= 10; ++digit_count; } - char * file_name_template = (char *) calloc(file_template_len, sizeof (char)), - * file_name = (char *) calloc(file_template_len + digit_count, sizeof (char)); + char *file_name_template = (char *) calloc(file_template_len, sizeof(char)), + *file_name = (char *) calloc(file_template_len + digit_count, sizeof(char)); int result = EXIT_SUCCESS; - if(file_name_template == NULL || file_name == NULL){ - if(file_name_template != NULL) free(file_name_template); - if(file_name != NULL) free(file_name); + if (file_name_template == NULL || file_name == NULL) { + if (file_name_template != NULL) free(file_name_template); + if (file_name != NULL) free(file_name); perror("Unable to convert to png sequence, possibly prefix too long\n"); return EXIT_FAILURE; } memset(file_name_template, '\0', file_template_len); strncpy(file_name_template, out_file.path, strlen(out_file.path)); strncat(file_name_template, ls_OUT_PNGS_SUFFIX, file_template_len); - for(float frame_current = 0.0f; frame_current < (float)frame_count; frame_current += ratio){ - FILE * fp = NULL; + for (float frame_current = 0.0f; frame_current < (float) frame_count; frame_current += ratio) { + FILE *fp = NULL; memset(file_name, '\0', file_template_len + digit_count); snprintf(file_name, file_template_len + digit_count, file_name_template, digit_count, frame_number++); - if((fp = fopen(file_name, "wb")) == NULL){ + if ((fp = fopen(file_name, "wb")) == NULL) { perror("Unable to write png frame\n"); result = EXIT_FAILURE; break; } Surface surface(buffer.get(), w, h, w * lp_COLOR_BYTES); - animation->renderSync((size_t)(frame_current + 0.5f), surface); - result = write_png(reinterpret_cast (buffer.get()), w, h, fp); + animation->renderSync((size_t) (frame_current + 0.5f), surface); + result = write_png(reinterpret_cast (buffer.get()), w, h, fp); fclose(fp); - if(result != EXIT_SUCCESS){ + if (result != EXIT_SUCCESS) { break; } } @@ -162,42 +162,78 @@ int convert_and_write_to(byte * in_file_data, uint8_t convert_to, size_t w, size free(file_name); return result; } - case li_OUT_GIF: - { - byte bg_r = (param >> 16) & 0xff, bg_g = (param >> 8) & 0xff, bg_b = param & 0xff; - GifWriter writer = GIF_WRITER_INIT(out_file.file_pointer); + case li_OUT_GIF: { + byte a_thr = param & 0xff; + int error_code = 0; + GifFileType *writer = EGifOpen(NULL, NULL, &error_code); + if (writer == NULL || error_code != 0) { + fprintf(stderr, "Unable to initialize GIF writer, error code: %d\n", error_code); + return EXIT_FAILURE; + } int frame_to_extract = (int) (animation->frameRate() / 10); - if (GifBegin(&writer, w, h, 1)) { - for (int frame_current = 0; frame_current < frame_count; frame_current += frame_to_extract) { - Surface surface(buffer.get(), w, h, w * lp_COLOR_BYTES); - animation->renderSync(frame_current, surface); - byte * byte_buffer_raw = reinterpret_cast (buffer.get()); - byte * byte_buffer_exch = byte_buffer_raw, * byte_buffer_start = byte_buffer_raw; - size_t pixel_count = w*h; - for (int i = 0; i < pixel_count; ++i) { - byte b, g, r, a; - b = *byte_buffer_raw++; - g = *byte_buffer_raw++; - r = *byte_buffer_raw++; - a = *byte_buffer_raw++; - if (!a) { - b = bg_b; - g = bg_g; - r = bg_r; - } - *byte_buffer_exch++ = r; - *byte_buffer_exch++ = g; - *byte_buffer_exch++ = b; - *byte_buffer_exch++ = a; - } - if (!GifWriteFrame(&writer, byte_buffer_start, w, h, 1, lp_COLOR_DEPTH)) { - fputs("Something went wrong while appending gif frame\n", stderr); - break; + ColorMapObject *outputPalette = GifMakeMapObject(1 << lp_COLOR_DEPTH, NULL); + ((GifFilePrivateType *) writer->Private)->File = out_file.file_pointer; + EGifSetGifVersion(writer, true); + if (EGifPutScreenDesc( + writer, + w, h, lp_COLOR_DEPTH, 0, + outputPalette + ) == GIF_ERROR) { + fputs("Something went wrong while creating gif\n", stderr); + return EXIT_FAILURE; + } + if(EGifPutImageDesc(writer, + 0, 0, w, h, false, NULL) == GIF_ERROR){ + fputs("Unable to write gif structure\n", stderr); + return EXIT_FAILURE; + } + byte loop[]{1, 0, 0}; + if (EGifPutExtensionLeader(writer, APPLICATION_EXT_FUNC_CODE) == GIF_ERROR) { + fputs("Unable to write gif structure\n", stderr); + return EXIT_FAILURE; + } + if (EGifPutExtensionBlock(writer, 11, "NETSCAPE2.0") == GIF_ERROR) { + fputs("Unable to write gif structure\n", stderr); + return EXIT_FAILURE; + } + if (EGifPutExtensionBlock(writer, 3, loop) == GIF_ERROR) { + fputs("Unable to write gif structure\n", stderr); + return EXIT_FAILURE; + } + if (EGifPutExtensionTrailer(writer) == GIF_ERROR) { + fputs("Unable to write gif structure\n", stderr); + return EXIT_FAILURE; + } + for (int frame_current = 0; frame_current < frame_count; frame_current += frame_to_extract) { + Surface surface(buffer.get(), w, h, w * lp_COLOR_BYTES); + animation->renderSync(frame_current, surface); + byte *byte_buffer_raw = reinterpret_cast (buffer.get()); + byte *byte_buffer_exch = byte_buffer_raw, *byte_buffer_start = byte_buffer_raw; + size_t pixel_count = w * h; + for (int i = 0; i < pixel_count; ++i) { + byte b, g, r, a; + b = *byte_buffer_raw++; + g = *byte_buffer_raw++; + r = *byte_buffer_raw++; + a = *byte_buffer_raw++; + if (a <= a_thr) { + b = 0; + g = 0; + r = 0; + a = kGifTransIndex; } + *byte_buffer_exch++ = r; + *byte_buffer_exch++ = g; + *byte_buffer_exch++ = b; + *byte_buffer_exch++ = a; + } + //EGifPutLine(GifFile, &(frames[ni][j]), gifsx) + if (!GifWriteFrame(&writer, byte_buffer_start, w, h, 1, lp_COLOR_DEPTH)) { + fputs("Something went wrong while appending gif frame\n", stderr); + break; } - } else { - fputs("Something went wrong while creating gif\n", stderr); } + //EGifCloseFile(GifFile) GifEnd(&writer); break; } @@ -205,7 +241,7 @@ int convert_and_write_to(byte * in_file_data, uint8_t convert_to, size_t w, size return EXIT_SUCCESS; } -int unzip(FILE * in_file, byte_buffer * out_data) { +int unzip(FILE *in_file, byte_buffer *out_data) { z_stream strm = {0}; byte in[lz_CHUNK_SIZE]; byte out[lz_CHUNK_SIZE]; @@ -218,7 +254,7 @@ int unzip(FILE * in_file, byte_buffer * out_data) { strm.avail_in = 0; - if (inflateInit2(& strm, lz_WINDOWN_BITS | lz_ENABLE_ZLIB_GZIP) < 0) { + if (inflateInit2(&strm, lz_WINDOWN_BITS | lz_ENABLE_ZLIB_GZIP) < 0) { fputs("Unable to init zlib\n", stderr); return EXIT_FAILURE; } @@ -227,9 +263,9 @@ int unzip(FILE * in_file, byte_buffer * out_data) { size_t bytes_read; int zlib_status; - bytes_read = fread(in, sizeof (byte), sizeof (in), in_file); + bytes_read = fread(in, sizeof(byte), sizeof(in), in_file); if (ferror(in_file)) { - inflateEnd(& strm); + inflateEnd(&strm); perror("Unable to read file data\n"); return EXIT_FAILURE; } @@ -239,7 +275,7 @@ int unzip(FILE * in_file, byte_buffer * out_data) { size_t have; strm.avail_out = lz_CHUNK_SIZE; strm.next_out = out; - zlib_status = inflate(& strm, Z_NO_FLUSH); + zlib_status = inflate(&strm, Z_NO_FLUSH); switch (zlib_status) { case Z_OK: case Z_STREAM_END: @@ -254,7 +290,7 @@ int unzip(FILE * in_file, byte_buffer * out_data) { fputs("Unable to allocate memory\n", stderr); return EXIT_FAILURE; } - bytes_read = fread(in, sizeof (byte), sizeof (in), in_file); + bytes_read = fread(in, sizeof(byte), sizeof(in), in_file); if (ferror(in_file)) { perror("Unable to read file data\n"); return EXIT_FAILURE; @@ -266,7 +302,7 @@ int unzip(FILE * in_file, byte_buffer * out_data) { return EXIT_FAILURE; } default: - inflateEnd(& strm); + inflateEnd(&strm); fprintf(stderr, "zlib error %d.\n", zlib_status); return EXIT_FAILURE; } @@ -277,7 +313,7 @@ int unzip(FILE * in_file, byte_buffer * out_data) { } } while (strm.avail_out == 0); if (feof(in_file)) { - inflateEnd(& strm); + inflateEnd(&strm); break; } if (first_read) first_read = false; @@ -290,20 +326,19 @@ int main(int argc, char **argv) { uint32_t param = 1; uint8_t convert_to = li_OUT_PNG; size_t w = 128, h = 128; - FILE * in_file = stdin; + FILE *in_file = stdin; file out_file = file_init(stdout, NULL); int argi = argc; switch (argc) { case 6: --argi; param = strtoul(argv[argi], NULL, 0); - case 5: - { + case 5: { --argi; size_t len = strlen(argv[argi]); size_t index_of_x = strcspn(argv[argi], "x"); if (len > 3 && index_of_x > 0 && index_of_x < len - 1) { - char * res = (char *) calloc(len, sizeof (char)); + char *res = (char *) calloc(len, sizeof(char)); if (res == NULL) { perror("Resolution error"); return EXIT_FAILURE; @@ -316,7 +351,7 @@ int main(int argc, char **argv) { strncpy(res, argv[argi] + index_of_x, len - index_of_x); h = strtoul(argv[argi], NULL, 10); free(res); - if(h == 0 || w == 0 || h > li_MAX_DIMENSION || w > li_MAX_DIMENSION){ + if (h == 0 || w == 0 || h > li_MAX_DIMENSION || w > li_MAX_DIMENSION) { fputs("Invalid resolution\n", stderr); return EXIT_FAILURE; } @@ -325,8 +360,7 @@ int main(int argc, char **argv) { return EXIT_FAILURE; } } - case 4: - { + case 4: { --argi; if (!strcmp(argv[argi], ls_OUT_PNG)) { convert_to = li_OUT_PNG; @@ -339,8 +373,7 @@ int main(int argc, char **argv) { return EXIT_FAILURE; } } - case 3: - { + case 3: { --argi; size_t len = strlen(argv[argi]); bool write_to_file = len > 1 && argv[argi][0] != '-'; @@ -349,7 +382,7 @@ int main(int argc, char **argv) { fputs("Unable to write image sequence to stdout, provide file prefix\n", stderr); return EXIT_FAILURE; } - if(strlen(argv[argi]) > FILENAME_MAX){ + if (strlen(argv[argi]) > FILENAME_MAX) { fputs("File name is too long", stderr); } out_file.path = argv[argi]; @@ -364,8 +397,7 @@ int main(int argc, char **argv) { } } } - case 2: - { + case 2: { --argi; size_t len = strlen(argv[argi]); if (len > 1 && argv[argi][0] != '-') { @@ -378,13 +410,13 @@ int main(int argc, char **argv) { } break; } - case 1: + default: fputs("Usage: PROG input_file|- output_file|- png|pngs|gif [resolution(128x128)] [param]\n", stderr); return EXIT_FAILURE; } byte_buffer in_file_data = bb_init(); - in_file_data.buffer = (byte *) calloc(0, sizeof (byte)); + in_file_data.buffer = (byte *) calloc(0, sizeof(byte)); if (in_file_data.buffer == NULL) { perror("Unable to init byte buffer"); fclose(in_file); @@ -397,8 +429,7 @@ int main(int argc, char **argv) { byte eos[1] = {'\0'}; bb_append(&in_file_data, eos, 1); result = convert_and_write_to(in_file_data.buffer, convert_to, w, h, param, out_file); - } - else + } else fputs("zlib error\n", stderr); free(in_file_data.buffer); diff --git a/lottie_export.h b/lottie_export.h index 52bf993..0f4e233 100644 --- a/lottie_export.h +++ b/lottie_export.h @@ -34,6 +34,8 @@ #include #include #include +#include "giflib/gif_lib.h" +#include "giflib/gif_lib_private.h" using namespace std; using namespace rlottie; From 16696cb6d80b511b105e6d1f8b9106d304d903bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0irhoe=20Biazhkovi=C4=8D?= Date: Mon, 8 Nov 2021 19:56:48 +0300 Subject: [PATCH 2/7] Move to cmake build --- .gitignore | 4 +- .gitmodules | 6 ++ CMakeLists.txt | 83 ++++++++++++++++++++ LICENSE.txt | 24 ++++++ Makefile | 128 ------------------------------ README.md | 13 +++- gif.h => gif.h_noload | 0 lib/giflib | 1 + lib/rlottie | 1 + lottie_export.cpp | 20 ----- lottie_export.h | 23 +----- memcheck.sh | 1 - nbproject/Makefile-Debug.mk | 83 -------------------- nbproject/Makefile-Release.mk | 83 -------------------- nbproject/Makefile-impl.mk | 133 -------------------------------- nbproject/Makefile-variables.mk | 35 --------- nbproject/Package-Debug.bash | 76 ------------------ nbproject/Package-Release.bash | 76 ------------------ nbproject/configurations.xml | 103 ------------------------- nbproject/project.properties | 2 - nbproject/project.xml | 28 ------- 21 files changed, 129 insertions(+), 794 deletions(-) create mode 100644 .gitmodules create mode 100644 CMakeLists.txt create mode 100644 LICENSE.txt delete mode 100644 Makefile rename gif.h => gif.h_noload (100%) create mode 160000 lib/giflib create mode 160000 lib/rlottie delete mode 100644 nbproject/Makefile-Debug.mk delete mode 100644 nbproject/Makefile-Release.mk delete mode 100644 nbproject/Makefile-impl.mk delete mode 100644 nbproject/Makefile-variables.mk delete mode 100644 nbproject/Package-Debug.bash delete mode 100644 nbproject/Package-Release.bash delete mode 100644 nbproject/configurations.xml delete mode 100644 nbproject/project.properties delete mode 100644 nbproject/project.xml diff --git a/.gitignore b/.gitignore index 59e0965..eeae5ae 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ +/.idea /build -/dist -/nbproject/private +/cmake-build* /AnimatedSticker.tgs /AnimatedSticker.json /out* diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..e5d3d40 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "3p/giflib"] + path = lib/giflib + url = https://git.code.sf.net/p/giflib/code +[submodule "3p/rlottie"] + path = lib/rlottie + url = https://github.com/Samsung/rlottie.git diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..e630a09 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,83 @@ +cmake_minimum_required(VERSION 3.18 FATAL_ERROR) +project(lottieconverter) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED True) +set(ZLIB_MINIMUM 1.2.3) +set(PNG_MINIMUM 1.6.0) +set(RL_MINIMUM 0.2) + +set(SOURCE_FILES lottie_export.cpp) +set(LIBS png zlib) +add_executable(${PROJECT_NAME} ${SOURCE_FILES}) + +option(SYSTEM_RL "Use system dynamic rlottie library instead of building static one" 0) + +find_package(ZLIB ${ZLIB_MINIMUM} REQUIRED) +find_package(PNG ${PNG_MINIMUM} REQUIRED) + +if (SYSTEM_RL) + find_path(RL_INCLUDEDIR NAMES rlottie.h HINTS ${_RL_INCLUDEDIR} REQUIRED) + find_library(RL_LIBDIR NAMES rlottie HINTS ${_RL_LIBDIR} REQUIRED) + set(LIBS ${LIBS} rlottie) +else (SYSTEM_RL) + include(ExternalProject) + ExternalProject_Add( + rlottieProject + URL "${CMAKE_SOURCE_DIR}/lib/rlottie" + ${ARGN} + PREFIX "${CMAKE_BINARY_DIR}/lib/rlottie" + CMAKE_ARGS + -Wno-dev + "-DCMAKE_TOOLCHAIN_FILE:PATH=${CMAKE_TOOLCHAIN_FILE}" + "-DCMAKE_USER_MAKE_RULES_OVERRIDE=${CMAKE_USER_MAKE_RULES_OVERRIDE}" + "-DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS}" + "-DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS}" + "-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}" + "-DCMAKE_INSTALL_PREFIX:PATH=" + "-DLOTTIE_MODULE=OFF" + "-DBUILD_SHARED_LIBS=OFF" + "-DLIB_INSTALL_DIR=${CMAKE_BINARY_DIR}/lib/rlottie" + BUILD_BYPRODUCTS "${CMAKE_BINARY_DIR}/lib/librlottie.a" + ) + ExternalProject_Get_Property(rlottieProject INSTALL_DIR) + set(RL_INCLUDEDIR "${INSTALL_DIR}/include") + add_library(rlottie STATIC IMPORTED) + add_dependencies(rlottie rlottieProject) +# set(LIBS ${LIBS} "${INSTALL_DIR}/librlottie.a") + add_dependencies(${PROJECT_NAME} rlottie) +endif (SYSTEM_RL) + +file(COPY ${CMAKE_SOURCE_DIR}/lib/giflib DESTINATION ${CMAKE_BINARY_DIR}/lib) + +add_custom_target( + giflibProject + COMMAND make libgif.a libutil.a + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/lib/giflib" + BYPRODUCTS "${CMAKE_BINARY_DIR}/lib/giflib/libgif.a" "${CMAKE_BINARY_DIR}/lib/giflib/libutil.a" +) + +add_library(giflibMain STATIC IMPORTED) +add_dependencies(giflibMain giflibProject) +set_target_properties(giflibMain + PROPERTIES IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/lib/giflib/libgif.a" +) + +add_library(giflibUtil STATIC IMPORTED) +add_dependencies(giflibUtil giflibProject) +set_target_properties(giflibUtil + PROPERTIES IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/lib/giflib/libutil.a" +) + +add_library(giflib INTERFACE IMPORTED) +set_property(TARGET giflib PROPERTY + INTERFACE_LINK_LIBRARIES giflibMain giflibUtil) +#add_dependencies(giflib giflibMain giflibUtil) + +set(LIBS ${LIBS} giflib) +add_dependencies(${PROJECT_NAME} giflib) + +include_directories("${CMAKE_BINARY_DIR}/lib/giflib" "${RL_INCLUDEDIR}") + +target_compile_options(${PROJECT_NAME} PUBLIC PRIVATE -std=c++${CMAKE_CXX_STANDARD} -Wall -O2) +target_link_libraries(${PROJECT_NAME} PUBLIC ${LIBS}) diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..3438ff0 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,24 @@ +BSD-3-Clause +Copyright 2021 sot + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. diff --git a/Makefile b/Makefile deleted file mode 100644 index 05de621..0000000 --- a/Makefile +++ /dev/null @@ -1,128 +0,0 @@ -# -# There exist several targets which are by default empty and which can be -# used for execution of your targets. These targets are usually executed -# before and after some main targets. They are: -# -# .build-pre: called before 'build' target -# .build-post: called after 'build' target -# .clean-pre: called before 'clean' target -# .clean-post: called after 'clean' target -# .clobber-pre: called before 'clobber' target -# .clobber-post: called after 'clobber' target -# .all-pre: called before 'all' target -# .all-post: called after 'all' target -# .help-pre: called before 'help' target -# .help-post: called after 'help' target -# -# Targets beginning with '.' are not intended to be called on their own. -# -# Main targets can be executed directly, and they are: -# -# build build a specific configuration -# clean remove built files from a configuration -# clobber remove all built files -# all build all configurations -# help print help mesage -# -# Targets .build-impl, .clean-impl, .clobber-impl, .all-impl, and -# .help-impl are implemented in nbproject/makefile-impl.mk. -# -# Available make variables: -# -# CND_BASEDIR base directory for relative paths -# CND_DISTDIR default top distribution directory (build artifacts) -# CND_BUILDDIR default top build directory (object files, ...) -# CONF name of current configuration -# CND_PLATFORM_${CONF} platform name (current configuration) -# CND_ARTIFACT_DIR_${CONF} directory of build artifact (current configuration) -# CND_ARTIFACT_NAME_${CONF} name of build artifact (current configuration) -# CND_ARTIFACT_PATH_${CONF} path to build artifact (current configuration) -# CND_PACKAGE_DIR_${CONF} directory of package (current configuration) -# CND_PACKAGE_NAME_${CONF} name of package (current configuration) -# CND_PACKAGE_PATH_${CONF} path to package (current configuration) -# -# NOCDDL - - -# Environment -MKDIR=mkdir -CP=cp -CCADMIN=CCadmin - - -# build -build: .build-post - -.build-pre: -# Add your pre 'build' code here... - -.build-post: .build-impl -# Add your post 'build' code here... - - -# clean -clean: .clean-post - -.clean-pre: -# Add your pre 'clean' code here... - -.clean-post: .clean-impl -# Add your post 'clean' code here... - - -# clobber -clobber: .clobber-post - -.clobber-pre: -# Add your pre 'clobber' code here... - -.clobber-post: .clobber-impl -# Add your post 'clobber' code here... - - -# all -all: .all-post - -.all-pre: -# Add your pre 'all' code here... - -.all-post: .all-impl -# Add your post 'all' code here... - - -# build tests -build-tests: .build-tests-post - -.build-tests-pre: -# Add your pre 'build-tests' code here... - -.build-tests-post: .build-tests-impl -# Add your post 'build-tests' code here... - - -# run tests -test: .test-post - -.test-pre: build-tests -# Add your pre 'test' code here... - -.test-post: .test-impl -# Add your post 'test' code here... - - -# help -help: .help-post - -.help-pre: -# Add your pre 'help' code here... - -.help-post: .help-impl -# Add your post 'help' code here... - - - -# include project implementation makefile -include nbproject/Makefile-impl.mk - -# include project make variables -include nbproject/Makefile-variables.mk diff --git a/README.md b/README.md index 97aadfc..782dff9 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,13 @@ Animation can be converted to png (with transparency) or to gif. Uses: -* [rlottie library](https://github.com/Samsung/rlottie "Samsung/rlottie") +* [rlottie library (MIT License)](https://github.com/Samsung/rlottie "Samsung/rlottie") -* [gif.h simple library](https://github.com/WohlSoft/LunaLua/blob/master/LunaDll/libs/gif-h/gif.h) +* [giflib (MIT Licence)](http://giflib.sourceforge.net) -* libpng, zlib +* [libpng (libPNG Licence)](http://www.libpng.org/pub/png/libpng.html) + +* [zlib (zlib License)](https://zlib.net) ## Usage `lottieconverter input_file|- output_file|- type [resolution] [option]` @@ -36,3 +38,8 @@ and build it inside rlottie's `"build"` subdir, just execute: LDLIBSOPTIONS_ADD="-L/home/user/rlottie/build" CXXFLAGS_ADD="-I/home/user/rlottie/inc" make CONF=Release ``` to avoid `fatal error: rlottie.h No such file or directory` error. + +## Licencing notice + +Up to v0.1.1 project has been licensed under GNU LGPL 2.1. +Actual revision is licenced under BSD-3-Clause. \ No newline at end of file diff --git a/gif.h b/gif.h_noload similarity index 100% rename from gif.h rename to gif.h_noload diff --git a/lib/giflib b/lib/giflib new file mode 160000 index 0000000..52b62de --- /dev/null +++ b/lib/giflib @@ -0,0 +1 @@ +Subproject commit 52b62de83d5facbbbde042b85bf3f61182e3bebd diff --git a/lib/rlottie b/lib/rlottie new file mode 160000 index 0000000..bf3d272 --- /dev/null +++ b/lib/rlottie @@ -0,0 +1 @@ +Subproject commit bf3d272df3916a0c34575ac8286cb0fe672fd0d4 diff --git a/lottie_export.cpp b/lottie_export.cpp index cc8590a..6f5b555 100644 --- a/lottie_export.cpp +++ b/lottie_export.cpp @@ -1,23 +1,4 @@ /* - * Copyright (C) 2019 sot. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - */ - -/* * File: lottie_export.cpp * Author: sot * @@ -25,7 +6,6 @@ */ #include "lottie_export.h" -#include "gif.h" int write_png(byte *buffer, size_t w, size_t h, FILE *out_file) { png_structp png_ptr = NULL; diff --git a/lottie_export.h b/lottie_export.h index 0f4e233..dbf57d1 100644 --- a/lottie_export.h +++ b/lottie_export.h @@ -1,23 +1,4 @@ /* - * Copyright (C) 2019 sot. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - */ - -/* * File: lottie_export.h * Author: sot * @@ -34,8 +15,8 @@ #include #include #include -#include "giflib/gif_lib.h" -#include "giflib/gif_lib_private.h" +#include "gif_lib.h" +#include "gif_lib_private.h" using namespace std; using namespace rlottie; diff --git a/memcheck.sh b/memcheck.sh index a345dc6..f693770 100755 --- a/memcheck.sh +++ b/memcheck.sh @@ -1,4 +1,3 @@ #!/bin/bash -echo "Parameters: $@" > memcheck.log valgrind --tool=memcheck --leak-check=full --show-reachable=yes --track-origins=yes -v \ dist/Debug/GNU-Linux/lottieconverter $@ 2> >(tee -a memcheck.log >&2) diff --git a/nbproject/Makefile-Debug.mk b/nbproject/Makefile-Debug.mk deleted file mode 100644 index 7b73d34..0000000 --- a/nbproject/Makefile-Debug.mk +++ /dev/null @@ -1,83 +0,0 @@ -# -# Generated Makefile - do not edit! -# -# Edit the Makefile in the project folder instead (../Makefile). Each target -# has a -pre and a -post target defined where you can add customized code. -# -# This makefile implements configuration specific macros and targets. - - -# Environment -MKDIR=mkdir -CP=cp -GREP=grep -NM=nm -CCADMIN=CCadmin -RANLIB=ranlib -CC=gcc -CCC=g++ -CXX=g++ -FC=gfortran -AS=as - -# Macros -CND_PLATFORM=GNU-Linux -CND_DLIB_EXT=so -CND_CONF=Debug -CND_DISTDIR=dist -CND_BUILDDIR=build - -# Include project Makefile -include Makefile - -# Object Directory -OBJECTDIR=${CND_BUILDDIR}/${CND_CONF}/${CND_PLATFORM} - -# Object Files -OBJECTFILES= \ - ${OBJECTDIR}/lottie_export.o - - -# C Compiler Flags -CFLAGS=${CCFLAGS_ADD} - -# CC Compiler Flags -CCFLAGS=${CXXFLAGS_ADD} -CXXFLAGS=${CXXFLAGS_ADD} - -# Fortran Compiler Flags -FFLAGS= - -# Assembler Flags -ASFLAGS= - -# Link Libraries and Options -LDLIBSOPTIONS=-lz -lpng -lrlottie ${LDLIBSOPTIONS_ADD} - -# Build Targets -.build-conf: ${BUILD_SUBPROJECTS} - "${MAKE}" -f nbproject/Makefile-${CND_CONF}.mk ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/lottieconverter - -${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/lottieconverter: ${OBJECTFILES} - ${MKDIR} -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM} - ${LINK.cc} -o ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/lottieconverter ${OBJECTFILES} ${LDLIBSOPTIONS} - -${OBJECTDIR}/lottie_export.o: lottie_export.cpp - ${MKDIR} -p ${OBJECTDIR} - ${RM} "$@.d" - $(COMPILE.cc) -g -std=c++14 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/lottie_export.o lottie_export.cpp - -# Subprojects -.build-subprojects: - -# Clean Targets -.clean-conf: ${CLEAN_SUBPROJECTS} - ${RM} -r ${CND_BUILDDIR}/${CND_CONF} - -# Subprojects -.clean-subprojects: - -# Enable dependency checking -.dep.inc: .depcheck-impl - -include .dep.inc diff --git a/nbproject/Makefile-Release.mk b/nbproject/Makefile-Release.mk deleted file mode 100644 index 1715422..0000000 --- a/nbproject/Makefile-Release.mk +++ /dev/null @@ -1,83 +0,0 @@ -# -# Generated Makefile - do not edit! -# -# Edit the Makefile in the project folder instead (../Makefile). Each target -# has a -pre and a -post target defined where you can add customized code. -# -# This makefile implements configuration specific macros and targets. - - -# Environment -MKDIR=mkdir -CP=cp -GREP=grep -NM=nm -CCADMIN=CCadmin -RANLIB=ranlib -CC=gcc -CCC=g++ -CXX=g++ -FC=gfortran -AS=as - -# Macros -CND_PLATFORM=GNU-Linux -CND_DLIB_EXT=so -CND_CONF=Release -CND_DISTDIR=dist -CND_BUILDDIR=build - -# Include project Makefile -include Makefile - -# Object Directory -OBJECTDIR=${CND_BUILDDIR}/${CND_CONF}/${CND_PLATFORM} - -# Object Files -OBJECTFILES= \ - ${OBJECTDIR}/lottie_export.o - - -# C Compiler Flags -CFLAGS=${CCFLAGS_ADD} - -# CC Compiler Flags -CCFLAGS=${CXXFLAGS_ADD} -CXXFLAGS=${CXXFLAGS_ADD} - -# Fortran Compiler Flags -FFLAGS= - -# Assembler Flags -ASFLAGS= - -# Link Libraries and Options -LDLIBSOPTIONS=-lz -lpng -lrlottie ${LDLIBSOPTIONS_ADD} - -# Build Targets -.build-conf: ${BUILD_SUBPROJECTS} - "${MAKE}" -f nbproject/Makefile-${CND_CONF}.mk ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/lottieconverter - -${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/lottieconverter: ${OBJECTFILES} - ${MKDIR} -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM} - ${LINK.cc} -o ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/lottieconverter ${OBJECTFILES} ${LDLIBSOPTIONS} - -${OBJECTDIR}/lottie_export.o: lottie_export.cpp - ${MKDIR} -p ${OBJECTDIR} - ${RM} "$@.d" - $(COMPILE.cc) -O2 -std=c++14 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/lottie_export.o lottie_export.cpp - -# Subprojects -.build-subprojects: - -# Clean Targets -.clean-conf: ${CLEAN_SUBPROJECTS} - ${RM} -r ${CND_BUILDDIR}/${CND_CONF} - -# Subprojects -.clean-subprojects: - -# Enable dependency checking -.dep.inc: .depcheck-impl - -include .dep.inc diff --git a/nbproject/Makefile-impl.mk b/nbproject/Makefile-impl.mk deleted file mode 100644 index 0056c40..0000000 --- a/nbproject/Makefile-impl.mk +++ /dev/null @@ -1,133 +0,0 @@ -# -# Generated Makefile - do not edit! -# -# Edit the Makefile in the project folder instead (../Makefile). Each target -# has a pre- and a post- target defined where you can add customization code. -# -# This makefile implements macros and targets common to all configurations. -# -# NOCDDL - - -# Building and Cleaning subprojects are done by default, but can be controlled with the SUB -# macro. If SUB=no, subprojects will not be built or cleaned. The following macro -# statements set BUILD_SUB-CONF and CLEAN_SUB-CONF to .build-reqprojects-conf -# and .clean-reqprojects-conf unless SUB has the value 'no' -SUB_no=NO -SUBPROJECTS=${SUB_${SUB}} -BUILD_SUBPROJECTS_=.build-subprojects -BUILD_SUBPROJECTS_NO= -BUILD_SUBPROJECTS=${BUILD_SUBPROJECTS_${SUBPROJECTS}} -CLEAN_SUBPROJECTS_=.clean-subprojects -CLEAN_SUBPROJECTS_NO= -CLEAN_SUBPROJECTS=${CLEAN_SUBPROJECTS_${SUBPROJECTS}} - - -# Project Name -PROJECTNAME=LottieConverter - -# Active Configuration -DEFAULTCONF=Debug -CONF=${DEFAULTCONF} - -# All Configurations -ALLCONFS=Debug Release - - -# build -.build-impl: .build-pre .validate-impl .depcheck-impl - @#echo "=> Running $@... Configuration=$(CONF)" - "${MAKE}" -f nbproject/Makefile-${CONF}.mk QMAKE=${QMAKE} SUBPROJECTS=${SUBPROJECTS} .build-conf - - -# clean -.clean-impl: .clean-pre .validate-impl .depcheck-impl - @#echo "=> Running $@... Configuration=$(CONF)" - "${MAKE}" -f nbproject/Makefile-${CONF}.mk QMAKE=${QMAKE} SUBPROJECTS=${SUBPROJECTS} .clean-conf - - -# clobber -.clobber-impl: .clobber-pre .depcheck-impl - @#echo "=> Running $@..." - for CONF in ${ALLCONFS}; \ - do \ - "${MAKE}" -f nbproject/Makefile-$${CONF}.mk QMAKE=${QMAKE} SUBPROJECTS=${SUBPROJECTS} .clean-conf; \ - done - -# all -.all-impl: .all-pre .depcheck-impl - @#echo "=> Running $@..." - for CONF in ${ALLCONFS}; \ - do \ - "${MAKE}" -f nbproject/Makefile-$${CONF}.mk QMAKE=${QMAKE} SUBPROJECTS=${SUBPROJECTS} .build-conf; \ - done - -# build tests -.build-tests-impl: .build-impl .build-tests-pre - @#echo "=> Running $@... Configuration=$(CONF)" - "${MAKE}" -f nbproject/Makefile-${CONF}.mk SUBPROJECTS=${SUBPROJECTS} .build-tests-conf - -# run tests -.test-impl: .build-tests-impl .test-pre - @#echo "=> Running $@... Configuration=$(CONF)" - "${MAKE}" -f nbproject/Makefile-${CONF}.mk SUBPROJECTS=${SUBPROJECTS} .test-conf - -# dependency checking support -.depcheck-impl: - @echo "# This code depends on make tool being used" >.dep.inc - @if [ -n "${MAKE_VERSION}" ]; then \ - echo "DEPFILES=\$$(wildcard \$$(addsuffix .d, \$${OBJECTFILES} \$${TESTOBJECTFILES}))" >>.dep.inc; \ - echo "ifneq (\$${DEPFILES},)" >>.dep.inc; \ - echo "include \$${DEPFILES}" >>.dep.inc; \ - echo "endif" >>.dep.inc; \ - else \ - echo ".KEEP_STATE:" >>.dep.inc; \ - echo ".KEEP_STATE_FILE:.make.state.\$${CONF}" >>.dep.inc; \ - fi - -# configuration validation -.validate-impl: - @if [ ! -f nbproject/Makefile-${CONF}.mk ]; \ - then \ - echo ""; \ - echo "Error: can not find the makefile for configuration '${CONF}' in project ${PROJECTNAME}"; \ - echo "See 'make help' for details."; \ - echo "Current directory: " `pwd`; \ - echo ""; \ - fi - @if [ ! -f nbproject/Makefile-${CONF}.mk ]; \ - then \ - exit 1; \ - fi - - -# help -.help-impl: .help-pre - @echo "This makefile supports the following configurations:" - @echo " ${ALLCONFS}" - @echo "" - @echo "and the following targets:" - @echo " build (default target)" - @echo " clean" - @echo " clobber" - @echo " all" - @echo " help" - @echo "" - @echo "Makefile Usage:" - @echo " make [CONF=] [SUB=no] build" - @echo " make [CONF=] [SUB=no] clean" - @echo " make [SUB=no] clobber" - @echo " make [SUB=no] all" - @echo " make help" - @echo "" - @echo "Target 'build' will build a specific configuration and, unless 'SUB=no'," - @echo " also build subprojects." - @echo "Target 'clean' will clean a specific configuration and, unless 'SUB=no'," - @echo " also clean subprojects." - @echo "Target 'clobber' will remove all built files from all configurations and," - @echo " unless 'SUB=no', also from subprojects." - @echo "Target 'all' will will build all configurations and, unless 'SUB=no'," - @echo " also build subprojects." - @echo "Target 'help' prints this message." - @echo "" - diff --git a/nbproject/Makefile-variables.mk b/nbproject/Makefile-variables.mk deleted file mode 100644 index 815e3a8..0000000 --- a/nbproject/Makefile-variables.mk +++ /dev/null @@ -1,35 +0,0 @@ -# -# Generated - do not edit! -# -# NOCDDL -# -CND_BASEDIR=`pwd` -CND_BUILDDIR=build -CND_DISTDIR=dist -# Debug configuration -CND_PLATFORM_Debug=GNU-Linux -CND_ARTIFACT_DIR_Debug=dist/Debug/GNU-Linux -CND_ARTIFACT_NAME_Debug=lottieconverter -CND_ARTIFACT_PATH_Debug=dist/Debug/GNU-Linux/lottieconverter -CND_PACKAGE_DIR_Debug=dist/Debug/GNU-Linux/package -CND_PACKAGE_NAME_Debug=lottieconverter.tar -CND_PACKAGE_PATH_Debug=dist/Debug/GNU-Linux/package/lottieconverter.tar -# Release configuration -CND_PLATFORM_Release=GNU-Linux -CND_ARTIFACT_DIR_Release=dist/Release/GNU-Linux -CND_ARTIFACT_NAME_Release=lottieconverter -CND_ARTIFACT_PATH_Release=dist/Release/GNU-Linux/lottieconverter -CND_PACKAGE_DIR_Release=dist/Release/GNU-Linux/package -CND_PACKAGE_NAME_Release=lottieconverter.tar -CND_PACKAGE_PATH_Release=dist/Release/GNU-Linux/package/lottieconverter.tar -# -# include compiler specific variables -# -# dmake command -ROOT:sh = test -f nbproject/private/Makefile-variables.mk || \ - (mkdir -p nbproject/private && touch nbproject/private/Makefile-variables.mk) -# -# gmake command -.PHONY: $(shell test -f nbproject/private/Makefile-variables.mk || (mkdir -p nbproject/private && touch nbproject/private/Makefile-variables.mk)) -# -include nbproject/private/Makefile-variables.mk diff --git a/nbproject/Package-Debug.bash b/nbproject/Package-Debug.bash deleted file mode 100644 index ab3ea5e..0000000 --- a/nbproject/Package-Debug.bash +++ /dev/null @@ -1,76 +0,0 @@ -#!/bin/bash -x - -# -# Generated - do not edit! -# - -# Macros -TOP=`pwd` -CND_PLATFORM=GNU-Linux -CND_CONF=Debug -CND_DISTDIR=dist -CND_BUILDDIR=build -CND_DLIB_EXT=so -NBTMPDIR=${CND_BUILDDIR}/${CND_CONF}/${CND_PLATFORM}/tmp-packaging -TMPDIRNAME=tmp-packaging -OUTPUT_PATH=${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/lottieconverter -OUTPUT_BASENAME=lottieconverter -PACKAGE_TOP_DIR=lottieconverter/ - -# Functions -function checkReturnCode -{ - rc=$? - if [ $rc != 0 ] - then - exit $rc - fi -} -function makeDirectory -# $1 directory path -# $2 permission (optional) -{ - mkdir -p "$1" - checkReturnCode - if [ "$2" != "" ] - then - chmod $2 "$1" - checkReturnCode - fi -} -function copyFileToTmpDir -# $1 from-file path -# $2 to-file path -# $3 permission -{ - cp "$1" "$2" - checkReturnCode - if [ "$3" != "" ] - then - chmod $3 "$2" - checkReturnCode - fi -} - -# Setup -cd "${TOP}" -mkdir -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package -rm -rf ${NBTMPDIR} -mkdir -p ${NBTMPDIR} - -# Copy files and create directories and links -cd "${TOP}" -makeDirectory "${NBTMPDIR}/lottieconverter/bin" -copyFileToTmpDir "${OUTPUT_PATH}" "${NBTMPDIR}/${PACKAGE_TOP_DIR}bin/${OUTPUT_BASENAME}" 0755 - - -# Generate tar file -cd "${TOP}" -rm -f ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/lottieconverter.tar -cd ${NBTMPDIR} -tar -vcf ../../../../${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/lottieconverter.tar * -checkReturnCode - -# Cleanup -cd "${TOP}" -rm -rf ${NBTMPDIR} diff --git a/nbproject/Package-Release.bash b/nbproject/Package-Release.bash deleted file mode 100644 index d594e84..0000000 --- a/nbproject/Package-Release.bash +++ /dev/null @@ -1,76 +0,0 @@ -#!/bin/bash -x - -# -# Generated - do not edit! -# - -# Macros -TOP=`pwd` -CND_PLATFORM=GNU-Linux -CND_CONF=Release -CND_DISTDIR=dist -CND_BUILDDIR=build -CND_DLIB_EXT=so -NBTMPDIR=${CND_BUILDDIR}/${CND_CONF}/${CND_PLATFORM}/tmp-packaging -TMPDIRNAME=tmp-packaging -OUTPUT_PATH=${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/lottieconverter -OUTPUT_BASENAME=lottieconverter -PACKAGE_TOP_DIR=lottieconverter/ - -# Functions -function checkReturnCode -{ - rc=$? - if [ $rc != 0 ] - then - exit $rc - fi -} -function makeDirectory -# $1 directory path -# $2 permission (optional) -{ - mkdir -p "$1" - checkReturnCode - if [ "$2" != "" ] - then - chmod $2 "$1" - checkReturnCode - fi -} -function copyFileToTmpDir -# $1 from-file path -# $2 to-file path -# $3 permission -{ - cp "$1" "$2" - checkReturnCode - if [ "$3" != "" ] - then - chmod $3 "$2" - checkReturnCode - fi -} - -# Setup -cd "${TOP}" -mkdir -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package -rm -rf ${NBTMPDIR} -mkdir -p ${NBTMPDIR} - -# Copy files and create directories and links -cd "${TOP}" -makeDirectory "${NBTMPDIR}/lottieconverter/bin" -copyFileToTmpDir "${OUTPUT_PATH}" "${NBTMPDIR}/${PACKAGE_TOP_DIR}bin/${OUTPUT_BASENAME}" 0755 - - -# Generate tar file -cd "${TOP}" -rm -f ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/lottieconverter.tar -cd ${NBTMPDIR} -tar -vcf ../../../../${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/lottieconverter.tar * -checkReturnCode - -# Cleanup -cd "${TOP}" -rm -rf ${NBTMPDIR} diff --git a/nbproject/configurations.xml b/nbproject/configurations.xml deleted file mode 100644 index 58ee132..0000000 --- a/nbproject/configurations.xml +++ /dev/null @@ -1,103 +0,0 @@ - - - - - lottie_export.cpp - - - gif.h - lottie_export.h - - - - - - - Makefile - - - Makefile - - - - default - true - false - - - - ${CCFLAGS_ADD} - - - 11 - ${CXXFLAGS_ADD} - - - ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/lottieconverter - - DataCompression - png - rlottie - ${LDLIBSOPTIONS_ADD} - - - - - - - - - - - - - default - true - false - - - - 5 - ${CCFLAGS_ADD} - - - 5 - 11 - ${CXXFLAGS_ADD} - - - 5 - - - 5 - - - - DataCompression - png - rlottie - ${LDLIBSOPTIONS_ADD} - - - - - - - - - - - - diff --git a/nbproject/project.properties b/nbproject/project.properties deleted file mode 100644 index 2a704dd..0000000 --- a/nbproject/project.properties +++ /dev/null @@ -1,2 +0,0 @@ -#Thu Sep 26 20:44:18 MSK 2019 -project.license=lgpl21 diff --git a/nbproject/project.xml b/nbproject/project.xml deleted file mode 100644 index 3b96c79..0000000 --- a/nbproject/project.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - org.netbeans.modules.cnd.makeproject - - - LottieConverter - - cpp - h - UTF-8 - - - - - Debug - 1 - - - Release - 1 - - - - false - - - - From ef6e4c6b3f0b7b1390ce34ccf857916b0e566c1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0irhoe=20Biazhkovi=C4=8D?= Date: Tue, 9 Nov 2021 01:20:18 +0300 Subject: [PATCH 3/7] Alpha works TODO: sanitise code and recheck memory leaks OPTIONAL: byte_buffer -> vector --- CMakeLists.txt | 35 ++++---- lottie_export.cpp | 216 ++++++++++++++++++++++++++++------------------ lottie_export.h | 37 +++++--- 3 files changed, 178 insertions(+), 110 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e630a09..6924203 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,10 +7,17 @@ set(ZLIB_MINIMUM 1.2.3) set(PNG_MINIMUM 1.6.0) set(RL_MINIMUM 0.2) +set(COMPILE_PARAMS -Wall) set(SOURCE_FILES lottie_export.cpp) -set(LIBS png zlib) +set(LIBS png z) add_executable(${PROJECT_NAME} ${SOURCE_FILES}) +if (CMAKE_BUILD_TYPE EQUAL "RELEASE") + set(COMPILE_PARAMS ${COMPILE_PARAMS} -O2) +else(CMAKE_BUILD_TYPE) + set(COMPILE_PARAMS ${COMPILE_PARAMS} -O0 -g3) +endif() + option(SYSTEM_RL "Use system dynamic rlottie library instead of building static one" 0) find_package(ZLIB ${ZLIB_MINIMUM} REQUIRED) @@ -23,7 +30,7 @@ if (SYSTEM_RL) else (SYSTEM_RL) include(ExternalProject) ExternalProject_Add( - rlottieProject + rlottie URL "${CMAKE_SOURCE_DIR}/lib/rlottie" ${ARGN} PREFIX "${CMAKE_BINARY_DIR}/lib/rlottie" @@ -38,13 +45,11 @@ else (SYSTEM_RL) "-DLOTTIE_MODULE=OFF" "-DBUILD_SHARED_LIBS=OFF" "-DLIB_INSTALL_DIR=${CMAKE_BINARY_DIR}/lib/rlottie" - BUILD_BYPRODUCTS "${CMAKE_BINARY_DIR}/lib/librlottie.a" + BUILD_BYPRODUCTS "${CMAKE_BINARY_DIR}/librlottie.a" ) - ExternalProject_Get_Property(rlottieProject INSTALL_DIR) + ExternalProject_Get_Property(rlottie INSTALL_DIR) set(RL_INCLUDEDIR "${INSTALL_DIR}/include") - add_library(rlottie STATIC IMPORTED) - add_dependencies(rlottie rlottieProject) -# set(LIBS ${LIBS} "${INSTALL_DIR}/librlottie.a") + set(LIBS ${LIBS} pthread "${INSTALL_DIR}/librlottie.a") add_dependencies(${PROJECT_NAME} rlottie) endif (SYSTEM_RL) @@ -57,21 +62,21 @@ add_custom_target( BYPRODUCTS "${CMAKE_BINARY_DIR}/lib/giflib/libgif.a" "${CMAKE_BINARY_DIR}/lib/giflib/libutil.a" ) -add_library(giflibMain STATIC IMPORTED) -add_dependencies(giflibMain giflibProject) -set_target_properties(giflibMain - PROPERTIES IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/lib/giflib/libgif.a" -) - add_library(giflibUtil STATIC IMPORTED) add_dependencies(giflibUtil giflibProject) set_target_properties(giflibUtil PROPERTIES IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/lib/giflib/libutil.a" + ) + +add_library(giflibMain STATIC IMPORTED) +add_dependencies(giflibMain giflibProject) +set_target_properties(giflibMain + PROPERTIES IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/lib/giflib/libgif.a" ) add_library(giflib INTERFACE IMPORTED) set_property(TARGET giflib PROPERTY - INTERFACE_LINK_LIBRARIES giflibMain giflibUtil) + INTERFACE_LINK_LIBRARIES giflibUtil giflibMain) #add_dependencies(giflib giflibMain giflibUtil) set(LIBS ${LIBS} giflib) @@ -79,5 +84,5 @@ add_dependencies(${PROJECT_NAME} giflib) include_directories("${CMAKE_BINARY_DIR}/lib/giflib" "${RL_INCLUDEDIR}") -target_compile_options(${PROJECT_NAME} PUBLIC PRIVATE -std=c++${CMAKE_CXX_STANDARD} -Wall -O2) +target_compile_options(${PROJECT_NAME} PUBLIC PRIVATE -std=c++${CMAKE_CXX_STANDARD} ${COMPILE_PARAMS}) target_link_libraries(${PROJECT_NAME} PUBLIC ${LIBS}) diff --git a/lottie_export.cpp b/lottie_export.cpp index 6f5b555..eaa1f92 100644 --- a/lottie_export.cpp +++ b/lottie_export.cpp @@ -8,19 +8,19 @@ #include "lottie_export.h" int write_png(byte *buffer, size_t w, size_t h, FILE *out_file) { - png_structp png_ptr = NULL; - png_infop info_ptr = NULL; - png_byte **row_pointers = NULL; + png_structp png_ptr = nullptr; + png_infop info_ptr = nullptr; + png_byte **row_pointers; - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (png_ptr == NULL) { + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + if (png_ptr == nullptr) { fputs("PNG export failed: unable to create structure\n", stderr); return EXIT_FAILURE; } info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == NULL) { + if (info_ptr == nullptr) { png_destroy_write_struct(&png_ptr, &info_ptr); fputs("PNG export failed: unable to create info data\n", stderr); return EXIT_FAILURE; @@ -37,16 +37,16 @@ int write_png(byte *buffer, size_t w, size_t h, FILE *out_file) { PNG_FILTER_TYPE_DEFAULT); row_pointers = (png_byte **) png_malloc(png_ptr, h * sizeof(png_byte *)); - if (row_pointers == NULL) { + if (row_pointers == nullptr) { png_destroy_write_struct(&png_ptr, &info_ptr); perror("PNG export failed\n"); return EXIT_FAILURE; } - for (int y = 0; y < h; ++y) { - png_byte *row = (png_byte *) png_malloc(png_ptr, sizeof(byte) * w * lp_COLOR_BYTES); - if (row == NULL) { + for (unsigned int y = 0; y < h; ++y) { + auto *row = (png_byte *) png_malloc(png_ptr, sizeof(byte) * w * lp_COLOR_BYTES); + if (row == nullptr) { perror("PNG export failed\n"); - for (int yy = 0; yy < y; ++yy) { + for (unsigned int yy = 0; yy < y; ++yy) { png_free(png_ptr, row_pointers[yy]); } png_free(png_ptr, row_pointers); @@ -54,7 +54,7 @@ int write_png(byte *buffer, size_t w, size_t h, FILE *out_file) { return EXIT_FAILURE; } row_pointers[y] = row; - for (int x = 0; x < w; x++) { + for (unsigned int x = 0; x < w; x++) { byte b, g, r; b = *buffer++; g = *buffer++; @@ -68,9 +68,9 @@ int write_png(byte *buffer, size_t w, size_t h, FILE *out_file) { png_set_rows(png_ptr, info_ptr, row_pointers); png_init_io(png_ptr, out_file); - png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); + png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, nullptr); - for (int y = 0; y < h; ++y) { + for (unsigned int y = 0; y < h; ++y) { png_free(png_ptr, row_pointers[y]); } png_free(png_ptr, row_pointers); @@ -78,7 +78,8 @@ int write_png(byte *buffer, size_t w, size_t h, FILE *out_file) { return EXIT_SUCCESS; } -int convert_and_write_to(byte *in_file_data, uint8_t convert_to, size_t w, size_t h, uint32_t param, file out_file) { +int convert_and_write_to(byte *in_file_data, uint8_t convert_to, int w, int h, uint32_t param, file *out_file) { + int status = EXIT_SUCCESS; string data(reinterpret_cast (in_file_data)); unique_ptr animation = Animation::loadFromData(data, "", "", false); if (!animation) { @@ -87,7 +88,7 @@ int convert_and_write_to(byte *in_file_data, uint8_t convert_to, size_t w, size_ } size_t frame_count = animation->totalFrame(); unique_ptr buffer = unique_ptr(new uint32_t[w * h]); - if (buffer == nullptr || buffer.get() == nullptr) { + if (buffer == nullptr) { fputs("Unable to init frame buffer\n", stderr); return EXIT_FAILURE; } @@ -97,41 +98,40 @@ int convert_and_write_to(byte *in_file_data, uint8_t convert_to, size_t w, size_ if (frame_to_extract > frame_count - 1) frame_to_extract = frame_count - 1; Surface surface(buffer.get(), w, h, w * lp_COLOR_BYTES); animation->renderSync(frame_to_extract, surface); - return write_png(reinterpret_cast (buffer.get()), w, h, out_file.file_pointer); + return write_png(reinterpret_cast (buffer.get()), w, h, out_file->file_pointer); } case li_OUT_PNGS: { float ratio = (float) animation->frameRate() / param; - size_t frame_count_out = frame_count / ratio, file_template_len = - strlen(out_file.path) + strlen(ls_OUT_PNGS_SUFFIX) + 1; + size_t frame_count_out = frame_count / ratio; size_t frame_count_out_t = frame_count_out; unsigned int digit_count = 1, frame_number = 0; while (frame_count_out_t > 9) { frame_count_out_t /= 10; ++digit_count; } - char *file_name_template = (char *) calloc(file_template_len, sizeof(char)), - *file_name = (char *) calloc(file_template_len + digit_count, sizeof(char)); + char *file_name_template = (char *) calloc(FILENAME_MAX, sizeof(char)), + *file_name = (char *) calloc(FILENAME_MAX, sizeof(char)); int result = EXIT_SUCCESS; - if (file_name_template == NULL || file_name == NULL) { - if (file_name_template != NULL) free(file_name_template); - if (file_name != NULL) free(file_name); + if (file_name_template == nullptr || file_name == nullptr) { + if (file_name_template != nullptr) free(file_name_template); + if (file_name != nullptr) free(file_name); perror("Unable to convert to png sequence, possibly prefix too long\n"); return EXIT_FAILURE; } - memset(file_name_template, '\0', file_template_len); - strncpy(file_name_template, out_file.path, strlen(out_file.path)); - strncat(file_name_template, ls_OUT_PNGS_SUFFIX, file_template_len); + memset(file_name_template, '\0', FILENAME_MAX); + strncpy(file_name_template, out_file->path, FILENAME_MAX); + strncat(file_name_template, ls_OUT_PNGS_SUFFIX, FILENAME_MAX); for (float frame_current = 0.0f; frame_current < (float) frame_count; frame_current += ratio) { - FILE *fp = NULL; - memset(file_name, '\0', file_template_len + digit_count); - snprintf(file_name, file_template_len + digit_count, file_name_template, digit_count, frame_number++); - if ((fp = fopen(file_name, "wb")) == NULL) { + FILE *fp = nullptr; + memset(file_name, '\0', FILENAME_MAX); + snprintf(file_name, FILENAME_MAX, file_name_template, digit_count, frame_number++); + if ((fp = fopen(file_name, "wb")) == nullptr) { perror("Unable to write png frame\n"); result = EXIT_FAILURE; break; } Surface surface(buffer.get(), w, h, w * lp_COLOR_BYTES); - animation->renderSync((size_t) (frame_current + 0.5f), surface); + animation->renderSync(lround(frame_current), surface); result = write_png(reinterpret_cast (buffer.get()), w, h, fp); fclose(fp); if (result != EXIT_SUCCESS) { @@ -143,86 +143,139 @@ int convert_and_write_to(byte *in_file_data, uint8_t convert_to, size_t w, size_ return result; } case li_OUT_GIF: { - byte a_thr = param & 0xff; int error_code = 0; - GifFileType *writer = EGifOpen(NULL, NULL, &error_code); - if (writer == NULL || error_code != 0) { + GifFileType *writer = EGifOpen(nullptr, nullptr, &error_code); + if (writer == nullptr || error_code != 0) { fprintf(stderr, "Unable to initialize GIF writer, error code: %d\n", error_code); return EXIT_FAILURE; } int frame_to_extract = (int) (animation->frameRate() / 10); - ColorMapObject *outputPalette = GifMakeMapObject(1 << lp_COLOR_DEPTH, NULL); - ((GifFilePrivateType *) writer->Private)->File = out_file.file_pointer; + int color_map_size = 1 << lp_COLOR_DEPTH; + ColorMapObject *output_palette = GifMakeMapObject(color_map_size, nullptr); + ((GifFilePrivateType *) writer->Private)->File = out_file->file_pointer; EGifSetGifVersion(writer, true); if (EGifPutScreenDesc( writer, w, h, lp_COLOR_DEPTH, 0, - outputPalette + output_palette ) == GIF_ERROR) { fputs("Something went wrong while creating gif\n", stderr); return EXIT_FAILURE; } - if(EGifPutImageDesc(writer, - 0, 0, w, h, false, NULL) == GIF_ERROR){ - fputs("Unable to write gif structure\n", stderr); - return EXIT_FAILURE; - } byte loop[]{1, 0, 0}; if (EGifPutExtensionLeader(writer, APPLICATION_EXT_FUNC_CODE) == GIF_ERROR) { - fputs("Unable to write gif structure\n", stderr); + fputs("Unable to write gif extension\n", stderr); return EXIT_FAILURE; } if (EGifPutExtensionBlock(writer, 11, "NETSCAPE2.0") == GIF_ERROR) { - fputs("Unable to write gif structure\n", stderr); + fputs("Unable to write gif extension\n", stderr); return EXIT_FAILURE; } if (EGifPutExtensionBlock(writer, 3, loop) == GIF_ERROR) { - fputs("Unable to write gif structure\n", stderr); + fputs("Unable to write gif extension\n", stderr); return EXIT_FAILURE; } if (EGifPutExtensionTrailer(writer) == GIF_ERROR) { - fputs("Unable to write gif structure\n", stderr); + fputs("Unable to write gif extension\n", stderr); return EXIT_FAILURE; } - for (int frame_current = 0; frame_current < frame_count; frame_current += frame_to_extract) { + for (size_t frame_current = 0; + frame_current < frame_count && status == EXIT_SUCCESS; frame_current += frame_to_extract) { Surface surface(buffer.get(), w, h, w * lp_COLOR_BYTES); animation->renderSync(frame_current, surface); - byte *byte_buffer_raw = reinterpret_cast (buffer.get()); - byte *byte_buffer_exch = byte_buffer_raw, *byte_buffer_start = byte_buffer_raw; + auto *byte_buffer_raw = reinterpret_cast (buffer.get()); size_t pixel_count = w * h; - for (int i = 0; i < pixel_count; ++i) { + byte *rb = (byte *)calloc(pixel_count, sizeof(byte)), + *gb = (byte *)calloc(pixel_count, sizeof(byte)), + *bb = (byte *)calloc(pixel_count, sizeof(byte)), + *out = (byte *)calloc(pixel_count, sizeof(byte)); + if (rb == nullptr || gb == nullptr || bb == nullptr || out == nullptr) { + perror("Unable to init byte buffer"); + if(rb != nullptr) free(rb); + if(gb != nullptr) free(gb); + if(bb != nullptr) free(bb); + if(out != nullptr) free(out); + status = EXIT_FAILURE; + break; + } + for (size_t i = 0; i < pixel_count; ++i) { byte b, g, r, a; b = *byte_buffer_raw++; g = *byte_buffer_raw++; r = *byte_buffer_raw++; a = *byte_buffer_raw++; - if (a <= a_thr) { - b = 0; - g = 0; - r = 0; - a = kGifTransIndex; + if (a) { + if (a != 0xFF) { + r += (byte) (((float) r) * (float) (0xFF - a) / 255.0f); + g += (byte) (((float) g) * (float) (0xFF - a) / 255.0f); + b += (byte) (((float) b) * (float) (0xFF - a) / 255.0f); + } + } else { + r = g = b = 0; //background } - *byte_buffer_exch++ = r; - *byte_buffer_exch++ = g; - *byte_buffer_exch++ = b; - *byte_buffer_exch++ = a; + rb[i] = r; + gb[i] = g; + bb[i] = b; } - //EGifPutLine(GifFile, &(frames[ni][j]), gifsx) - if (!GifWriteFrame(&writer, byte_buffer_start, w, h, 1, lp_COLOR_DEPTH)) { - fputs("Something went wrong while appending gif frame\n", stderr); + error_code = GifQuantizeBuffer(w, h, &output_palette->ColorCount, + rb, gb, bb, + out, output_palette->Colors); + free(rb); + free(gb); + free(bb); + if(error_code != GIF_OK){ + free(out); + fputs("Unable quantize gif colors\n", stderr); + status = EXIT_FAILURE; break; } + byte *line_buffer = out; + static unsigned char delay[4] = {0x0D, // Bit 0 - flag if transparent index given (checked), + // Bit 1 - User Input Flag (unchecked), + // Bits 2-4 - Disposal Method: + // 0 - unspecified, + // 1 - don't dispose, + // 2 - restore to background color, + // 3 - restore to previous (checked) + 10, // >Hundredths of + 0, // seconds to wait< + 0}; // Transparent color index //TODO: try to calculate + if(EGifPutExtension(writer, GRAPHICS_EXT_FUNC_CODE, 4, delay) == GIF_OK) { + if (EGifPutImageDesc(writer, 0, 0, w, h, false, output_palette) == GIF_OK) { + for (int line = 0; line < h; ++line) { + if (EGifPutLine(writer, line_buffer, w) != GIF_OK) { + fputs("Unable to write GIF line\n", stderr); + status = EXIT_FAILURE; + break; + } + line_buffer += w; + } + } else{ + fputs("Unable to write gif image info\n", stderr); + status = EXIT_FAILURE; + } + } else { + fputs("Unable to write gif extension\n", stderr); + status = EXIT_FAILURE; + } + free(out); + } + if (EGifCloseFile(writer, &error_code) != GIF_OK) { + fprintf(stderr, "Unable to finalize GIF writer, error code: %d\n", error_code); + status = EXIT_FAILURE; } - //EGifCloseFile(GifFile) - GifEnd(&writer); + //already closed by EGifCloseFile + out_file->file_pointer = nullptr; break; } + default: + break; } - return EXIT_SUCCESS; + return status; } int unzip(FILE *in_file, byte_buffer *out_data) { - z_stream strm = {0}; + z_stream strm = {nullptr}; byte in[lz_CHUNK_SIZE]; byte out[lz_CHUNK_SIZE]; bool first_read = true; @@ -305,31 +358,31 @@ int main(int argc, char **argv) { uint32_t param = 1; uint8_t convert_to = li_OUT_PNG; - size_t w = 128, h = 128; + unsigned long w = 128, h = 128; FILE *in_file = stdin; - file out_file = file_init(stdout, NULL); + file out_file = file(stdout, nullptr); int argi = argc; switch (argc) { case 6: --argi; - param = strtoul(argv[argi], NULL, 0); + param = strtoul(argv[argi], nullptr, 0); case 5: { --argi; size_t len = strlen(argv[argi]); size_t index_of_x = strcspn(argv[argi], "x"); if (len > 3 && index_of_x > 0 && index_of_x < len - 1) { char *res = (char *) calloc(len, sizeof(char)); - if (res == NULL) { + if (res == nullptr) { perror("Resolution error"); return EXIT_FAILURE; } memset(res, '\0', len); strncpy(res, argv[argi], index_of_x); - w = strtoul(argv[argi], NULL, 10); + w = strtoul(argv[argi], nullptr, 10); ++index_of_x; memset(res, '\0', len); strncpy(res, argv[argi] + index_of_x, len - index_of_x); - h = strtoul(argv[argi], NULL, 10); + h = strtoul(argv[argi], nullptr, 10); free(res); if (h == 0 || w == 0 || h > li_MAX_DIMENSION || w > li_MAX_DIMENSION) { fputs("Invalid resolution\n", stderr); @@ -366,12 +419,12 @@ int main(int argc, char **argv) { fputs("File name is too long", stderr); } out_file.path = argv[argi]; - out_file.file_pointer = NULL; + out_file.file_pointer = nullptr; } else { if (write_to_file) { out_file.file_pointer = fopen(argv[argi], "wb"); } - if (out_file.file_pointer == NULL) { + if (out_file.file_pointer == nullptr) { perror(argv[argi]); return EXIT_FAILURE; } @@ -385,7 +438,7 @@ int main(int argc, char **argv) { } if (!in_file) { perror(argv[argi]); - file_close(out_file); + out_file.close(); return EXIT_FAILURE; } break; @@ -395,12 +448,12 @@ int main(int argc, char **argv) { return EXIT_FAILURE; } - byte_buffer in_file_data = bb_init(); + byte_buffer in_file_data = byte_buffer(); in_file_data.buffer = (byte *) calloc(0, sizeof(byte)); - if (in_file_data.buffer == NULL) { + if (in_file_data.buffer == nullptr) { perror("Unable to init byte buffer"); fclose(in_file); - file_close(out_file); + out_file.close(); return EXIT_FAILURE; } int result = unzip(in_file, &in_file_data); @@ -408,13 +461,12 @@ int main(int argc, char **argv) { if (result == EXIT_SUCCESS) { byte eos[1] = {'\0'}; bb_append(&in_file_data, eos, 1); - result = convert_and_write_to(in_file_data.buffer, convert_to, w, h, param, out_file); + result = convert_and_write_to(in_file_data.buffer, convert_to, (int)w, (int)h, param, &out_file); } else fputs("zlib error\n", stderr); free(in_file_data.buffer); - file_close(out_file); + out_file.close(); return result; } - diff --git a/lottie_export.h b/lottie_export.h index dbf57d1..bc54bbd 100644 --- a/lottie_export.h +++ b/lottie_export.h @@ -8,16 +8,23 @@ #ifndef LOTTIE_EXPORT_H #define LOTTIE_EXPORT_H -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include #include "gif_lib.h" #include "gif_lib_private.h" +//include from getarg.h +extern "C" int GifQuantizeBuffer(unsigned int Width, unsigned int Height, + int *ColorMapSize, GifByteType * RedInput, + GifByteType * GreenInput, GifByteType * BlueInput, + GifByteType * OutputBuffer, + GifColorType * OutputColorMap); + using namespace std; using namespace rlottie; @@ -49,21 +56,28 @@ using namespace rlottie; typedef uint8_t byte; struct byte_buffer { - byte * buffer = NULL; + byte_buffer()=default; + byte * buffer = nullptr; size_t size = 0; }; struct file { - FILE * file_pointer = NULL; - char * path = NULL; -}; + FILE * file_pointer = nullptr; + char * path = nullptr; -#define bb_init() {.buffer = NULL, .size = 0} + file(FILE * fd, char * p){ + file_pointer = fd; + path = p; + } + void close() const{ + if (file_pointer != nullptr) fclose(file_pointer); + } +}; int bb_append(byte_buffer * bb, byte * data, size_t data_size) { bb->buffer = (byte *) realloc(bb->buffer, (bb->size + data_size) * sizeof (byte)); - if (bb->buffer == NULL) { + if (bb->buffer == nullptr) { perror("Unable to extend byte buffer"); return EXIT_FAILURE; } @@ -73,8 +87,5 @@ int bb_append(byte_buffer * bb, byte * data, size_t data_size) { return EXIT_SUCCESS; } -#define file_init(_fp_, _path_) { .file_pointer = (_fp_), .path = (_path_) } -#define file_close(_file_) { if ((_file_).file_pointer != NULL) fclose((_file_).file_pointer); } - #endif /* LOTTIE_EXPORT_H */ From 2624a7bfdc592abf1072c814b0b42f8e015fe5ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0irhoe=20Biazhkovi=C4=8D?= Date: Fri, 12 Nov 2021 01:20:08 +0300 Subject: [PATCH 4/7] Add libpng external library * Update README * Remove gif.h library --- .gitignore | 1 + .gitmodules | 5 +- CMakeLists.txt | 112 ++++-- README.md | 31 +- gif.h_noload | 819 ---------------------------------------- lib/libpng | 1 + lottie_export.cpp | 68 ++-- lottie_export.h | 4 +- memcheck.log | 929 ++++++++++++++++++++++++++++++++++++++++++++++ memcheck.sh | 2 +- 10 files changed, 1075 insertions(+), 897 deletions(-) delete mode 100644 gif.h_noload create mode 160000 lib/libpng diff --git a/.gitignore b/.gitignore index eeae5ae..e9a33a9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ /.idea /build +/dist /cmake-build* /AnimatedSticker.tgs /AnimatedSticker.json diff --git a/.gitmodules b/.gitmodules index e5d3d40..536cac6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,9 @@ [submodule "3p/giflib"] path = lib/giflib - url = https://git.code.sf.net/p/giflib/code + url = git://git.code.sf.net/p/giflib/code [submodule "3p/rlottie"] path = lib/rlottie url = https://github.com/Samsung/rlottie.git +[submodule "3p/libpng"] + path = lib/libpng + url = git://git.code.sf.net/p/libpng/code diff --git a/CMakeLists.txt b/CMakeLists.txt index 6924203..67ce929 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,15 +1,17 @@ cmake_minimum_required(VERSION 3.18 FATAL_ERROR) project(lottieconverter) +include(ExternalProject) +include(FindPackageMessage) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED True) set(ZLIB_MINIMUM 1.2.3) set(PNG_MINIMUM 1.6.0) -set(RL_MINIMUM 0.2) set(COMPILE_PARAMS -Wall) set(SOURCE_FILES lottie_export.cpp) -set(LIBS png z) +set(LIBS z) +set(INCLUDES) add_executable(${PROJECT_NAME} ${SOURCE_FILES}) if (CMAKE_BUILD_TYPE EQUAL "RELEASE") @@ -18,17 +20,47 @@ else(CMAKE_BUILD_TYPE) set(COMPILE_PARAMS ${COMPILE_PARAMS} -O0 -g3) endif() +option(SYSTEM_PNG "Use system dynamic png library instead of building static one" 1) option(SYSTEM_RL "Use system dynamic rlottie library instead of building static one" 0) +option(SYSTEM_GL "Use system dynamic giflib library instead of building static one" 0) find_package(ZLIB ${ZLIB_MINIMUM} REQUIRED) -find_package(PNG ${PNG_MINIMUM} REQUIRED) + +if(SYSTEM_PNG) + find_package(PNG ${PNG_MINIMUM} REQUIRED) + set(LIBS ${LIBS} png) +else() + message(NOTICE "-- Building static libpng") + ExternalProject_Add( + png + URL "${CMAKE_SOURCE_DIR}/lib/libpng" + ${ARGN} + PREFIX "${CMAKE_BINARY_DIR}/lib/libpng" + CMAKE_ARGS + -Wno-dev + "-DCMAKE_TOOLCHAIN_FILE:PATH=${CMAKE_TOOLCHAIN_FILE}" + "-DCMAKE_USER_MAKE_RULES_OVERRIDE=${CMAKE_USER_MAKE_RULES_OVERRIDE}" + "-DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS}" + "-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}" + "-DCMAKE_INSTALL_PREFIX:PATH=" + "-DBUILD_SHARED_LIBS=OFF" + "-DPNG_SHARED=OFF" + "-DPNG_TESTS=OFF" + "-DCMAKE_INSTALL_LIBDIR=${CMAKE_BINARY_DIR}/lib/libpng" + BUILD_BYPRODUCTS "${CMAKE_BINARY_DIR}/lib/libpng/libpng.a" + ) + set(INCLUDES ${INCLUDES} "${CMAKE_BINARY_DIR}/lib/libpng/include") + set(LIBS ${LIBS} pthread "${CMAKE_BINARY_DIR}/lib/libpng/libpng.a") + add_dependencies(${PROJECT_NAME} png) +endif() if (SYSTEM_RL) find_path(RL_INCLUDEDIR NAMES rlottie.h HINTS ${_RL_INCLUDEDIR} REQUIRED) find_library(RL_LIBDIR NAMES rlottie HINTS ${_RL_LIBDIR} REQUIRED) - set(LIBS ${LIBS} rlottie) -else (SYSTEM_RL) - include(ExternalProject) + find_package_message(rlottie "Found RLOTTIE: ${RL_LIBDIR}" "_") + set(LIBS ${LIBS} "${RL_LIBDIR}") +else () + message(NOTICE "-- Building static rlottie") ExternalProject_Add( rlottie URL "${CMAKE_SOURCE_DIR}/lib/rlottie" @@ -45,44 +77,54 @@ else (SYSTEM_RL) "-DLOTTIE_MODULE=OFF" "-DBUILD_SHARED_LIBS=OFF" "-DLIB_INSTALL_DIR=${CMAKE_BINARY_DIR}/lib/rlottie" - BUILD_BYPRODUCTS "${CMAKE_BINARY_DIR}/librlottie.a" + BUILD_BYPRODUCTS "${CMAKE_BINARY_DIR}/lib/rlottie/librlottie.a" ) - ExternalProject_Get_Property(rlottie INSTALL_DIR) - set(RL_INCLUDEDIR "${INSTALL_DIR}/include") - set(LIBS ${LIBS} pthread "${INSTALL_DIR}/librlottie.a") + set(INCLUDES ${INCLUDES} "${CMAKE_BINARY_DIR}/lib/rlottie/include") + set(LIBS ${LIBS} pthread "${CMAKE_BINARY_DIR}/lib/rlottie/librlottie.a") add_dependencies(${PROJECT_NAME} rlottie) -endif (SYSTEM_RL) +endif () -file(COPY ${CMAKE_SOURCE_DIR}/lib/giflib DESTINATION ${CMAKE_BINARY_DIR}/lib) +if(SYSTEM_GL) + find_path(GL_INCLUDEDIR NAMES gif_lib.h HINTS ${_GL_INCLUDEDIR} REQUIRED) + find_library(GL_LIBDIR NAMES gif HINTS ${_GL_LIBDIR} REQUIRED) + find_package_message(gif "Found GIF: ${GL_LIBDIR}" "_") + set(LIBS ${LIBS} "${GL_LIBDIR}") +else() + message(NOTICE "-- Building static giflib") + file(COPY ${CMAKE_SOURCE_DIR}/lib/giflib DESTINATION ${CMAKE_BINARY_DIR}/lib) -add_custom_target( - giflibProject - COMMAND make libgif.a libutil.a - WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/lib/giflib" - BYPRODUCTS "${CMAKE_BINARY_DIR}/lib/giflib/libgif.a" "${CMAKE_BINARY_DIR}/lib/giflib/libutil.a" -) + add_custom_target( + giflibProject + COMMAND make libgif.a libutil.a + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/lib/giflib" + BYPRODUCTS "${CMAKE_BINARY_DIR}/lib/giflib/libgif.a" "${CMAKE_BINARY_DIR}/lib/giflib/libutil.a" + ) -add_library(giflibUtil STATIC IMPORTED) -add_dependencies(giflibUtil giflibProject) -set_target_properties(giflibUtil - PROPERTIES IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/lib/giflib/libutil.a" - ) + add_library(giflibUtil STATIC IMPORTED) + add_dependencies(giflibUtil giflibProject) + set_target_properties(giflibUtil + PROPERTIES IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/lib/giflib/libutil.a" + ) -add_library(giflibMain STATIC IMPORTED) -add_dependencies(giflibMain giflibProject) -set_target_properties(giflibMain - PROPERTIES IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/lib/giflib/libgif.a" -) + add_library(giflibMain STATIC IMPORTED) + add_dependencies(giflibMain giflibProject) + set_target_properties(giflibMain + PROPERTIES IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/lib/giflib/libgif.a" + ) -add_library(giflib INTERFACE IMPORTED) -set_property(TARGET giflib PROPERTY - INTERFACE_LINK_LIBRARIES giflibUtil giflibMain) -#add_dependencies(giflib giflibMain giflibUtil) + add_library(giflib INTERFACE IMPORTED) + set_property(TARGET giflib PROPERTY + INTERFACE_LINK_LIBRARIES giflibUtil giflibMain) + #add_dependencies(giflib giflibMain giflibUtil) -set(LIBS ${LIBS} giflib) -add_dependencies(${PROJECT_NAME} giflib) + set(LIBS ${LIBS} giflib) + add_dependencies(${PROJECT_NAME} giflib) + set(INCLUDES "${INCLUDES}" "${CMAKE_BINARY_DIR}/lib/giflib") +endif() -include_directories("${CMAKE_BINARY_DIR}/lib/giflib" "${RL_INCLUDEDIR}") +if(INCLUDES) + include_directories(${INCLUDES}) +endif() target_compile_options(${PROJECT_NAME} PUBLIC PRIVATE -std=c++${CMAKE_CXX_STANDARD} ${COMPILE_PARAMS}) target_link_libraries(${PROJECT_NAME} PUBLIC ${LIBS}) diff --git a/README.md b/README.md index 782dff9..a253c91 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Uses: * [giflib (MIT Licence)](http://giflib.sourceforge.net) -* [libpng (libPNG Licence)](http://www.libpng.org/pub/png/libpng.html) +* [libpng (zlib/libpng Licence)](http://www.libpng.org/pub/png/libpng.html) * [zlib (zlib License)](https://zlib.net) @@ -22,22 +22,29 @@ Parameters: * output_file - file to be written, if set `-` stdout is used, **note, that for `pngs` type, file name prefix is required** * type - output format, currently supported: `png`, `gif`, `pngs` * resolution - size in pixels of out image, shoul be in `SIZExSIZE` format, default `128x128` -* option - depends of type, default 0 for all: +* option - depends of type, default 1 for all: * `png` - which frame in percents to extract, i.e. if set to `20`, and there's 200 frames in animation, 40th frame will be extracted * `pngs` - frame rate to try to extract images, i.e. if animation framerate is 30, and `option` set to 10 every 3rd frame will be extracted, if animation frame rate is 10, and `option` set to 30 every frame will be written 3 times - * `gif` - background color (RGB) to be set unstead fully transparent pixels, format must be same as C constant representation (`12345`, `0x123abc`, `01267` etc.) + * `gif` - unused ## Build -Just execute `make CONF=Release` for release build (with -O2 optimization), or `make CONF=Debug` for debug. -You can also set additional variables for c++ compiler (`CXXFLAGS_ADD`) and linker (`LDLIBSOPTIONS_ADD`), i.e.: -If rlottie headers and library not installed to system default search directories, -but you have downloaded it's [source](https://github.com/Samsung/rlottie) to `/home/user/rlottie` -and build it inside rlottie's `"build"` subdir, just execute: -```bash -LDLIBSOPTIONS_ADD="-L/home/user/rlottie/build" CXXFLAGS_ADD="-I/home/user/rlottie/inc" make CONF=Release -``` -to avoid `fatal error: rlottie.h No such file or directory` error. +1. Clone this repo or download sources from releases page +2. If cloned AND you need included `libpng`, `rlottie` or `giflib` fetch submodules +by executing `git submodule update --init` +3. Execute CMake build: + 1. `mkdir build && cd build` + 2. `cmake -DCMAKE_BUILD_TYPE=Release .. && cmake --build .` +4. Copy or execute ready `lottieconverter` in `build` subdirectory. + +## Additional build options +By default, project uses system's shared `libpng` library and header, +static `rlottie` and `libgif`. +You can change behaviour by providing cmake options +`SYSTEM_PNG`, `SYSTEM_RL` and `SYSTEM_GL` to 0 or 1 respectively +(`-DSYSTEM_PNG=0 -DSYSTEM_RL=1 -DSYSTEM_GL=0` or any). + +_NB: `libz` must be pre-installed in your system._ ## Licencing notice diff --git a/gif.h_noload b/gif.h_noload deleted file mode 100644 index 94d445c..0000000 --- a/gif.h_noload +++ /dev/null @@ -1,819 +0,0 @@ -// -// gif.h -// by Charlie Tangora -// Public domain. -// Email me : ctangora -at- gmail -dot- com -// -// This file offers a simple, very limited way to create animated GIFs directly in code. -// -// Those looking for particular cleverness are likely to be disappointed; it's pretty -// much a straight-ahead implementation of the GIF format with optional Floyd-Steinberg -// dithering. (It does at least use delta encoding - only the changed portions of each -// frame are saved.) -// -// So resulting files are often quite large. The hope is that it will be handy nonetheless -// as a quick and easily-integrated way for programs to spit out animations. -// -// Only RGBA8 is currently supported as an input format. (The alpha is ignored.) -// -// USAGE: -// Create a GifWriter struct. Pass it to GifBegin() to initialize and write the header. -// Pass subsequent frames to GifWriteFrame(). -// Finally, call GifEnd() to close the file handle and free memory. -// - -#ifndef gif_h -#define gif_h - -#include // for FILE* -#include // for memcpy and bzero -#include // for integer typedefs - -// Define these macros to hook into a custom memory allocator. -// TEMP_MALLOC and TEMP_FREE will only be called in stack fashion - frees in the reverse order of mallocs -// and any temp memory allocated by a function will be freed before it exits. -// MALLOC and FREE are used only by GifBegin and GifEnd respectively (to allocate a buffer the size of the image, which -// is used to find changed pixels for delta-encoding.) - -#ifndef GIF_TEMP_MALLOC -#include -#define GIF_TEMP_MALLOC malloc -#endif - -#ifndef GIF_TEMP_FREE -#include -#define GIF_TEMP_FREE free -#endif - -#ifndef GIF_MALLOC -#include -#define GIF_MALLOC malloc -#endif - -#ifndef GIF_FREE -#include -#define GIF_FREE free -#endif - -static const int kGifTransIndex = 0; - -struct GifPalette { - int bitDepth; - - uint8_t r[256]; - uint8_t g[256]; - uint8_t b[256]; - - // k-d tree over RGB space, organized in heap fashion - // i.e. left child of node i is node i*2, right child is node i*2+1 - // nodes 256-511 are implicitly the leaves, containing a color - uint8_t treeSplitElt[256]; - uint8_t treeSplit[256]; -}; - -// max, min, and abs functions - -static int GifIMax(int l, int r) { - return l > r ? l : r; -} - -static int GifIMin(int l, int r) { - return l < r ? l : r; -} - -static int GifIAbs(int i) { - return i < 0 ? -i : i; -} - -static const int colorDimScales[3] = {14, 20, 17}; - -// walks the k-d tree to pick the palette entry for a desired color. -// Takes as in/out parameters the current best color and its error - -// only changes them if it finds a better color in its subtree. -// this is the major hotspot in the code at the moment. - -static void GifGetClosestPaletteColor(GifPalette* pPal, int r, int g, int b, int& bestInd, int& bestDiff, int treeRoot = 1) { - // base case, reached the bottom of the tree - if (treeRoot > (1 << pPal->bitDepth) - 1) { - int ind = treeRoot - (1 << pPal->bitDepth); - if (ind == kGifTransIndex) return; - - // check whether this color is better than the current winner - int r_err = r - ((int32_t) pPal->r[ind]); - int g_err = g - ((int32_t) pPal->g[ind]); - int b_err = b - ((int32_t) pPal->b[ind]); - // RED: Increase green importance - int diff = colorDimScales[0] * GifIAbs(r_err) + colorDimScales[1] * GifIAbs(g_err) + colorDimScales[2] * GifIAbs(b_err); - - if (diff < bestDiff) { - bestInd = ind; - bestDiff = diff; - } - - return; - } - - // take the appropriate color (r, g, or b) for this node of the k-d tree - int comps[3]; - comps[0] = r; - comps[1] = g; - comps[2] = b; - int splitComp = comps[pPal->treeSplitElt[treeRoot]]; - int dimScale = colorDimScales[pPal->treeSplitElt[treeRoot]]; - - int splitPos = pPal->treeSplit[treeRoot]; - if (splitPos > splitComp) { - // check the left subtree - GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot * 2); - if (bestDiff > dimScale * (splitPos - splitComp)) { - // cannot prove there's not a better value in the right subtree, check that too - GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot * 2 + 1); - } - } else { - GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot * 2 + 1); - if (bestDiff > dimScale * (splitComp - splitPos)) { - GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot * 2); - } - } -} - -static void GifSwapPixels(uint8_t* image, int pixA, int pixB) { - uint8_t rA = image[pixA * 4]; - uint8_t gA = image[pixA * 4 + 1]; - uint8_t bA = image[pixA * 4 + 2]; - uint8_t aA = image[pixA * 4 + 3]; - - uint8_t rB = image[pixB * 4]; - uint8_t gB = image[pixB * 4 + 1]; - uint8_t bB = image[pixB * 4 + 2]; - uint8_t aB = image[pixA * 4 + 3]; - - image[pixA * 4] = rB; - image[pixA * 4 + 1] = gB; - image[pixA * 4 + 2] = bB; - image[pixA * 4 + 3] = aB; - - image[pixB * 4] = rA; - image[pixB * 4 + 1] = gA; - image[pixB * 4 + 2] = bA; - image[pixB * 4 + 3] = aA; -} - -// just the partition operation from quicksort - -static int GifPartition(uint8_t* image, const int left, const int right, const int elt, int pivotIndex) { - const int pivotValue = image[(pivotIndex)*4 + elt]; - GifSwapPixels(image, pivotIndex, right - 1); - int storeIndex = left; - bool split = 0; - for (int ii = left; ii < right - 1; ++ii) { - int arrayVal = image[ii * 4 + elt]; - if (arrayVal < pivotValue) { - GifSwapPixels(image, ii, storeIndex); - ++storeIndex; - } else if (arrayVal == pivotValue) { - if (split) { - GifSwapPixels(image, ii, storeIndex); - ++storeIndex; - } - split = !split; - } - } - GifSwapPixels(image, storeIndex, right - 1); - return storeIndex; -} - -// Perform an incomplete sort, finding all elements above and below the desired median - -static void GifPartitionByMedian(uint8_t* image, int left, int right, int com, int neededCenter) { - if (left < right - 1) { - int pivotIndex = left + (right - left) / 2; - - pivotIndex = GifPartition(image, left, right, com, pivotIndex); - - // Only "sort" the section of the array that contains the median - if (pivotIndex > neededCenter) - GifPartitionByMedian(image, left, pivotIndex, com, neededCenter); - - if (pivotIndex < neededCenter) - GifPartitionByMedian(image, pivotIndex + 1, right, com, neededCenter); - } -} - -// Builds a palette by creating a balanced k-d tree of all pixels in the image - -static void GifSplitPalette(uint8_t* image, int numPixels, int firstElt, int lastElt, int splitElt, int splitDist, int treeNode, bool buildForDither, GifPalette* pal) { - if (lastElt <= firstElt || numPixels == 0) - return; - - // base case, bottom of the tree - if (lastElt == firstElt + 1) { - if (buildForDither) { - // Dithering needs at least one color as dark as anything - // in the image and at least one brightest color - - // otherwise it builds up error and produces strange artifacts - if (firstElt == 1) { - // special case: the darkest color in the image - uint32_t r = 255, g = 255, b = 255; - for (int ii = 0; ii < numPixels; ++ii) { - r = GifIMin(r, image[ii * 4 + 0]); - g = GifIMin(g, image[ii * 4 + 1]); - b = GifIMin(b, image[ii * 4 + 2]); - } - - pal->r[firstElt] = r; - pal->g[firstElt] = g; - pal->b[firstElt] = b; - - return; - } - - if (firstElt == (1 << pal->bitDepth) - 1) { - // special case: the lightest color in the image - uint32_t r = 0, g = 0, b = 0; - for (int ii = 0; ii < numPixels; ++ii) { - r = GifIMax(r, image[ii * 4 + 0]); - g = GifIMax(g, image[ii * 4 + 1]); - b = GifIMax(b, image[ii * 4 + 2]); - } - - pal->r[firstElt] = r; - pal->g[firstElt] = g; - pal->b[firstElt] = b; - - return; - } - } - - // otherwise, take the average of all colors in this subcube - uint64_t r = 0, g = 0, b = 0; - for (int ii = 0; ii < numPixels; ++ii) { - r += image[ii * 4 + 0]; - g += image[ii * 4 + 1]; - b += image[ii * 4 + 2]; - } - - r += numPixels / 2; // round to nearest - g += numPixels / 2; - b += numPixels / 2; - - r /= numPixels; - g /= numPixels; - b /= numPixels; - - pal->r[firstElt] = (uint8_t) r; - pal->g[firstElt] = (uint8_t) g; - pal->b[firstElt] = (uint8_t) b; - - return; - } - - // Find the axis with the largest range - int minR = 255, maxR = 0; - int minG = 255, maxG = 0; - int minB = 255, maxB = 0; - for (int ii = 0; ii < numPixels; ++ii) { - int r = image[ii * 4 + 0]; - int g = image[ii * 4 + 1]; - int b = image[ii * 4 + 2]; - - if (r > maxR) maxR = r; - if (r < minR) minR = r; - - if (g > maxG) maxG = g; - if (g < minG) minG = g; - - if (b > maxB) maxB = b; - if (b < minB) minB = b; - } - - int rRange = maxR - minR; - int gRange = maxG - minG; - int bRange = maxB - minB; - rRange *= colorDimScales[0]; - gRange *= colorDimScales[1]; // RED: Modification to increase green importance - bRange *= colorDimScales[2]; - - // and split along that axis. (incidentally, this means this isn't a "proper" k-d tree but I don't know what else to call it) - int splitCom = 1; - if (bRange > gRange) splitCom = 2; - if (rRange > bRange && rRange > gRange) splitCom = 0; - - int subPixelsA = numPixels * (splitElt - firstElt) / (lastElt - firstElt); - int subPixelsB = numPixels - subPixelsA; - - GifPartitionByMedian(image, 0, numPixels, splitCom, subPixelsA); - - pal->treeSplitElt[treeNode] = splitCom; - pal->treeSplit[treeNode] = image[subPixelsA * 4 + splitCom]; - - GifSplitPalette(image, subPixelsA, firstElt, splitElt, splitElt - splitDist, splitDist / 2, treeNode * 2, buildForDither, pal); - GifSplitPalette(image + subPixelsA * 4, subPixelsB, splitElt, lastElt, splitElt + splitDist, splitDist / 2, treeNode * 2 + 1, buildForDither, pal); -} - -// Finds all pixels that have changed from the previous image and -// moves them to the fromt of th buffer. -// This allows us to build a palette optimized for the colors of the -// changed pixels only. - -static int GifPickChangedPixels(const uint8_t* lastFrame, uint8_t* frame, int numPixels) { - int numChanged = 0; - uint8_t* writeIter = frame; - - for (int ii = 0; ii < numPixels; ++ii) { - if (lastFrame[0] != frame[0] || - lastFrame[1] != frame[1] || - lastFrame[2] != frame[2]) { - writeIter[0] = frame[0]; - writeIter[1] = frame[1]; - writeIter[2] = frame[2]; - ++numChanged; - writeIter += 4; - } - lastFrame += 4; - frame += 4; - } - - return numChanged; -} - -// Creates a palette by placing all the image pixels in a k-d tree and then averaging the blocks at the bottom. -// This is known as the "modified median split" technique - -static void GifMakePalette(const uint8_t* lastFrame, const uint8_t* nextFrame, uint32_t width, uint32_t height, int bitDepth, bool buildForDither, GifPalette* pPal) { - pPal->bitDepth = bitDepth; - - // SplitPalette is destructive (it sorts the pixels by color) so - // we must create a copy of the image for it to destroy - int imageSize = width * height * 4 * sizeof (uint8_t); - uint8_t* destroyableImage = (uint8_t*) GIF_TEMP_MALLOC(imageSize); - memcpy(destroyableImage, nextFrame, imageSize); - - int numPixels = width*height; - if (lastFrame) - numPixels = GifPickChangedPixels(lastFrame, destroyableImage, numPixels); - - const int lastElt = 1 << bitDepth; - const int splitElt = lastElt / 2; - const int splitDist = splitElt / 2; - - GifSplitPalette(destroyableImage, numPixels, 1, lastElt, splitElt, splitDist, 1, buildForDither, pPal); - - GIF_TEMP_FREE(destroyableImage); - - // add the bottom node for the transparency index - pPal->treeSplit[1 << (bitDepth - 1)] = 0; - pPal->treeSplitElt[1 << (bitDepth - 1)] = 0; - - pPal->r[0] = pPal->g[0] = pPal->b[0] = 0; -} - -// Implements Floyd-Steinberg dithering, writes palette value to alpha - -static void GifDitherImage(const uint8_t* lastFrame, const uint8_t* nextFrame, uint8_t* outFrame, uint32_t width, uint32_t height, GifPalette* pPal) { - int numPixels = width*height; - - // quantPixels initially holds color*256 for all pixels - // The extra 8 bits of precision allow for sub-single-color error values - // to be propagated - int32_t* quantPixels = (int32_t*) GIF_TEMP_MALLOC(sizeof (int32_t) * numPixels * 4); - - for (int ii = 0; ii < numPixels * 4; ++ii) { - uint8_t pix = nextFrame[ii]; - int32_t pix16 = int32_t(pix) * 256; - quantPixels[ii] = pix16; - } - - for (uint32_t yy = 0; yy < height; ++yy) { - for (uint32_t xx = 0; xx < width; ++xx) { - int32_t* nextPix = quantPixels + 4 * (yy * width + xx); - const uint8_t* lastPix = lastFrame ? lastFrame + 4 * (yy * width + xx) : NULL; - - // Compute the colors we want (rounding to nearest) - int32_t rr = (nextPix[0] + 127) / 256; - int32_t gg = (nextPix[1] + 127) / 256; - int32_t bb = (nextPix[2] + 127) / 256; - - // if it happens that we want the color from last frame, then just write out - // a transparent pixel - if (lastFrame && - lastPix[0] == rr && - lastPix[1] == gg && - lastPix[2] == bb) { - nextPix[0] = rr; - nextPix[1] = gg; - nextPix[2] = bb; - nextPix[3] = kGifTransIndex; - continue; - } - - int32_t bestDiff = 1000000; - int32_t bestInd = kGifTransIndex; - - // Search the palete - GifGetClosestPaletteColor(pPal, rr, gg, bb, bestInd, bestDiff); - - // Write the result to the temp buffer - int32_t r_err = nextPix[0] - int32_t(pPal->r[bestInd]) * 256; - int32_t g_err = nextPix[1] - int32_t(pPal->g[bestInd]) * 256; - int32_t b_err = nextPix[2] - int32_t(pPal->b[bestInd]) * 256; - - nextPix[0] = pPal->r[bestInd]; - nextPix[1] = pPal->g[bestInd]; - nextPix[2] = pPal->b[bestInd]; - nextPix[3] = bestInd; - - // Propagate the error to the four adjacent locations - // that we haven't touched yet - int quantloc_7 = (yy * width + xx + 1); - int quantloc_3 = (yy * width + width + xx - 1); - int quantloc_5 = (yy * width + width + xx); - int quantloc_1 = (yy * width + width + xx + 1); - - if (quantloc_7 < numPixels) { - int32_t* pix7 = quantPixels + 4 * quantloc_7; - pix7[0] += GifIMax(-pix7[0], r_err * 7 / 16); - pix7[1] += GifIMax(-pix7[1], g_err * 7 / 16); - pix7[2] += GifIMax(-pix7[2], b_err * 7 / 16); - } - - if (quantloc_3 < numPixels) { - int32_t* pix3 = quantPixels + 4 * quantloc_3; - pix3[0] += GifIMax(-pix3[0], r_err * 3 / 16); - pix3[1] += GifIMax(-pix3[1], g_err * 3 / 16); - pix3[2] += GifIMax(-pix3[2], b_err * 3 / 16); - } - - if (quantloc_5 < numPixels) { - int32_t* pix5 = quantPixels + 4 * quantloc_5; - pix5[0] += GifIMax(-pix5[0], r_err * 5 / 16); - pix5[1] += GifIMax(-pix5[1], g_err * 5 / 16); - pix5[2] += GifIMax(-pix5[2], b_err * 5 / 16); - } - - if (quantloc_1 < numPixels) { - int32_t* pix1 = quantPixels + 4 * quantloc_1; - pix1[0] += GifIMax(-pix1[0], r_err / 16); - pix1[1] += GifIMax(-pix1[1], g_err / 16); - pix1[2] += GifIMax(-pix1[2], b_err / 16); - } - } - } - - // Copy the palettized result to the output buffer - for (int ii = 0; ii < numPixels * 4; ++ii) { - outFrame[ii] = quantPixels[ii]; - } - - GIF_TEMP_FREE(quantPixels); -} - -// Picks palette colors for the image using simple thresholding, no dithering - -static void GifThresholdImage(const uint8_t* lastFrame, const uint8_t* nextFrame, uint8_t* outFrame, uint32_t width, uint32_t height, GifPalette* pPal) { - uint32_t numPixels = width*height; - for (uint32_t ii = 0; ii < numPixels; ++ii) { - // if a previous color is available, and it matches the current color, - // set the pixel to transparent - if (lastFrame && - lastFrame[0] == nextFrame[0] && - lastFrame[1] == nextFrame[1] && - lastFrame[2] == nextFrame[2]) { - outFrame[0] = lastFrame[0]; - outFrame[1] = lastFrame[1]; - outFrame[2] = lastFrame[2]; - outFrame[3] = kGifTransIndex; - } else { - // palettize the pixel - int32_t bestDiff = 1000000; - int32_t bestInd = 1; - GifGetClosestPaletteColor(pPal, nextFrame[0], nextFrame[1], nextFrame[2], bestInd, bestDiff); - - bool usedOld = false; - if (lastFrame) { - // RED: If the chosen one is worse than the old one, don't go with it - int r_err = (int) lastFrame[0] - (int) nextFrame[0]; - int g_err = (int) lastFrame[1] - (int) nextFrame[1]; - int b_err = (int) lastFrame[2] - (int) nextFrame[2]; - int oldDiff = colorDimScales[0] * GifIAbs(r_err) + colorDimScales[1] * GifIAbs(g_err) + colorDimScales[2] * GifIAbs(b_err); - if (oldDiff <= bestDiff) { - outFrame[0] = lastFrame[0]; - outFrame[1] = lastFrame[1]; - outFrame[2] = lastFrame[2]; - outFrame[3] = kGifTransIndex; - usedOld = true; - } - } - - if (!usedOld) { - // Write the resulting color to the output buffer - outFrame[0] = pPal->r[bestInd]; - outFrame[1] = pPal->g[bestInd]; - outFrame[2] = pPal->b[bestInd]; - outFrame[3] = bestInd; - } - } - - if (lastFrame) lastFrame += 4; - outFrame += 4; - nextFrame += 4; - } -} - -// Simple structure to write out the LZW-compressed portion of the image -// one bit at a time - -struct GifBitStatus { - uint8_t bitIndex; // how many bits in the partial byte written so far - uint8_t byte; // current partial byte - - uint32_t chunkIndex; - uint8_t chunk[256]; // bytes are written in here until we have 256 of them, then written to the file -}; - -// insert a single bit - -static void GifWriteBit(GifBitStatus& stat, uint32_t bit) { - bit = bit & 1; - bit = bit << stat.bitIndex; - stat.byte |= bit; - - ++stat.bitIndex; - if (stat.bitIndex > 7) { - // move the newly-finished byte to the chunk buffer - stat.chunk[stat.chunkIndex++] = stat.byte; - // and start a new byte - stat.bitIndex = 0; - stat.byte = 0; - } -} - -// write all bytes so far to the file - -static void GifWriteChunk(FILE* f, GifBitStatus& stat) { - fputc(stat.chunkIndex, f); - fwrite(stat.chunk, 1, stat.chunkIndex, f); - - stat.bitIndex = 0; - stat.byte = 0; - stat.chunkIndex = 0; -} - -static void GifWriteCode(FILE* f, GifBitStatus& stat, uint32_t code, uint32_t length) { - for (uint32_t ii = 0; ii < length; ++ii) { - GifWriteBit(stat, code); - code = code >> 1; - - if (stat.chunkIndex == 255) { - GifWriteChunk(f, stat); - } - } -} - -// The LZW dictionary is a 256-ary tree constructed as the file is encoded, -// this is one node - -struct GifLzwNode { - uint16_t m_next[256]; -}; - -// write a 256-color (8-bit) image palette to the file - -static void GifWritePalette(const GifPalette* pPal, FILE* f) { - fputc(0, f); // first color: transparency - fputc(0, f); - fputc(0, f); - - for (int ii = 1; ii < (1 << pPal->bitDepth); ++ii) { - uint32_t r = pPal->r[ii]; - uint32_t g = pPal->g[ii]; - uint32_t b = pPal->b[ii]; - - fputc(r, f); - fputc(g, f); - fputc(b, f); - } -} - -// write the image header, LZW-compress and write out the image - -static void GifWriteLzwImage(FILE* f, uint8_t* image, uint32_t left, uint32_t top, uint32_t width, uint32_t height, uint32_t delay, GifPalette* pPal, long int *delaypos) { - // graphics control extension - fputc(0x21, f); - fputc(0xf9, f); - fputc(0x04, f); - fputc(0x0d, f); // leave prev frame in place, this frame has transparency - if (delaypos) *delaypos = ftell(f); - fputc(delay & 0xff, f); - fputc((delay >> 8) & 0xff, f); - fputc(kGifTransIndex, f); // transparent color index - fputc(0, f); - - fputc(0x2c, f); // image descriptor block - - fputc(left & 0xff, f); // corner of image in canvas space - fputc((left >> 8) & 0xff, f); - fputc(top & 0xff, f); - fputc((top >> 8) & 0xff, f); - - fputc(width & 0xff, f); // width and height of image - fputc((width >> 8) & 0xff, f); - fputc(height & 0xff, f); - fputc((height >> 8) & 0xff, f); - - //fputc(0, f); // no local color table, no transparency - //fputc(0x80, f); // no local color table, but transparency - - fputc(0x80 + pPal->bitDepth - 1, f); // local color table present, 2 ^ bitDepth entries - GifWritePalette(pPal, f); - - const int minCodeSize = pPal->bitDepth; - const uint32_t clearCode = 1 << pPal->bitDepth; - - fputc(minCodeSize, f); // min code size 8 bits - - GifLzwNode* codetree = (GifLzwNode*) GIF_TEMP_MALLOC(sizeof (GifLzwNode)*4096); - - memset(codetree, 0, sizeof (GifLzwNode)*4096); - int32_t curCode = -1; - uint32_t codeSize = minCodeSize + 1; - uint32_t maxCode = clearCode + 1; - - GifBitStatus stat; - stat.byte = 0; - stat.bitIndex = 0; - stat.chunkIndex = 0; - - GifWriteCode(f, stat, clearCode, codeSize); // start with a fresh LZW dictionary - - for (uint32_t yy = 0; yy < height; ++yy) { - for (uint32_t xx = 0; xx < width; ++xx) { - uint8_t nextValue = image[(yy * width + xx)*4 + 3]; - - // "loser mode" - no compression, every single code is followed immediately by a clear - //WriteCode( f, stat, nextValue, codeSize ); - //WriteCode( f, stat, 256, codeSize ); - - if (curCode < 0) { - // first value in a new run - curCode = nextValue; - } else if (codetree[curCode].m_next[nextValue]) { - // current run already in the dictionary - curCode = codetree[curCode].m_next[nextValue]; - } else { - // finish the current run, write a code - GifWriteCode(f, stat, curCode, codeSize); - - // insert the new run into the dictionary - codetree[curCode].m_next[nextValue] = ++maxCode; - - if (maxCode >= (1ul << codeSize)) { - // dictionary entry count has broken a size barrier, - // we need more bits for codes - codeSize++; - } - if (maxCode == 4095) { - // the dictionary is full, clear it out and begin anew - GifWriteCode(f, stat, clearCode, codeSize); // clear tree - - memset(codetree, 0, sizeof (GifLzwNode)*4096); - curCode = -1; - codeSize = minCodeSize + 1; - maxCode = clearCode + 1; - } - - curCode = nextValue; - } - } - } - - // compression footer - GifWriteCode(f, stat, curCode, codeSize); - GifWriteCode(f, stat, clearCode, codeSize); - GifWriteCode(f, stat, clearCode + 1, minCodeSize + 1); - - // write out the last partial chunk - while (stat.bitIndex) GifWriteBit(stat, 0); - if (stat.chunkIndex) GifWriteChunk(f, stat); - - fputc(0, f); // image block terminator - - GIF_TEMP_FREE(codetree); -} - -struct GifWriter { - FILE* f; - uint8_t* oldImage; - bool firstFrame; - long int delaypos; -}; - -#define GIF_WRITER_INIT(_X_) {.f = (_X_), .oldImage = NULL, .firstFrame = true, .delaypos = -1} - -// Creates a gif file. -// The input GIFWriter is assumed to be uninitialized. -// The delay value is the time between frames in hundredths of a second - note that not all viewers pay much attention to this value. - -static bool GifBegin(GifWriter* writer, uint32_t width, uint32_t height, uint32_t delay) { - if (!writer->f) return false; - - writer->firstFrame = true; - writer->delaypos = -1; - - // allocate - writer->oldImage = (uint8_t*) GIF_MALLOC(width * height * 4); - - fputs("GIF89a", writer->f); - - // screen descriptor - fputc(width & 0xff, writer->f); - fputc((width >> 8) & 0xff, writer->f); - fputc(height & 0xff, writer->f); - fputc((height >> 8) & 0xff, writer->f); - - fputc(0xf0, writer->f); // there is an unsorted global color table of 2 entries - fputc(0, writer->f); // background color - fputc(0, writer->f); // pixels are square (we need to specify this because it's 1989) - - // now the "global" palette (really just a dummy palette) - // color 0: black - fputc(0, writer->f); - fputc(0, writer->f); - fputc(0, writer->f); - // color 1: also black - fputc(0, writer->f); - fputc(0, writer->f); - fputc(0, writer->f); - - if (delay != 0) { - // animation header - fputc(0x21, writer->f); // extension - fputc(0xff, writer->f); // application specific - fputc(11, writer->f); // length 11 - fputs("NETSCAPE2.0", writer->f); // yes, really - fputc(3, writer->f); // 3 bytes of NETSCAPE2.0 data - - fputc(1, writer->f); // JUST BECAUSE - fputc(0, writer->f); // loop infinitely (byte 0) - fputc(0, writer->f); // loop infinitely (byte 1) - - fputc(0, writer->f); // block terminator - } - - return true; -} - -// Writes out a new frame to a GIF in progress. -// The GIFWriter should have been created by GIFBegin. -// AFAIK, it is legal to use different bit depths for different frames of an image - -// this may be handy to save bits in animations that don't change much. - -static bool GifWriteFrame(GifWriter* writer, const uint8_t* image, uint32_t width, uint32_t height, uint32_t delay, int bitDepth = 8, bool dither = false) { - if (!writer->f) return false; - - const uint8_t* oldImage = writer->firstFrame ? NULL : writer->oldImage; - writer->firstFrame = false; - - GifPalette pal; - GifMakePalette((dither ? NULL : oldImage), image, width, height, bitDepth, dither, &pal); - - if (dither) - GifDitherImage(oldImage, image, writer->oldImage, width, height, &pal); - else - GifThresholdImage(oldImage, image, writer->oldImage, width, height, &pal); - - GifWriteLzwImage(writer->f, writer->oldImage, 0, 0, width, height, delay, &pal, &writer->delaypos); - - return true; -} - -static void GifOverwriteLastDelay(GifWriter* writer, uint32_t delay) { - if (writer->delaypos == -1) return; - FILE* f = writer->f; - - long int pos = ftell(f); - fseek(f, writer->delaypos, SEEK_SET); - fputc(delay & 0xff, f); - fputc((delay >> 8) & 0xff, f); - fseek(f, pos, SEEK_SET); -} - -// Writes the EOF code, closes the file handle, and frees temp memory used by a GIF. -// Many if not most viewers will still display a GIF properly if the EOF code is missing, -// but it's still a good idea to write it out. - -static bool GifEnd(GifWriter* writer) { - if (!writer->f) return false; - - fputc(0x3b, writer->f); // end of file - GIF_FREE(writer->oldImage); - - writer->f = NULL; - writer->oldImage = NULL; - writer->delaypos = -1; - - return true; -} - - -#endif \ No newline at end of file diff --git a/lib/libpng b/lib/libpng new file mode 160000 index 0000000..a40189c --- /dev/null +++ b/lib/libpng @@ -0,0 +1 @@ +Subproject commit a40189cf881e9f0db80511c382292a5604c3c3d1 diff --git a/lottie_export.cpp b/lottie_export.cpp index eaa1f92..58f9039 100644 --- a/lottie_export.cpp +++ b/lottie_export.cpp @@ -87,6 +87,7 @@ int convert_and_write_to(byte *in_file_data, uint8_t convert_to, int w, int h, u return EXIT_FAILURE; } size_t frame_count = animation->totalFrame(); + auto frame_inc = (float)animation->frameRate() / (float)param; unique_ptr buffer = unique_ptr(new uint32_t[w * h]); if (buffer == nullptr) { fputs("Unable to init frame buffer\n", stderr); @@ -101,8 +102,8 @@ int convert_and_write_to(byte *in_file_data, uint8_t convert_to, int w, int h, u return write_png(reinterpret_cast (buffer.get()), w, h, out_file->file_pointer); } case li_OUT_PNGS: { - float ratio = (float) animation->frameRate() / param; - size_t frame_count_out = frame_count / ratio; + float frame_current = 0.0f; + auto frame_count_out = (size_t)((float)frame_count / frame_inc); size_t frame_count_out_t = frame_count_out; unsigned int digit_count = 1, frame_number = 0; while (frame_count_out_t > 9) { @@ -121,8 +122,8 @@ int convert_and_write_to(byte *in_file_data, uint8_t convert_to, int w, int h, u memset(file_name_template, '\0', FILENAME_MAX); strncpy(file_name_template, out_file->path, FILENAME_MAX); strncat(file_name_template, ls_OUT_PNGS_SUFFIX, FILENAME_MAX); - for (float frame_current = 0.0f; frame_current < (float) frame_count; frame_current += ratio) { - FILE *fp = nullptr; + while (frame_current < (float) frame_count) { + FILE *fp; memset(file_name, '\0', FILENAME_MAX); snprintf(file_name, FILENAME_MAX, file_name_template, digit_count, frame_number++); if ((fp = fopen(file_name, "wb")) == nullptr) { @@ -137,22 +138,41 @@ int convert_and_write_to(byte *in_file_data, uint8_t convert_to, int w, int h, u if (result != EXIT_SUCCESS) { break; } + frame_current += frame_inc; } free(file_name_template); free(file_name); return result; } case li_OUT_GIF: { + if(param == 0 || param > 100){ + fputs("GIF framerate must be between 1 and 100", stderr); + return EXIT_FAILURE; + } + float frame_current = 0.0f; int error_code = 0; - GifFileType *writer = EGifOpen(nullptr, nullptr, &error_code); + GifFileType *writer = EGifOpenFileHandle(fileno(out_file->file_pointer), &error_code); if (writer == nullptr || error_code != 0) { fprintf(stderr, "Unable to initialize GIF writer, error code: %d\n", error_code); return EXIT_FAILURE; } - int frame_to_extract = (int) (animation->frameRate() / 10); int color_map_size = 1 << lp_COLOR_DEPTH; + byte loop[]{1, 0, 0}; //infinite gif loop + static byte delay[4] = {0x0D, // Bit 0 - flag if transparent index given (checked), + // Bit 1 - User Input Flag (unchecked), + // Bits 2-4 - Disposal Method: + // 0 - unspecified, + // 1 - don't dispose, + // 2 - restore to background color, + // 3 - restore to previous (checked) + 10, // >Hundredths of + 0, // seconds to wait< + 0}; // Transparent color index //TODO: try to calculate ColorMapObject *output_palette = GifMakeMapObject(color_map_size, nullptr); - ((GifFilePrivateType *) writer->Private)->File = out_file->file_pointer; + if(output_palette == nullptr){ + status = EXIT_FAILURE; + goto CLOSE_FILE; + } EGifSetGifVersion(writer, true); if (EGifPutScreenDesc( writer, @@ -160,29 +180,31 @@ int convert_and_write_to(byte *in_file_data, uint8_t convert_to, int w, int h, u output_palette ) == GIF_ERROR) { fputs("Something went wrong while creating gif\n", stderr); - return EXIT_FAILURE; + status = EXIT_FAILURE; + goto FREE_MAP; } - byte loop[]{1, 0, 0}; if (EGifPutExtensionLeader(writer, APPLICATION_EXT_FUNC_CODE) == GIF_ERROR) { fputs("Unable to write gif extension\n", stderr); - return EXIT_FAILURE; + status = EXIT_FAILURE; + goto FREE_MAP; } if (EGifPutExtensionBlock(writer, 11, "NETSCAPE2.0") == GIF_ERROR) { fputs("Unable to write gif extension\n", stderr); - return EXIT_FAILURE; + status = EXIT_FAILURE; + goto FREE_MAP; } if (EGifPutExtensionBlock(writer, 3, loop) == GIF_ERROR) { fputs("Unable to write gif extension\n", stderr); - return EXIT_FAILURE; + status = EXIT_FAILURE; + goto FREE_MAP; } if (EGifPutExtensionTrailer(writer) == GIF_ERROR) { fputs("Unable to write gif extension\n", stderr); - return EXIT_FAILURE; + status = EXIT_FAILURE; } - for (size_t frame_current = 0; - frame_current < frame_count && status == EXIT_SUCCESS; frame_current += frame_to_extract) { + while (frame_current < (float)frame_count && status == EXIT_SUCCESS) { Surface surface(buffer.get(), w, h, w * lp_COLOR_BYTES); - animation->renderSync(frame_current, surface); + animation->renderSync(lround(frame_current), surface); auto *byte_buffer_raw = reinterpret_cast (buffer.get()); size_t pixel_count = w * h; byte *rb = (byte *)calloc(pixel_count, sizeof(byte)), @@ -230,16 +252,6 @@ int convert_and_write_to(byte *in_file_data, uint8_t convert_to, int w, int h, u break; } byte *line_buffer = out; - static unsigned char delay[4] = {0x0D, // Bit 0 - flag if transparent index given (checked), - // Bit 1 - User Input Flag (unchecked), - // Bits 2-4 - Disposal Method: - // 0 - unspecified, - // 1 - don't dispose, - // 2 - restore to background color, - // 3 - restore to previous (checked) - 10, // >Hundredths of - 0, // seconds to wait< - 0}; // Transparent color index //TODO: try to calculate if(EGifPutExtension(writer, GRAPHICS_EXT_FUNC_CODE, 4, delay) == GIF_OK) { if (EGifPutImageDesc(writer, 0, 0, w, h, false, output_palette) == GIF_OK) { for (int line = 0; line < h; ++line) { @@ -259,7 +271,11 @@ int convert_and_write_to(byte *in_file_data, uint8_t convert_to, int w, int h, u status = EXIT_FAILURE; } free(out); + frame_current += frame_inc; } +FREE_MAP: + GifFreeMapObject(output_palette); +CLOSE_FILE: if (EGifCloseFile(writer, &error_code) != GIF_OK) { fprintf(stderr, "Unable to finalize GIF writer, error code: %d\n", error_code); status = EXIT_FAILURE; diff --git a/lottie_export.h b/lottie_export.h index bc54bbd..38742e1 100644 --- a/lottie_export.h +++ b/lottie_export.h @@ -15,8 +15,7 @@ #include #include #include -#include "gif_lib.h" -#include "gif_lib_private.h" +#include //include from getarg.h extern "C" int GifQuantizeBuffer(unsigned int Width, unsigned int Height, @@ -78,7 +77,6 @@ int bb_append(byte_buffer * bb, byte * data, size_t data_size) { bb->buffer = (byte *) realloc(bb->buffer, (bb->size + data_size) * sizeof (byte)); if (bb->buffer == nullptr) { - perror("Unable to extend byte buffer"); return EXIT_FAILURE; } memset(bb->buffer + bb->size, 0, data_size); diff --git a/memcheck.log b/memcheck.log index df1b00c..068938f 100644 --- a/memcheck.log +++ b/memcheck.log @@ -146,3 +146,932 @@ Parameters: AnimatedSticker.tgs - gif 256x256 30 ==20129== ==20129== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) ==20129== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) +==38532== Memcheck, a memory error detector +==38532== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. +==38532== Using Valgrind-3.15.0-608cb11914-20190413 and LibVEX; rerun with -h for copyright info +==38532== Command: build/lottieconverter AnimatedSticker.tgs out.png png 300x300 10 +==38532== +--38532-- Valgrind options: +--38532-- --tool=memcheck +--38532-- --leak-check=full +--38532-- --show-reachable=yes +--38532-- --track-origins=yes +--38532-- -v +--38532-- Contents of /proc/version: +--38532-- Linux version 5.11.0-40-generic (buildd@lgw01-amd64-010) (gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0, GNU ld (GNU Binutils for Ubuntu) 2.34) #44~20.04.2-Ubuntu SMP Tue Oct 26 18:07:44 UTC 2021 +--38532-- +--38532-- Arch and hwcaps: AMD64, LittleEndian, amd64-cx16-lzcnt-rdtscp-sse3-ssse3-avx-avx2-bmi-f16c-rdrand +--38532-- Page sizes: currently 4096, max supported 4096 +--38532-- Valgrind library directory: /usr/lib/x86_64-linux-gnu/valgrind +--38532-- Reading syms from /home/sot/Projects/LottieConverter/build/lottieconverter +--38532-- Reading syms from /lib/x86_64-linux-gnu/ld-2.31.so +--38532-- Considering /lib/x86_64-linux-gnu/ld-2.31.so .. +--38532-- .. CRC mismatch (computed b1e31cec wanted 7bd1f8ba) +--38532-- Considering /lib/x86_64-linux-gnu/ld-2.31.so .. +--38532-- .. CRC mismatch (computed b1e31cec wanted 7bd1f8ba) +--38532-- Considering /usr/lib/debug/lib/x86_64-linux-gnu/ld-2.31.so .. +--38532-- .. CRC is valid +--38532-- Reading syms from /usr/lib/x86_64-linux-gnu/valgrind/memcheck-amd64-linux +--38532-- object doesn't have a symbol table +--38532-- object doesn't have a dynamic symbol table +--38532-- Scheduler: using generic scheduler lock implementation. +--38532-- Reading suppressions file: /usr/lib/x86_64-linux-gnu/valgrind/default.supp +==38532== embedded gdbserver: reading from /tmp/vgdb-pipe-from-vgdb-to-38532-by-sot-on-??? +==38532== embedded gdbserver: writing to /tmp/vgdb-pipe-to-vgdb-from-38532-by-sot-on-??? +==38532== embedded gdbserver: shared mem /tmp/vgdb-pipe-shared-mem-vgdb-38532-by-sot-on-??? +==38532== +==38532== TO CONTROL THIS PROCESS USING vgdb (which you probably +==38532== don't want to do, unless you know exactly what you're doing, +==38532== or are doing some strange experiment): +==38532== /usr/lib/x86_64-linux-gnu/valgrind/../../bin/vgdb --pid=38532 ...command... +==38532== +==38532== TO DEBUG THIS PROCESS USING GDB: start GDB like this +==38532== /path/to/gdb build/lottieconverter +==38532== and then give GDB the following command +==38532== target remote | /usr/lib/x86_64-linux-gnu/valgrind/../../bin/vgdb --pid=38532 +==38532== --pid is optional if only one valgrind process is running +==38532== +--38532-- REDIR: 0x4022f60 (ld-linux-x86-64.so.2:strlen) redirected to 0x580c9ce2 (???) +--38532-- REDIR: 0x4022d30 (ld-linux-x86-64.so.2:index) redirected to 0x580c9cfc (???) +--38532-- Reading syms from /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_core-amd64-linux.so +--38532-- object doesn't have a symbol table +--38532-- Reading syms from /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so +--38532-- object doesn't have a symbol table +==38532== WARNING: new redirection conflicts with existing -- ignoring it +--38532-- old: 0x04022f60 (strlen ) R-> (0000.0) 0x580c9ce2 ??? +--38532-- new: 0x04022f60 (strlen ) R-> (2007.0) 0x0483f060 strlen +--38532-- REDIR: 0x401f740 (ld-linux-x86-64.so.2:strcmp) redirected to 0x483ffd0 (strcmp) +--38532-- REDIR: 0x40234c0 (ld-linux-x86-64.so.2:mempcpy) redirected to 0x4843a20 (mempcpy) +--38532-- Reading syms from /lib/x86_64-linux-gnu/libz.so.1.2.11 +--38532-- object doesn't have a symbol table +--38532-- Reading syms from /lib/x86_64-linux-gnu/libpthread-2.31.so +--38532-- Considering /usr/lib/debug/.build-id/ee/b5b055a9d738db64e450065f88980bebfc9cc2.debug .. +--38532-- .. build-id is valid +--38532-- Reading syms from /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28 +--38532-- object doesn't have a symbol table +--38532-- Reading syms from /lib/x86_64-linux-gnu/libm-2.31.so +--38532-- Considering /lib/x86_64-linux-gnu/libm-2.31.so .. +--38532-- .. CRC mismatch (computed 5f7b2a42 wanted ffb185de) +--38532-- Considering /lib/x86_64-linux-gnu/libm-2.31.so .. +--38532-- .. CRC mismatch (computed 5f7b2a42 wanted ffb185de) +--38532-- Considering /usr/lib/debug/lib/x86_64-linux-gnu/libm-2.31.so .. +--38532-- .. CRC is valid +--38532-- Reading syms from /lib/x86_64-linux-gnu/libgcc_s.so.1 +--38532-- object doesn't have a symbol table +--38532-- Reading syms from /lib/x86_64-linux-gnu/libc-2.31.so +--38532-- Considering /lib/x86_64-linux-gnu/libc-2.31.so .. +--38532-- .. CRC mismatch (computed 11759501 wanted 88150686) +--38532-- Considering /lib/x86_64-linux-gnu/libc-2.31.so .. +--38532-- .. CRC mismatch (computed 11759501 wanted 88150686) +--38532-- Considering /usr/lib/debug/lib/x86_64-linux-gnu/libc-2.31.so .. +--38532-- .. CRC is valid +--38532-- REDIR: 0x4ca5600 (libc.so.6:memmove) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4ca4900 (libc.so.6:strncpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4ca5930 (libc.so.6:strcasecmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4ca4220 (libc.so.6:strcat) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4ca4960 (libc.so.6:rindex) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4ca6dd0 (libc.so.6:rawmemchr) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4cc1e60 (libc.so.6:wmemchr) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4cc19a0 (libc.so.6:wcscmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4ca5760 (libc.so.6:mempcpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4ca5590 (libc.so.6:bcmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4ca4890 (libc.so.6:strncmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4ca42d0 (libc.so.6:strcmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4ca56c0 (libc.so.6:memset) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4cc1960 (libc.so.6:wcschr) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4ca47f0 (libc.so.6:strnlen) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4ca43b0 (libc.so.6:strcspn) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4ca5980 (libc.so.6:strncasecmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4ca4350 (libc.so.6:strcpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4ca5ad0 (libc.so.6:memcpy@@GLIBC_2.14) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4cc30d0 (libc.so.6:wcsnlen) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4cc19e0 (libc.so.6:wcscpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4ca49a0 (libc.so.6:strpbrk) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4ca4280 (libc.so.6:index) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4ca47b0 (libc.so.6:strlen) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4cadd20 (libc.so.6:memrchr) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4ca59d0 (libc.so.6:strcasecmp_l) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4ca5550 (libc.so.6:memchr) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4cc1ab0 (libc.so.6:wcslen) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4ca4c60 (libc.so.6:strspn) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4ca58d0 (libc.so.6:stpncpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4ca5870 (libc.so.6:stpcpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4ca6e10 (libc.so.6:strchrnul) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4ca5a20 (libc.so.6:strncasecmp_l) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4d328e0 (libc.so.6:__memcpy_chk) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38532-- REDIR: 0x4d8d490 (libc.so.6:__strrchr_avx2) redirected to 0x483ea10 (rindex) +--38532-- REDIR: 0x4c9f260 (libc.so.6:malloc) redirected to 0x483b780 (malloc) +--38532-- REDIR: 0x4d8d660 (libc.so.6:__strlen_avx2) redirected to 0x483ef40 (strlen) +--38532-- REDIR: 0x4d89c50 (libc.so.6:__memcmp_avx2_movbe) redirected to 0x48421e0 (bcmp) +--38532-- REDIR: 0x4d88b60 (libc.so.6:__strcmp_avx2) redirected to 0x483fed0 (strcmp) +--38532-- REDIR: 0x4d887b0 (libc.so.6:__strcspn_sse42) redirected to 0x4843e10 (strcspn) +--38532-- REDIR: 0x4ca0c90 (libc.so.6:calloc) redirected to 0x483dce0 (calloc) +--38532-- REDIR: 0x4d90af0 (libc.so.6:__memset_avx2_unaligned_erms) redirected to 0x48428e0 (memset) +--38532-- REDIR: 0x4d8ef30 (libc.so.6:__strncpy_avx2) redirected to 0x483f230 (strncpy) +--38532-- REDIR: 0x4c9f850 (libc.so.6:free) redirected to 0x483c9d0 (free) +--38532-- REDIR: 0x4ca5120 (libc.so.6:__GI_strstr) redirected to 0x4843ca0 (__strstr_sse2) +--38532-- REDIR: 0x4d90670 (libc.so.6:__memcpy_avx_unaligned_erms) redirected to 0x48429f0 (memmove) +--38532-- REDIR: 0x4ca0000 (libc.so.6:realloc) redirected to 0x483df30 (realloc) +--38532-- REDIR: 0x495eb20 (libstdc++.so.6:operator new(unsigned long)) redirected to 0x483bdf0 (operator new(unsigned long)) +--38532-- REDIR: 0x495eb80 (libstdc++.so.6:operator new[](unsigned long)) redirected to 0x483c510 (operator new[](unsigned long)) +--38532-- REDIR: 0x4d8d2a0 (libc.so.6:__strchrnul_avx2) redirected to 0x4843540 (strchrnul) +--38532-- REDIR: 0x4d90650 (libc.so.6:__mempcpy_avx_unaligned_erms) redirected to 0x4843660 (mempcpy) +--38532-- REDIR: 0x495cd70 (libstdc++.so.6:operator delete(void*)) redirected to 0x483cf50 (operator delete(void*)) +--38532-- REDIR: 0x495cd80 (libstdc++.so.6:operator delete(void*, unsigned long)) redirected to 0x483d160 (operator delete(void*, unsigned long)) +--38532-- REDIR: 0x4d894c0 (libc.so.6:__memchr_avx2) redirected to 0x4840050 (memchr) +--38532-- REDIR: 0x495cda0 (libstdc++.so.6:operator delete[](void*)) redirected to 0x483d6e0 (operator delete[](void*)) +==38532== +==38532== HEAP SUMMARY: +==38532== in use at exit: 0 bytes in 0 blocks +==38532== total heap usage: 8,979 allocs, 8,979 frees, 14,589,605 bytes allocated +==38532== +==38532== All heap blocks were freed -- no leaks are possible +==38532== +==38532== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) +==38629== Memcheck, a memory error detector +==38629== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. +==38629== Using Valgrind-3.15.0-608cb11914-20190413 and LibVEX; rerun with -h for copyright info +==38629== Command: build/lottieconverter AnimatedSticker.tgs out pngs 300x300 10 +==38629== +--38629-- Valgrind options: +--38629-- --tool=memcheck +--38629-- --leak-check=full +--38629-- --show-reachable=yes +--38629-- --track-origins=yes +--38629-- -v +--38629-- Contents of /proc/version: +--38629-- Linux version 5.11.0-40-generic (buildd@lgw01-amd64-010) (gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0, GNU ld (GNU Binutils for Ubuntu) 2.34) #44~20.04.2-Ubuntu SMP Tue Oct 26 18:07:44 UTC 2021 +--38629-- +--38629-- Arch and hwcaps: AMD64, LittleEndian, amd64-cx16-lzcnt-rdtscp-sse3-ssse3-avx-avx2-bmi-f16c-rdrand +--38629-- Page sizes: currently 4096, max supported 4096 +--38629-- Valgrind library directory: /usr/lib/x86_64-linux-gnu/valgrind +--38629-- Reading syms from /home/sot/Projects/LottieConverter/build/lottieconverter +--38629-- Reading syms from /lib/x86_64-linux-gnu/ld-2.31.so +--38629-- Considering /lib/x86_64-linux-gnu/ld-2.31.so .. +--38629-- .. CRC mismatch (computed b1e31cec wanted 7bd1f8ba) +--38629-- Considering /lib/x86_64-linux-gnu/ld-2.31.so .. +--38629-- .. CRC mismatch (computed b1e31cec wanted 7bd1f8ba) +--38629-- Considering /usr/lib/debug/lib/x86_64-linux-gnu/ld-2.31.so .. +--38629-- .. CRC is valid +--38629-- Reading syms from /usr/lib/x86_64-linux-gnu/valgrind/memcheck-amd64-linux +--38629-- object doesn't have a symbol table +--38629-- object doesn't have a dynamic symbol table +--38629-- Scheduler: using generic scheduler lock implementation. +--38629-- Reading suppressions file: /usr/lib/x86_64-linux-gnu/valgrind/default.supp +==38629== embedded gdbserver: reading from /tmp/vgdb-pipe-from-vgdb-to-38629-by-sot-on-??? +==38629== embedded gdbserver: writing to /tmp/vgdb-pipe-to-vgdb-from-38629-by-sot-on-??? +==38629== embedded gdbserver: shared mem /tmp/vgdb-pipe-shared-mem-vgdb-38629-by-sot-on-??? +==38629== +==38629== TO CONTROL THIS PROCESS USING vgdb (which you probably +==38629== don't want to do, unless you know exactly what you're doing, +==38629== or are doing some strange experiment): +==38629== /usr/lib/x86_64-linux-gnu/valgrind/../../bin/vgdb --pid=38629 ...command... +==38629== +==38629== TO DEBUG THIS PROCESS USING GDB: start GDB like this +==38629== /path/to/gdb build/lottieconverter +==38629== and then give GDB the following command +==38629== target remote | /usr/lib/x86_64-linux-gnu/valgrind/../../bin/vgdb --pid=38629 +==38629== --pid is optional if only one valgrind process is running +==38629== +--38629-- REDIR: 0x4022f60 (ld-linux-x86-64.so.2:strlen) redirected to 0x580c9ce2 (???) +--38629-- REDIR: 0x4022d30 (ld-linux-x86-64.so.2:index) redirected to 0x580c9cfc (???) +--38629-- Reading syms from /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_core-amd64-linux.so +--38629-- object doesn't have a symbol table +--38629-- Reading syms from /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so +--38629-- object doesn't have a symbol table +==38629== WARNING: new redirection conflicts with existing -- ignoring it +--38629-- old: 0x04022f60 (strlen ) R-> (0000.0) 0x580c9ce2 ??? +--38629-- new: 0x04022f60 (strlen ) R-> (2007.0) 0x0483f060 strlen +--38629-- REDIR: 0x401f740 (ld-linux-x86-64.so.2:strcmp) redirected to 0x483ffd0 (strcmp) +--38629-- REDIR: 0x40234c0 (ld-linux-x86-64.so.2:mempcpy) redirected to 0x4843a20 (mempcpy) +--38629-- Reading syms from /lib/x86_64-linux-gnu/libz.so.1.2.11 +--38629-- object doesn't have a symbol table +--38629-- Reading syms from /lib/x86_64-linux-gnu/libpthread-2.31.so +--38629-- Considering /usr/lib/debug/.build-id/ee/b5b055a9d738db64e450065f88980bebfc9cc2.debug .. +--38629-- .. build-id is valid +--38629-- Reading syms from /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28 +--38629-- object doesn't have a symbol table +--38629-- Reading syms from /lib/x86_64-linux-gnu/libm-2.31.so +--38629-- Considering /lib/x86_64-linux-gnu/libm-2.31.so .. +--38629-- .. CRC mismatch (computed 5f7b2a42 wanted ffb185de) +--38629-- Considering /lib/x86_64-linux-gnu/libm-2.31.so .. +--38629-- .. CRC mismatch (computed 5f7b2a42 wanted ffb185de) +--38629-- Considering /usr/lib/debug/lib/x86_64-linux-gnu/libm-2.31.so .. +--38629-- .. CRC is valid +--38629-- Reading syms from /lib/x86_64-linux-gnu/libgcc_s.so.1 +--38629-- object doesn't have a symbol table +--38629-- Reading syms from /lib/x86_64-linux-gnu/libc-2.31.so +--38629-- Considering /lib/x86_64-linux-gnu/libc-2.31.so .. +--38629-- .. CRC mismatch (computed 11759501 wanted 88150686) +--38629-- Considering /lib/x86_64-linux-gnu/libc-2.31.so .. +--38629-- .. CRC mismatch (computed 11759501 wanted 88150686) +--38629-- Considering /usr/lib/debug/lib/x86_64-linux-gnu/libc-2.31.so .. +--38629-- .. CRC is valid +--38629-- REDIR: 0x4ca5600 (libc.so.6:memmove) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4ca4900 (libc.so.6:strncpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4ca5930 (libc.so.6:strcasecmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4ca4220 (libc.so.6:strcat) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4ca4960 (libc.so.6:rindex) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4ca6dd0 (libc.so.6:rawmemchr) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4cc1e60 (libc.so.6:wmemchr) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4cc19a0 (libc.so.6:wcscmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4ca5760 (libc.so.6:mempcpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4ca5590 (libc.so.6:bcmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4ca4890 (libc.so.6:strncmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4ca42d0 (libc.so.6:strcmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4ca56c0 (libc.so.6:memset) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4cc1960 (libc.so.6:wcschr) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4ca47f0 (libc.so.6:strnlen) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4ca43b0 (libc.so.6:strcspn) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4ca5980 (libc.so.6:strncasecmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4ca4350 (libc.so.6:strcpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4ca5ad0 (libc.so.6:memcpy@@GLIBC_2.14) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4cc30d0 (libc.so.6:wcsnlen) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4cc19e0 (libc.so.6:wcscpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4ca49a0 (libc.so.6:strpbrk) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4ca4280 (libc.so.6:index) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4ca47b0 (libc.so.6:strlen) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4cadd20 (libc.so.6:memrchr) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4ca59d0 (libc.so.6:strcasecmp_l) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4ca5550 (libc.so.6:memchr) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4cc1ab0 (libc.so.6:wcslen) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4ca4c60 (libc.so.6:strspn) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4ca58d0 (libc.so.6:stpncpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4ca5870 (libc.so.6:stpcpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4ca6e10 (libc.so.6:strchrnul) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4ca5a20 (libc.so.6:strncasecmp_l) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4d328e0 (libc.so.6:__memcpy_chk) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38629-- REDIR: 0x4d8d490 (libc.so.6:__strrchr_avx2) redirected to 0x483ea10 (rindex) +--38629-- REDIR: 0x4c9f260 (libc.so.6:malloc) redirected to 0x483b780 (malloc) +--38629-- REDIR: 0x4d8d660 (libc.so.6:__strlen_avx2) redirected to 0x483ef40 (strlen) +--38629-- REDIR: 0x4d89c50 (libc.so.6:__memcmp_avx2_movbe) redirected to 0x48421e0 (bcmp) +--38629-- REDIR: 0x4d88b60 (libc.so.6:__strcmp_avx2) redirected to 0x483fed0 (strcmp) +--38629-- REDIR: 0x4d887b0 (libc.so.6:__strcspn_sse42) redirected to 0x4843e10 (strcspn) +--38629-- REDIR: 0x4ca0c90 (libc.so.6:calloc) redirected to 0x483dce0 (calloc) +--38629-- REDIR: 0x4d90af0 (libc.so.6:__memset_avx2_unaligned_erms) redirected to 0x48428e0 (memset) +--38629-- REDIR: 0x4d8ef30 (libc.so.6:__strncpy_avx2) redirected to 0x483f230 (strncpy) +--38629-- REDIR: 0x4c9f850 (libc.so.6:free) redirected to 0x483c9d0 (free) +--38629-- REDIR: 0x4ca5120 (libc.so.6:__GI_strstr) redirected to 0x4843ca0 (__strstr_sse2) +--38629-- REDIR: 0x4d90670 (libc.so.6:__memcpy_avx_unaligned_erms) redirected to 0x48429f0 (memmove) +--38629-- REDIR: 0x4ca0000 (libc.so.6:realloc) redirected to 0x483df30 (realloc) +--38629-- REDIR: 0x495eb20 (libstdc++.so.6:operator new(unsigned long)) redirected to 0x483bdf0 (operator new(unsigned long)) +--38629-- REDIR: 0x495eb80 (libstdc++.so.6:operator new[](unsigned long)) redirected to 0x483c510 (operator new[](unsigned long)) +--38629-- REDIR: 0x4d8d2a0 (libc.so.6:__strchrnul_avx2) redirected to 0x4843540 (strchrnul) +--38629-- REDIR: 0x4d90650 (libc.so.6:__mempcpy_avx_unaligned_erms) redirected to 0x4843660 (mempcpy) +--38629-- REDIR: 0x495cd70 (libstdc++.so.6:operator delete(void*)) redirected to 0x483cf50 (operator delete(void*)) +--38629-- REDIR: 0x495cd80 (libstdc++.so.6:operator delete(void*, unsigned long)) redirected to 0x483d160 (operator delete(void*, unsigned long)) +--38629-- REDIR: 0x4d894c0 (libc.so.6:__memchr_avx2) redirected to 0x4840050 (memchr) +--38629-- REDIR: 0x495cda0 (libstdc++.so.6:operator delete[](void*)) redirected to 0x483d6e0 (operator delete[](void*)) +==38629== +==38629== HEAP SUMMARY: +==38629== in use at exit: 0 bytes in 0 blocks +==38629== total heap usage: 18,826 allocs, 18,826 frees, 32,091,060 bytes allocated +==38629== +==38629== All heap blocks were freed -- no leaks are possible +==38629== +==38629== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) +==38816== Memcheck, a memory error detector +==38816== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. +==38816== Using Valgrind-3.15.0-608cb11914-20190413 and LibVEX; rerun with -h for copyright info +==38816== Command: build/lottieconverter AnimatedSticker.tgs out.gif gif 300x300 +==38816== +--38816-- Valgrind options: +--38816-- --tool=memcheck +--38816-- --leak-check=full +--38816-- --show-reachable=yes +--38816-- --track-origins=yes +--38816-- -v +--38816-- Contents of /proc/version: +--38816-- Linux version 5.11.0-40-generic (buildd@lgw01-amd64-010) (gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0, GNU ld (GNU Binutils for Ubuntu) 2.34) #44~20.04.2-Ubuntu SMP Tue Oct 26 18:07:44 UTC 2021 +--38816-- +--38816-- Arch and hwcaps: AMD64, LittleEndian, amd64-cx16-lzcnt-rdtscp-sse3-ssse3-avx-avx2-bmi-f16c-rdrand +--38816-- Page sizes: currently 4096, max supported 4096 +--38816-- Valgrind library directory: /usr/lib/x86_64-linux-gnu/valgrind +--38816-- Reading syms from /home/sot/Projects/LottieConverter/build/lottieconverter +--38816-- Reading syms from /lib/x86_64-linux-gnu/ld-2.31.so +--38816-- Considering /lib/x86_64-linux-gnu/ld-2.31.so .. +--38816-- .. CRC mismatch (computed b1e31cec wanted 7bd1f8ba) +--38816-- Considering /lib/x86_64-linux-gnu/ld-2.31.so .. +--38816-- .. CRC mismatch (computed b1e31cec wanted 7bd1f8ba) +--38816-- Considering /usr/lib/debug/lib/x86_64-linux-gnu/ld-2.31.so .. +--38816-- .. CRC is valid +--38816-- Reading syms from /usr/lib/x86_64-linux-gnu/valgrind/memcheck-amd64-linux +--38816-- object doesn't have a symbol table +--38816-- object doesn't have a dynamic symbol table +--38816-- Scheduler: using generic scheduler lock implementation. +--38816-- Reading suppressions file: /usr/lib/x86_64-linux-gnu/valgrind/default.supp +==38816== embedded gdbserver: reading from /tmp/vgdb-pipe-from-vgdb-to-38816-by-sot-on-??? +==38816== embedded gdbserver: writing to /tmp/vgdb-pipe-to-vgdb-from-38816-by-sot-on-??? +==38816== embedded gdbserver: shared mem /tmp/vgdb-pipe-shared-mem-vgdb-38816-by-sot-on-??? +==38816== +==38816== TO CONTROL THIS PROCESS USING vgdb (which you probably +==38816== don't want to do, unless you know exactly what you're doing, +==38816== or are doing some strange experiment): +==38816== /usr/lib/x86_64-linux-gnu/valgrind/../../bin/vgdb --pid=38816 ...command... +==38816== +==38816== TO DEBUG THIS PROCESS USING GDB: start GDB like this +==38816== /path/to/gdb build/lottieconverter +==38816== and then give GDB the following command +==38816== target remote | /usr/lib/x86_64-linux-gnu/valgrind/../../bin/vgdb --pid=38816 +==38816== --pid is optional if only one valgrind process is running +==38816== +--38816-- REDIR: 0x4022f60 (ld-linux-x86-64.so.2:strlen) redirected to 0x580c9ce2 (???) +--38816-- REDIR: 0x4022d30 (ld-linux-x86-64.so.2:index) redirected to 0x580c9cfc (???) +--38816-- Reading syms from /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_core-amd64-linux.so +--38816-- object doesn't have a symbol table +--38816-- Reading syms from /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so +--38816-- object doesn't have a symbol table +==38816== WARNING: new redirection conflicts with existing -- ignoring it +--38816-- old: 0x04022f60 (strlen ) R-> (0000.0) 0x580c9ce2 ??? +--38816-- new: 0x04022f60 (strlen ) R-> (2007.0) 0x0483f060 strlen +--38816-- REDIR: 0x401f740 (ld-linux-x86-64.so.2:strcmp) redirected to 0x483ffd0 (strcmp) +--38816-- REDIR: 0x40234c0 (ld-linux-x86-64.so.2:mempcpy) redirected to 0x4843a20 (mempcpy) +--38816-- Reading syms from /lib/x86_64-linux-gnu/libz.so.1.2.11 +--38816-- object doesn't have a symbol table +--38816-- Reading syms from /lib/x86_64-linux-gnu/libpthread-2.31.so +--38816-- Considering /usr/lib/debug/.build-id/ee/b5b055a9d738db64e450065f88980bebfc9cc2.debug .. +--38816-- .. build-id is valid +--38816-- Reading syms from /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28 +--38816-- object doesn't have a symbol table +--38816-- Reading syms from /lib/x86_64-linux-gnu/libm-2.31.so +--38816-- Considering /lib/x86_64-linux-gnu/libm-2.31.so .. +--38816-- .. CRC mismatch (computed 5f7b2a42 wanted ffb185de) +--38816-- Considering /lib/x86_64-linux-gnu/libm-2.31.so .. +--38816-- .. CRC mismatch (computed 5f7b2a42 wanted ffb185de) +--38816-- Considering /usr/lib/debug/lib/x86_64-linux-gnu/libm-2.31.so .. +--38816-- .. CRC is valid +--38816-- Reading syms from /lib/x86_64-linux-gnu/libgcc_s.so.1 +--38816-- object doesn't have a symbol table +--38816-- Reading syms from /lib/x86_64-linux-gnu/libc-2.31.so +--38816-- Considering /lib/x86_64-linux-gnu/libc-2.31.so .. +--38816-- .. CRC mismatch (computed 11759501 wanted 88150686) +--38816-- Considering /lib/x86_64-linux-gnu/libc-2.31.so .. +--38816-- .. CRC mismatch (computed 11759501 wanted 88150686) +--38816-- Considering /usr/lib/debug/lib/x86_64-linux-gnu/libc-2.31.so .. +--38816-- .. CRC is valid +--38816-- REDIR: 0x4ca5600 (libc.so.6:memmove) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4ca4900 (libc.so.6:strncpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4ca5930 (libc.so.6:strcasecmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4ca4220 (libc.so.6:strcat) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4ca4960 (libc.so.6:rindex) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4ca6dd0 (libc.so.6:rawmemchr) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4cc1e60 (libc.so.6:wmemchr) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4cc19a0 (libc.so.6:wcscmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4ca5760 (libc.so.6:mempcpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4ca5590 (libc.so.6:bcmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4ca4890 (libc.so.6:strncmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4ca42d0 (libc.so.6:strcmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4ca56c0 (libc.so.6:memset) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4cc1960 (libc.so.6:wcschr) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4ca47f0 (libc.so.6:strnlen) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4ca43b0 (libc.so.6:strcspn) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4ca5980 (libc.so.6:strncasecmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4ca4350 (libc.so.6:strcpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4ca5ad0 (libc.so.6:memcpy@@GLIBC_2.14) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4cc30d0 (libc.so.6:wcsnlen) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4cc19e0 (libc.so.6:wcscpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4ca49a0 (libc.so.6:strpbrk) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4ca4280 (libc.so.6:index) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4ca47b0 (libc.so.6:strlen) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4cadd20 (libc.so.6:memrchr) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4ca59d0 (libc.so.6:strcasecmp_l) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4ca5550 (libc.so.6:memchr) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4cc1ab0 (libc.so.6:wcslen) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4ca4c60 (libc.so.6:strspn) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4ca58d0 (libc.so.6:stpncpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4ca5870 (libc.so.6:stpcpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4ca6e10 (libc.so.6:strchrnul) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4ca5a20 (libc.so.6:strncasecmp_l) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4d328e0 (libc.so.6:__memcpy_chk) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--38816-- REDIR: 0x4d8d490 (libc.so.6:__strrchr_avx2) redirected to 0x483ea10 (rindex) +--38816-- REDIR: 0x4c9f260 (libc.so.6:malloc) redirected to 0x483b780 (malloc) +--38816-- REDIR: 0x4d8d660 (libc.so.6:__strlen_avx2) redirected to 0x483ef40 (strlen) +--38816-- REDIR: 0x4d89c50 (libc.so.6:__memcmp_avx2_movbe) redirected to 0x48421e0 (bcmp) +--38816-- REDIR: 0x4d88b60 (libc.so.6:__strcmp_avx2) redirected to 0x483fed0 (strcmp) +--38816-- REDIR: 0x4d887b0 (libc.so.6:__strcspn_sse42) redirected to 0x4843e10 (strcspn) +--38816-- REDIR: 0x4ca0c90 (libc.so.6:calloc) redirected to 0x483dce0 (calloc) +--38816-- REDIR: 0x4d90af0 (libc.so.6:__memset_avx2_unaligned_erms) redirected to 0x48428e0 (memset) +--38816-- REDIR: 0x4d8ef30 (libc.so.6:__strncpy_avx2) redirected to 0x483f230 (strncpy) +--38816-- REDIR: 0x4c9f850 (libc.so.6:free) redirected to 0x483c9d0 (free) +--38816-- REDIR: 0x4ca5120 (libc.so.6:__GI_strstr) redirected to 0x4843ca0 (__strstr_sse2) +--38816-- REDIR: 0x4d90670 (libc.so.6:__memcpy_avx_unaligned_erms) redirected to 0x48429f0 (memmove) +--38816-- REDIR: 0x4ca0000 (libc.so.6:realloc) redirected to 0x483df30 (realloc) +--38816-- REDIR: 0x495eb20 (libstdc++.so.6:operator new(unsigned long)) redirected to 0x483bdf0 (operator new(unsigned long)) +--38816-- REDIR: 0x495eb80 (libstdc++.so.6:operator new[](unsigned long)) redirected to 0x483c510 (operator new[](unsigned long)) +--38816-- REDIR: 0x4d8d2a0 (libc.so.6:__strchrnul_avx2) redirected to 0x4843540 (strchrnul) +--38816-- REDIR: 0x4d90650 (libc.so.6:__mempcpy_avx_unaligned_erms) redirected to 0x4843660 (mempcpy) +--38816-- REDIR: 0x495cd70 (libstdc++.so.6:operator delete(void*)) redirected to 0x483cf50 (operator delete(void*)) +--38816-- REDIR: 0x495cd80 (libstdc++.so.6:operator delete(void*, unsigned long)) redirected to 0x483d160 (operator delete(void*, unsigned long)) +--38816-- REDIR: 0x4d894c0 (libc.so.6:__memchr_avx2) redirected to 0x4840050 (memchr) +--38816-- REDIR: 0x495cda0 (libstdc++.so.6:operator delete[](void*)) redirected to 0x483d6e0 (operator delete[](void*)) +==38816== +==38816== HEAP SUMMARY: +==38816== in use at exit: 1,264 bytes in 3 blocks +==38816== total heap usage: 17,832 allocs, 17,829 frees, 49,138,164 bytes allocated +==38816== +==38816== Searching for pointers to 3 not-freed blocks +==38816== Checked 140,808 bytes +==38816== +==38816== 472 bytes in 1 blocks are still reachable in loss record 1 of 3 +==38816== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) +==38816== by 0x4C87AAD: __fopen_internal (iofopen.c:65) +==38816== by 0x4C87AAD: fopen@@GLIBC_2.2.5 (iofopen.c:86) +==38816== by 0x110936: main (lottie_export.cpp:424) +==38816== +==38816== 768 bytes in 1 blocks are indirectly lost in loss record 2 of 3 +==38816== at 0x483DD99: calloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) +==38816== by 0x1B9608: GifMakeMapObject (in /home/sot/Projects/LottieConverter/build/lottieconverter) +==38816== by 0x10F6D2: convert_and_write_to(unsigned char*, unsigned char, int, int, unsigned int, file*) (lottie_export.cpp:154) +==38816== by 0x110B25: main (lottie_export.cpp:463) +==38816== +==38816== 792 (24 direct, 768 indirect) bytes in 1 blocks are definitely lost in loss record 3 of 3 +==38816== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) +==38816== by 0x1B95F0: GifMakeMapObject (in /home/sot/Projects/LottieConverter/build/lottieconverter) +==38816== by 0x10F6D2: convert_and_write_to(unsigned char*, unsigned char, int, int, unsigned int, file*) (lottie_export.cpp:154) +==38816== by 0x110B25: main (lottie_export.cpp:463) +==38816== +==38816== LEAK SUMMARY: +==38816== definitely lost: 24 bytes in 1 blocks +==38816== indirectly lost: 768 bytes in 1 blocks +==38816== possibly lost: 0 bytes in 0 blocks +==38816== still reachable: 472 bytes in 1 blocks +==38816== suppressed: 0 bytes in 0 blocks +==38816== +==38816== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0) +==49458== Memcheck, a memory error detector +==49458== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. +==49458== Using Valgrind-3.15.0-608cb11914-20190413 and LibVEX; rerun with -h for copyright info +==49458== Command: build/lottieconverter - out.gif gif 300x300 10 +==49458== +--49458-- Valgrind options: +--49458-- --tool=memcheck +--49458-- --leak-check=full +--49458-- --show-reachable=yes +--49458-- --track-origins=yes +--49458-- -v +--49458-- Contents of /proc/version: +--49458-- Linux version 5.11.0-40-generic (buildd@lgw01-amd64-010) (gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0, GNU ld (GNU Binutils for Ubuntu) 2.34) #44~20.04.2-Ubuntu SMP Tue Oct 26 18:07:44 UTC 2021 +--49458-- +--49458-- Arch and hwcaps: AMD64, LittleEndian, amd64-cx16-lzcnt-rdtscp-sse3-ssse3-avx-avx2-bmi-f16c-rdrand +--49458-- Page sizes: currently 4096, max supported 4096 +--49458-- Valgrind library directory: /usr/lib/x86_64-linux-gnu/valgrind +--49458-- Reading syms from /home/sot/Projects/LottieConverter/build/lottieconverter +--49458-- Reading syms from /lib/x86_64-linux-gnu/ld-2.31.so +--49458-- Considering /lib/x86_64-linux-gnu/ld-2.31.so .. +--49458-- .. CRC mismatch (computed b1e31cec wanted 7bd1f8ba) +--49458-- Considering /lib/x86_64-linux-gnu/ld-2.31.so .. +--49458-- .. CRC mismatch (computed b1e31cec wanted 7bd1f8ba) +--49458-- Considering /usr/lib/debug/lib/x86_64-linux-gnu/ld-2.31.so .. +--49458-- .. CRC is valid +--49458-- Reading syms from /usr/lib/x86_64-linux-gnu/valgrind/memcheck-amd64-linux +--49458-- object doesn't have a symbol table +--49458-- object doesn't have a dynamic symbol table +--49458-- Scheduler: using generic scheduler lock implementation. +--49458-- Reading suppressions file: /usr/lib/x86_64-linux-gnu/valgrind/default.supp +==49458== embedded gdbserver: reading from /tmp/vgdb-pipe-from-vgdb-to-49458-by-sot-on-??? +==49458== embedded gdbserver: writing to /tmp/vgdb-pipe-to-vgdb-from-49458-by-sot-on-??? +==49458== embedded gdbserver: shared mem /tmp/vgdb-pipe-shared-mem-vgdb-49458-by-sot-on-??? +==49458== +==49458== TO CONTROL THIS PROCESS USING vgdb (which you probably +==49458== don't want to do, unless you know exactly what you're doing, +==49458== or are doing some strange experiment): +==49458== /usr/lib/x86_64-linux-gnu/valgrind/../../bin/vgdb --pid=49458 ...command... +==49458== +==49458== TO DEBUG THIS PROCESS USING GDB: start GDB like this +==49458== /path/to/gdb build/lottieconverter +==49458== and then give GDB the following command +==49458== target remote | /usr/lib/x86_64-linux-gnu/valgrind/../../bin/vgdb --pid=49458 +==49458== --pid is optional if only one valgrind process is running +==49458== +--49458-- REDIR: 0x4022f60 (ld-linux-x86-64.so.2:strlen) redirected to 0x580c9ce2 (???) +--49458-- REDIR: 0x4022d30 (ld-linux-x86-64.so.2:index) redirected to 0x580c9cfc (???) +--49458-- Reading syms from /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_core-amd64-linux.so +--49458-- object doesn't have a symbol table +--49458-- Reading syms from /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so +--49458-- object doesn't have a symbol table +==49458== WARNING: new redirection conflicts with existing -- ignoring it +--49458-- old: 0x04022f60 (strlen ) R-> (0000.0) 0x580c9ce2 ??? +--49458-- new: 0x04022f60 (strlen ) R-> (2007.0) 0x0483f060 strlen +--49458-- REDIR: 0x401f740 (ld-linux-x86-64.so.2:strcmp) redirected to 0x483ffd0 (strcmp) +--49458-- REDIR: 0x40234c0 (ld-linux-x86-64.so.2:mempcpy) redirected to 0x4843a20 (mempcpy) +--49458-- Reading syms from /lib/x86_64-linux-gnu/libz.so.1.2.11 +--49458-- object doesn't have a symbol table +--49458-- Reading syms from /lib/x86_64-linux-gnu/libpthread-2.31.so +--49458-- Considering /usr/lib/debug/.build-id/ee/b5b055a9d738db64e450065f88980bebfc9cc2.debug .. +--49458-- .. build-id is valid +--49458-- Reading syms from /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28 +--49458-- object doesn't have a symbol table +--49458-- Reading syms from /lib/x86_64-linux-gnu/libm-2.31.so +--49458-- Considering /lib/x86_64-linux-gnu/libm-2.31.so .. +--49458-- .. CRC mismatch (computed 5f7b2a42 wanted ffb185de) +--49458-- Considering /lib/x86_64-linux-gnu/libm-2.31.so .. +--49458-- .. CRC mismatch (computed 5f7b2a42 wanted ffb185de) +--49458-- Considering /usr/lib/debug/lib/x86_64-linux-gnu/libm-2.31.so .. +--49458-- .. CRC is valid +--49458-- Reading syms from /lib/x86_64-linux-gnu/libgcc_s.so.1 +--49458-- object doesn't have a symbol table +--49458-- Reading syms from /lib/x86_64-linux-gnu/libc-2.31.so +--49458-- Considering /lib/x86_64-linux-gnu/libc-2.31.so .. +--49458-- .. CRC mismatch (computed 11759501 wanted 88150686) +--49458-- Considering /lib/x86_64-linux-gnu/libc-2.31.so .. +--49458-- .. CRC mismatch (computed 11759501 wanted 88150686) +--49458-- Considering /usr/lib/debug/lib/x86_64-linux-gnu/libc-2.31.so .. +--49458-- .. CRC is valid +--49458-- REDIR: 0x4ca5600 (libc.so.6:memmove) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4ca4900 (libc.so.6:strncpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4ca5930 (libc.so.6:strcasecmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4ca4220 (libc.so.6:strcat) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4ca4960 (libc.so.6:rindex) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4ca6dd0 (libc.so.6:rawmemchr) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4cc1e60 (libc.so.6:wmemchr) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4cc19a0 (libc.so.6:wcscmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4ca5760 (libc.so.6:mempcpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4ca5590 (libc.so.6:bcmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4ca4890 (libc.so.6:strncmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4ca42d0 (libc.so.6:strcmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4ca56c0 (libc.so.6:memset) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4cc1960 (libc.so.6:wcschr) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4ca47f0 (libc.so.6:strnlen) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4ca43b0 (libc.so.6:strcspn) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4ca5980 (libc.so.6:strncasecmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4ca4350 (libc.so.6:strcpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4ca5ad0 (libc.so.6:memcpy@@GLIBC_2.14) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4cc30d0 (libc.so.6:wcsnlen) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4cc19e0 (libc.so.6:wcscpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4ca49a0 (libc.so.6:strpbrk) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4ca4280 (libc.so.6:index) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4ca47b0 (libc.so.6:strlen) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4cadd20 (libc.so.6:memrchr) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4ca59d0 (libc.so.6:strcasecmp_l) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4ca5550 (libc.so.6:memchr) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4cc1ab0 (libc.so.6:wcslen) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4ca4c60 (libc.so.6:strspn) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4ca58d0 (libc.so.6:stpncpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4ca5870 (libc.so.6:stpcpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4ca6e10 (libc.so.6:strchrnul) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4ca5a20 (libc.so.6:strncasecmp_l) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4d328e0 (libc.so.6:__memcpy_chk) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49458-- REDIR: 0x4d8d490 (libc.so.6:__strrchr_avx2) redirected to 0x483ea10 (rindex) +--49458-- REDIR: 0x4c9f260 (libc.so.6:malloc) redirected to 0x483b780 (malloc) +--49458-- REDIR: 0x4d8d660 (libc.so.6:__strlen_avx2) redirected to 0x483ef40 (strlen) +--49458-- REDIR: 0x4d89c50 (libc.so.6:__memcmp_avx2_movbe) redirected to 0x48421e0 (bcmp) +--49458-- REDIR: 0x4d88b60 (libc.so.6:__strcmp_avx2) redirected to 0x483fed0 (strcmp) +--49458-- REDIR: 0x4d887b0 (libc.so.6:__strcspn_sse42) redirected to 0x4843e10 (strcspn) +--49458-- REDIR: 0x4ca0c90 (libc.so.6:calloc) redirected to 0x483dce0 (calloc) +--49458-- REDIR: 0x4d90af0 (libc.so.6:__memset_avx2_unaligned_erms) redirected to 0x48428e0 (memset) +--49458-- REDIR: 0x4d8ef30 (libc.so.6:__strncpy_avx2) redirected to 0x483f230 (strncpy) +--49458-- REDIR: 0x4c9f850 (libc.so.6:free) redirected to 0x483c9d0 (free) +--49458-- REDIR: 0x4ca5120 (libc.so.6:__GI_strstr) redirected to 0x4843ca0 (__strstr_sse2) +--49458-- REDIR: 0x4d90670 (libc.so.6:__memcpy_avx_unaligned_erms) redirected to 0x48429f0 (memmove) +--49458-- REDIR: 0x4ca0000 (libc.so.6:realloc) redirected to 0x483df30 (realloc) +--49458-- REDIR: 0x495eb20 (libstdc++.so.6:operator new(unsigned long)) redirected to 0x483bdf0 (operator new(unsigned long)) +--49458-- REDIR: 0x495eb80 (libstdc++.so.6:operator new[](unsigned long)) redirected to 0x483c510 (operator new[](unsigned long)) +--49458-- REDIR: 0x4d8d2a0 (libc.so.6:__strchrnul_avx2) redirected to 0x4843540 (strchrnul) +--49458-- REDIR: 0x4d90650 (libc.so.6:__mempcpy_avx_unaligned_erms) redirected to 0x4843660 (mempcpy) +--49458-- REDIR: 0x495cd70 (libstdc++.so.6:operator delete(void*)) redirected to 0x483cf50 (operator delete(void*)) +--49458-- REDIR: 0x495cd80 (libstdc++.so.6:operator delete(void*, unsigned long)) redirected to 0x483d160 (operator delete(void*, unsigned long)) +--49458-- REDIR: 0x4d894c0 (libc.so.6:__memchr_avx2) redirected to 0x4840050 (memchr) +--49458-- REDIR: 0x495cda0 (libstdc++.so.6:operator delete[](void*)) redirected to 0x483d6e0 (operator delete[](void*)) +==49458== +==49458== HEAP SUMMARY: +==49458== in use at exit: 472 bytes in 1 blocks +==49458== total heap usage: 17,857 allocs, 17,856 frees, 49,212,985 bytes allocated +==49458== +==49458== Searching for pointers to 1 not-freed blocks +==49458== Checked 140,808 bytes +==49458== +==49458== 472 bytes in 1 blocks are still reachable in loss record 1 of 1 +==49458== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) +==49458== by 0x4C87AAD: __fopen_internal (iofopen.c:65) +==49458== by 0x4C87AAD: fopen@@GLIBC_2.2.5 (iofopen.c:86) +==49458== by 0x1109B2: main (lottie_export.cpp:441) +==49458== +==49458== LEAK SUMMARY: +==49458== definitely lost: 0 bytes in 0 blocks +==49458== indirectly lost: 0 bytes in 0 blocks +==49458== possibly lost: 0 bytes in 0 blocks +==49458== still reachable: 472 bytes in 1 blocks +==49458== suppressed: 0 bytes in 0 blocks +==49458== +==49458== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) +==49548== Memcheck, a memory error detector +==49548== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. +==49548== Using Valgrind-3.15.0-608cb11914-20190413 and LibVEX; rerun with -h for copyright info +==49548== Command: build/lottieconverter AnimatedSticker.tgs out.gif gif 300x300 10 +==49548== +--49548-- Valgrind options: +--49548-- --tool=memcheck +--49548-- --leak-check=full +--49548-- --show-reachable=yes +--49548-- --track-origins=yes +--49548-- -v +--49548-- Contents of /proc/version: +--49548-- Linux version 5.11.0-40-generic (buildd@lgw01-amd64-010) (gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0, GNU ld (GNU Binutils for Ubuntu) 2.34) #44~20.04.2-Ubuntu SMP Tue Oct 26 18:07:44 UTC 2021 +--49548-- +--49548-- Arch and hwcaps: AMD64, LittleEndian, amd64-cx16-lzcnt-rdtscp-sse3-ssse3-avx-avx2-bmi-f16c-rdrand +--49548-- Page sizes: currently 4096, max supported 4096 +--49548-- Valgrind library directory: /usr/lib/x86_64-linux-gnu/valgrind +--49548-- Reading syms from /home/sot/Projects/LottieConverter/build/lottieconverter +--49548-- Reading syms from /lib/x86_64-linux-gnu/ld-2.31.so +--49548-- Considering /lib/x86_64-linux-gnu/ld-2.31.so .. +--49548-- .. CRC mismatch (computed b1e31cec wanted 7bd1f8ba) +--49548-- Considering /lib/x86_64-linux-gnu/ld-2.31.so .. +--49548-- .. CRC mismatch (computed b1e31cec wanted 7bd1f8ba) +--49548-- Considering /usr/lib/debug/lib/x86_64-linux-gnu/ld-2.31.so .. +--49548-- .. CRC is valid +--49548-- Reading syms from /usr/lib/x86_64-linux-gnu/valgrind/memcheck-amd64-linux +--49548-- object doesn't have a symbol table +--49548-- object doesn't have a dynamic symbol table +--49548-- Scheduler: using generic scheduler lock implementation. +--49548-- Reading suppressions file: /usr/lib/x86_64-linux-gnu/valgrind/default.supp +==49548== embedded gdbserver: reading from /tmp/vgdb-pipe-from-vgdb-to-49548-by-sot-on-??? +==49548== embedded gdbserver: writing to /tmp/vgdb-pipe-to-vgdb-from-49548-by-sot-on-??? +==49548== embedded gdbserver: shared mem /tmp/vgdb-pipe-shared-mem-vgdb-49548-by-sot-on-??? +==49548== +==49548== TO CONTROL THIS PROCESS USING vgdb (which you probably +==49548== don't want to do, unless you know exactly what you're doing, +==49548== or are doing some strange experiment): +==49548== /usr/lib/x86_64-linux-gnu/valgrind/../../bin/vgdb --pid=49548 ...command... +==49548== +==49548== TO DEBUG THIS PROCESS USING GDB: start GDB like this +==49548== /path/to/gdb build/lottieconverter +==49548== and then give GDB the following command +==49548== target remote | /usr/lib/x86_64-linux-gnu/valgrind/../../bin/vgdb --pid=49548 +==49548== --pid is optional if only one valgrind process is running +==49548== +--49548-- REDIR: 0x4022f60 (ld-linux-x86-64.so.2:strlen) redirected to 0x580c9ce2 (???) +--49548-- REDIR: 0x4022d30 (ld-linux-x86-64.so.2:index) redirected to 0x580c9cfc (???) +--49548-- Reading syms from /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_core-amd64-linux.so +--49548-- object doesn't have a symbol table +--49548-- Reading syms from /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so +--49548-- object doesn't have a symbol table +==49548== WARNING: new redirection conflicts with existing -- ignoring it +--49548-- old: 0x04022f60 (strlen ) R-> (0000.0) 0x580c9ce2 ??? +--49548-- new: 0x04022f60 (strlen ) R-> (2007.0) 0x0483f060 strlen +--49548-- REDIR: 0x401f740 (ld-linux-x86-64.so.2:strcmp) redirected to 0x483ffd0 (strcmp) +--49548-- REDIR: 0x40234c0 (ld-linux-x86-64.so.2:mempcpy) redirected to 0x4843a20 (mempcpy) +--49548-- Reading syms from /lib/x86_64-linux-gnu/libz.so.1.2.11 +--49548-- object doesn't have a symbol table +--49548-- Reading syms from /lib/x86_64-linux-gnu/libpthread-2.31.so +--49548-- Considering /usr/lib/debug/.build-id/ee/b5b055a9d738db64e450065f88980bebfc9cc2.debug .. +--49548-- .. build-id is valid +--49548-- Reading syms from /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28 +--49548-- object doesn't have a symbol table +--49548-- Reading syms from /lib/x86_64-linux-gnu/libm-2.31.so +--49548-- Considering /lib/x86_64-linux-gnu/libm-2.31.so .. +--49548-- .. CRC mismatch (computed 5f7b2a42 wanted ffb185de) +--49548-- Considering /lib/x86_64-linux-gnu/libm-2.31.so .. +--49548-- .. CRC mismatch (computed 5f7b2a42 wanted ffb185de) +--49548-- Considering /usr/lib/debug/lib/x86_64-linux-gnu/libm-2.31.so .. +--49548-- .. CRC is valid +--49548-- Reading syms from /lib/x86_64-linux-gnu/libgcc_s.so.1 +--49548-- object doesn't have a symbol table +--49548-- Reading syms from /lib/x86_64-linux-gnu/libc-2.31.so +--49548-- Considering /lib/x86_64-linux-gnu/libc-2.31.so .. +--49548-- .. CRC mismatch (computed 11759501 wanted 88150686) +--49548-- Considering /lib/x86_64-linux-gnu/libc-2.31.so .. +--49548-- .. CRC mismatch (computed 11759501 wanted 88150686) +--49548-- Considering /usr/lib/debug/lib/x86_64-linux-gnu/libc-2.31.so .. +--49548-- .. CRC is valid +--49548-- REDIR: 0x4ca5600 (libc.so.6:memmove) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4ca4900 (libc.so.6:strncpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4ca5930 (libc.so.6:strcasecmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4ca4220 (libc.so.6:strcat) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4ca4960 (libc.so.6:rindex) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4ca6dd0 (libc.so.6:rawmemchr) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4cc1e60 (libc.so.6:wmemchr) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4cc19a0 (libc.so.6:wcscmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4ca5760 (libc.so.6:mempcpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4ca5590 (libc.so.6:bcmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4ca4890 (libc.so.6:strncmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4ca42d0 (libc.so.6:strcmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4ca56c0 (libc.so.6:memset) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4cc1960 (libc.so.6:wcschr) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4ca47f0 (libc.so.6:strnlen) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4ca43b0 (libc.so.6:strcspn) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4ca5980 (libc.so.6:strncasecmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4ca4350 (libc.so.6:strcpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4ca5ad0 (libc.so.6:memcpy@@GLIBC_2.14) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4cc30d0 (libc.so.6:wcsnlen) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4cc19e0 (libc.so.6:wcscpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4ca49a0 (libc.so.6:strpbrk) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4ca4280 (libc.so.6:index) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4ca47b0 (libc.so.6:strlen) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4cadd20 (libc.so.6:memrchr) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4ca59d0 (libc.so.6:strcasecmp_l) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4ca5550 (libc.so.6:memchr) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4cc1ab0 (libc.so.6:wcslen) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4ca4c60 (libc.so.6:strspn) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4ca58d0 (libc.so.6:stpncpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4ca5870 (libc.so.6:stpcpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4ca6e10 (libc.so.6:strchrnul) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4ca5a20 (libc.so.6:strncasecmp_l) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4d328e0 (libc.so.6:__memcpy_chk) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--49548-- REDIR: 0x4d8d490 (libc.so.6:__strrchr_avx2) redirected to 0x483ea10 (rindex) +--49548-- REDIR: 0x4c9f260 (libc.so.6:malloc) redirected to 0x483b780 (malloc) +--49548-- REDIR: 0x4d8d660 (libc.so.6:__strlen_avx2) redirected to 0x483ef40 (strlen) +--49548-- REDIR: 0x4d89c50 (libc.so.6:__memcmp_avx2_movbe) redirected to 0x48421e0 (bcmp) +--49548-- REDIR: 0x4d88b60 (libc.so.6:__strcmp_avx2) redirected to 0x483fed0 (strcmp) +--49548-- REDIR: 0x4d887b0 (libc.so.6:__strcspn_sse42) redirected to 0x4843e10 (strcspn) +--49548-- REDIR: 0x4ca0c90 (libc.so.6:calloc) redirected to 0x483dce0 (calloc) +--49548-- REDIR: 0x4d90af0 (libc.so.6:__memset_avx2_unaligned_erms) redirected to 0x48428e0 (memset) +--49548-- REDIR: 0x4d8ef30 (libc.so.6:__strncpy_avx2) redirected to 0x483f230 (strncpy) +--49548-- REDIR: 0x4c9f850 (libc.so.6:free) redirected to 0x483c9d0 (free) +--49548-- REDIR: 0x4ca5120 (libc.so.6:__GI_strstr) redirected to 0x4843ca0 (__strstr_sse2) +--49548-- REDIR: 0x4d90670 (libc.so.6:__memcpy_avx_unaligned_erms) redirected to 0x48429f0 (memmove) +--49548-- REDIR: 0x4ca0000 (libc.so.6:realloc) redirected to 0x483df30 (realloc) +--49548-- REDIR: 0x495eb20 (libstdc++.so.6:operator new(unsigned long)) redirected to 0x483bdf0 (operator new(unsigned long)) +--49548-- REDIR: 0x495eb80 (libstdc++.so.6:operator new[](unsigned long)) redirected to 0x483c510 (operator new[](unsigned long)) +--49548-- REDIR: 0x4d8d2a0 (libc.so.6:__strchrnul_avx2) redirected to 0x4843540 (strchrnul) +--49548-- REDIR: 0x4d90650 (libc.so.6:__mempcpy_avx_unaligned_erms) redirected to 0x4843660 (mempcpy) +--49548-- REDIR: 0x495cd70 (libstdc++.so.6:operator delete(void*)) redirected to 0x483cf50 (operator delete(void*)) +--49548-- REDIR: 0x495cd80 (libstdc++.so.6:operator delete(void*, unsigned long)) redirected to 0x483d160 (operator delete(void*, unsigned long)) +--49548-- REDIR: 0x4d894c0 (libc.so.6:__memchr_avx2) redirected to 0x4840050 (memchr) +--49548-- REDIR: 0x495cda0 (libstdc++.so.6:operator delete[](void*)) redirected to 0x483d6e0 (operator delete[](void*)) +==49548== +==49548== HEAP SUMMARY: +==49548== in use at exit: 472 bytes in 1 blocks +==49548== total heap usage: 17,842 allocs, 17,841 frees, 49,183,027 bytes allocated +==49548== +==49548== Searching for pointers to 1 not-freed blocks +==49548== Checked 140,824 bytes +==49548== +==49548== 472 bytes in 1 blocks are still reachable in loss record 1 of 1 +==49548== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) +==49548== by 0x4C87AAD: __fopen_internal (iofopen.c:65) +==49548== by 0x4C87AAD: fopen@@GLIBC_2.2.5 (iofopen.c:86) +==49548== by 0x1109B2: main (lottie_export.cpp:441) +==49548== +==49548== LEAK SUMMARY: +==49548== definitely lost: 0 bytes in 0 blocks +==49548== indirectly lost: 0 bytes in 0 blocks +==49548== possibly lost: 0 bytes in 0 blocks +==49548== still reachable: 472 bytes in 1 blocks +==49548== suppressed: 0 bytes in 0 blocks +==49548== +==49548== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) +==50096== Memcheck, a memory error detector +==50096== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. +==50096== Using Valgrind-3.15.0-608cb11914-20190413 and LibVEX; rerun with -h for copyright info +==50096== Command: build/lottieconverter AnimatedSticker.tgs out.gif gif 300x300 10 +==50096== +--50096-- Valgrind options: +--50096-- --tool=memcheck +--50096-- --leak-check=full +--50096-- --show-reachable=yes +--50096-- --track-origins=yes +--50096-- -v +--50096-- Contents of /proc/version: +--50096-- Linux version 5.11.0-40-generic (buildd@lgw01-amd64-010) (gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0, GNU ld (GNU Binutils for Ubuntu) 2.34) #44~20.04.2-Ubuntu SMP Tue Oct 26 18:07:44 UTC 2021 +--50096-- +--50096-- Arch and hwcaps: AMD64, LittleEndian, amd64-cx16-lzcnt-rdtscp-sse3-ssse3-avx-avx2-bmi-f16c-rdrand +--50096-- Page sizes: currently 4096, max supported 4096 +--50096-- Valgrind library directory: /usr/lib/x86_64-linux-gnu/valgrind +--50096-- Reading syms from /home/sot/Projects/LottieConverter/build/lottieconverter +--50096-- warning: DiCfSI 0x108000 .. 0x108004 outside mapped rx segments (NONE) +--50096-- warning: DiCfSI 0x108005 .. 0x108007 outside mapped rx segments (NONE) +--50096-- warning: DiCfSI 0x108008 .. 0x10800c outside mapped rx segments (NONE) +--50096-- warning: DiCfSI 0x10800d .. 0x108067 outside mapped rx segments (NONE) +--50096-- warning: DiCfSI 0x108068 .. 0x108068 outside mapped rx segments (NONE) +--50096-- warning: DiCfSI 0x108000 .. 0x108004 outside mapped rx segments (NONE) +--50096-- warning: DiCfSI 0x108005 .. 0x108007 outside mapped rx segments (NONE) +--50096-- warning: DiCfSI 0x108008 .. 0x10801c outside mapped rx segments (NONE) +--50096-- warning: DiCfSI 0x10801d .. 0x10801d outside mapped rx segments (NONE) +--50096-- warning: DiCfSI 0x108000 .. 0x108004 outside mapped rx segments (NONE) +--50096-- Reading syms from /lib/x86_64-linux-gnu/ld-2.31.so +--50096-- Considering /lib/x86_64-linux-gnu/ld-2.31.so .. +--50096-- .. CRC mismatch (computed b1e31cec wanted 7bd1f8ba) +--50096-- Considering /lib/x86_64-linux-gnu/ld-2.31.so .. +--50096-- .. CRC mismatch (computed b1e31cec wanted 7bd1f8ba) +--50096-- Considering /usr/lib/debug/lib/x86_64-linux-gnu/ld-2.31.so .. +--50096-- .. CRC is valid +--50096-- Reading syms from /usr/lib/x86_64-linux-gnu/valgrind/memcheck-amd64-linux +--50096-- object doesn't have a symbol table +--50096-- object doesn't have a dynamic symbol table +--50096-- Scheduler: using generic scheduler lock implementation. +--50096-- Reading suppressions file: /usr/lib/x86_64-linux-gnu/valgrind/default.supp +==50096== embedded gdbserver: reading from /tmp/vgdb-pipe-from-vgdb-to-50096-by-sot-on-??? +==50096== embedded gdbserver: writing to /tmp/vgdb-pipe-to-vgdb-from-50096-by-sot-on-??? +==50096== embedded gdbserver: shared mem /tmp/vgdb-pipe-shared-mem-vgdb-50096-by-sot-on-??? +==50096== +==50096== TO CONTROL THIS PROCESS USING vgdb (which you probably +==50096== don't want to do, unless you know exactly what you're doing, +==50096== or are doing some strange experiment): +==50096== /usr/lib/x86_64-linux-gnu/valgrind/../../bin/vgdb --pid=50096 ...command... +==50096== +==50096== TO DEBUG THIS PROCESS USING GDB: start GDB like this +==50096== /path/to/gdb build/lottieconverter +==50096== and then give GDB the following command +==50096== target remote | /usr/lib/x86_64-linux-gnu/valgrind/../../bin/vgdb --pid=50096 +==50096== --pid is optional if only one valgrind process is running +==50096== +--50096-- REDIR: 0x4022f60 (ld-linux-x86-64.so.2:strlen) redirected to 0x580c9ce2 (???) +--50096-- REDIR: 0x4022d30 (ld-linux-x86-64.so.2:index) redirected to 0x580c9cfc (???) +--50096-- Reading syms from /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_core-amd64-linux.so +--50096-- object doesn't have a symbol table +--50096-- Reading syms from /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so +--50096-- object doesn't have a symbol table +==50096== WARNING: new redirection conflicts with existing -- ignoring it +--50096-- old: 0x04022f60 (strlen ) R-> (0000.0) 0x580c9ce2 ??? +--50096-- new: 0x04022f60 (strlen ) R-> (2007.0) 0x0483f060 strlen +--50096-- REDIR: 0x401f740 (ld-linux-x86-64.so.2:strcmp) redirected to 0x483ffd0 (strcmp) +--50096-- REDIR: 0x40234c0 (ld-linux-x86-64.so.2:mempcpy) redirected to 0x4843a20 (mempcpy) +--50096-- Reading syms from /lib/x86_64-linux-gnu/libz.so.1.2.11 +--50096-- object doesn't have a symbol table +--50096-- Reading syms from /lib/x86_64-linux-gnu/libpthread-2.31.so +--50096-- Considering /usr/lib/debug/.build-id/ee/b5b055a9d738db64e450065f88980bebfc9cc2.debug .. +--50096-- .. build-id is valid +--50096-- Reading syms from /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28 +--50096-- object doesn't have a symbol table +--50096-- Reading syms from /lib/x86_64-linux-gnu/libm-2.31.so +--50096-- Considering /lib/x86_64-linux-gnu/libm-2.31.so .. +--50096-- .. CRC mismatch (computed 5f7b2a42 wanted ffb185de) +--50096-- Considering /lib/x86_64-linux-gnu/libm-2.31.so .. +--50096-- .. CRC mismatch (computed 5f7b2a42 wanted ffb185de) +--50096-- Considering /usr/lib/debug/lib/x86_64-linux-gnu/libm-2.31.so .. +--50096-- .. CRC is valid +--50096-- Reading syms from /lib/x86_64-linux-gnu/libgcc_s.so.1 +--50096-- object doesn't have a symbol table +--50096-- Reading syms from /lib/x86_64-linux-gnu/libc-2.31.so +--50096-- Considering /lib/x86_64-linux-gnu/libc-2.31.so .. +--50096-- .. CRC mismatch (computed 11759501 wanted 88150686) +--50096-- Considering /lib/x86_64-linux-gnu/libc-2.31.so .. +--50096-- .. CRC mismatch (computed 11759501 wanted 88150686) +--50096-- Considering /usr/lib/debug/lib/x86_64-linux-gnu/libc-2.31.so .. +--50096-- .. CRC is valid +--50096-- REDIR: 0x4ca5600 (libc.so.6:memmove) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4ca4900 (libc.so.6:strncpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4ca5930 (libc.so.6:strcasecmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4ca4220 (libc.so.6:strcat) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4ca4960 (libc.so.6:rindex) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4ca6dd0 (libc.so.6:rawmemchr) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4cc1e60 (libc.so.6:wmemchr) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4cc19a0 (libc.so.6:wcscmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4ca5760 (libc.so.6:mempcpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4ca5590 (libc.so.6:bcmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4ca4890 (libc.so.6:strncmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4ca42d0 (libc.so.6:strcmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4ca56c0 (libc.so.6:memset) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4cc1960 (libc.so.6:wcschr) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4ca47f0 (libc.so.6:strnlen) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4ca43b0 (libc.so.6:strcspn) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4ca5980 (libc.so.6:strncasecmp) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4ca4350 (libc.so.6:strcpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4ca5ad0 (libc.so.6:memcpy@@GLIBC_2.14) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4cc30d0 (libc.so.6:wcsnlen) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4cc19e0 (libc.so.6:wcscpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4ca49a0 (libc.so.6:strpbrk) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4ca4280 (libc.so.6:index) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4ca47b0 (libc.so.6:strlen) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4cadd20 (libc.so.6:memrchr) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4ca59d0 (libc.so.6:strcasecmp_l) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4ca5550 (libc.so.6:memchr) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4cc1ab0 (libc.so.6:wcslen) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4ca4c60 (libc.so.6:strspn) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4ca58d0 (libc.so.6:stpncpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4ca5870 (libc.so.6:stpcpy) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4ca6e10 (libc.so.6:strchrnul) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4ca5a20 (libc.so.6:strncasecmp_l) redirected to 0x48311d0 (_vgnU_ifunc_wrapper) +--50096-- REDIR: 0x4d8d490 (libc.so.6:__strrchr_avx2) redirected to 0x483ea10 (rindex) +--50096-- REDIR: 0x4c9f260 (libc.so.6:malloc) redirected to 0x483b780 (malloc) +--50096-- REDIR: 0x4d8d660 (libc.so.6:__strlen_avx2) redirected to 0x483ef40 (strlen) +--50096-- REDIR: 0x4d89c50 (libc.so.6:__memcmp_avx2_movbe) redirected to 0x48421e0 (bcmp) +--50096-- REDIR: 0x4d88b60 (libc.so.6:__strcmp_avx2) redirected to 0x483fed0 (strcmp) +--50096-- REDIR: 0x4d887b0 (libc.so.6:__strcspn_sse42) redirected to 0x4843e10 (strcspn) +--50096-- REDIR: 0x4ca0c90 (libc.so.6:calloc) redirected to 0x483dce0 (calloc) +--50096-- REDIR: 0x4d90af0 (libc.so.6:__memset_avx2_unaligned_erms) redirected to 0x48428e0 (memset) +--50096-- REDIR: 0x4d8ef30 (libc.so.6:__strncpy_avx2) redirected to 0x483f230 (strncpy) +--50096-- REDIR: 0x4c9f850 (libc.so.6:free) redirected to 0x483c9d0 (free) +--50096-- REDIR: 0x4ca5120 (libc.so.6:__GI_strstr) redirected to 0x4843ca0 (__strstr_sse2) +--50096-- REDIR: 0x4d90670 (libc.so.6:__memcpy_avx_unaligned_erms) redirected to 0x48429f0 (memmove) +--50096-- REDIR: 0x4ca0000 (libc.so.6:realloc) redirected to 0x483df30 (realloc) +--50096-- REDIR: 0x495eb20 (libstdc++.so.6:operator new(unsigned long)) redirected to 0x483bdf0 (operator new(unsigned long)) +--50096-- REDIR: 0x495eb80 (libstdc++.so.6:operator new[](unsigned long)) redirected to 0x483c510 (operator new[](unsigned long)) +--50096-- REDIR: 0x4d8d2a0 (libc.so.6:__strchrnul_avx2) redirected to 0x4843540 (strchrnul) +--50096-- REDIR: 0x4d90650 (libc.so.6:__mempcpy_avx_unaligned_erms) redirected to 0x4843660 (mempcpy) +--50096-- REDIR: 0x495cd70 (libstdc++.so.6:operator delete(void*)) redirected to 0x483cf50 (operator delete(void*)) +--50096-- REDIR: 0x495cd80 (libstdc++.so.6:operator delete(void*, unsigned long)) redirected to 0x483d160 (operator delete(void*, unsigned long)) +--50096-- REDIR: 0x4d894c0 (libc.so.6:__memchr_avx2) redirected to 0x4840050 (memchr) +--50096-- REDIR: 0x495cda0 (libstdc++.so.6:operator delete[](void*)) redirected to 0x483d6e0 (operator delete[](void*)) +==50096== +==50096== HEAP SUMMARY: +==50096== in use at exit: 472 bytes in 1 blocks +==50096== total heap usage: 17,852 allocs, 17,851 frees, 49,190,235 bytes allocated +==50096== +==50096== Searching for pointers to 1 not-freed blocks +==50096== Checked 140,760 bytes +==50096== +==50096== 472 bytes in 1 blocks are still reachable in loss record 1 of 1 +==50096== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) +==50096== by 0x4C87AAD: __fopen_internal (iofopen.c:65) +==50096== by 0x4C87AAD: fopen@@GLIBC_2.2.5 (iofopen.c:86) +==50096== by 0x110482: main (lottie_export.cpp:441) +==50096== +==50096== LEAK SUMMARY: +==50096== definitely lost: 0 bytes in 0 blocks +==50096== indirectly lost: 0 bytes in 0 blocks +==50096== possibly lost: 0 bytes in 0 blocks +==50096== still reachable: 472 bytes in 1 blocks +==50096== suppressed: 0 bytes in 0 blocks +==50096== +==50096== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) diff --git a/memcheck.sh b/memcheck.sh index f693770..88ffff5 100755 --- a/memcheck.sh +++ b/memcheck.sh @@ -1,3 +1,3 @@ #!/bin/bash valgrind --tool=memcheck --leak-check=full --show-reachable=yes --track-origins=yes -v \ - dist/Debug/GNU-Linux/lottieconverter $@ 2> >(tee -a memcheck.log >&2) + build/lottieconverter $@ 2> >(tee -a memcheck.log >&2) From c518a1a98421c4d19f777b9654a59c5a724e5d68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0irhoe=20Biazhkovi=C4=8D?= Date: Fri, 12 Nov 2021 18:44:49 +0300 Subject: [PATCH 5/7] Fix FPS parameter for gif, append README --- CMakeLists.txt | 6 ++--- README.md | 67 ++++++++++++++++++++++++++++++++++++++--------- lottie_export.cpp | 34 ++++++++++++++++-------- 3 files changed, 80 insertions(+), 27 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 67ce929..bc57994 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,9 +20,9 @@ else(CMAKE_BUILD_TYPE) set(COMPILE_PARAMS ${COMPILE_PARAMS} -O0 -g3) endif() -option(SYSTEM_PNG "Use system dynamic png library instead of building static one" 1) -option(SYSTEM_RL "Use system dynamic rlottie library instead of building static one" 0) -option(SYSTEM_GL "Use system dynamic giflib library instead of building static one" 0) +option(SYSTEM_PNG "Use system dynamic libpng" 1) +option(SYSTEM_RL "Use system dynamic rlottie" 0) +option(SYSTEM_GL "Use system shared giflib" 0) find_package(ZLIB ${ZLIB_MINIMUM} REQUIRED) diff --git a/README.md b/README.md index a253c91..727bf7e 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Animation can be converted to png (with transparency) or to gif. Uses: -* [rlottie library (MIT License)](https://github.com/Samsung/rlottie "Samsung/rlottie") +* [rlottie (MIT License)](https://github.com/Samsung/rlottie) * [giflib (MIT Licence)](http://giflib.sourceforge.net) @@ -21,32 +21,73 @@ Parameters: * input_file - path to lottie json or tgs (gzip-ed json), if set to `-` stdin is used * output_file - file to be written, if set `-` stdout is used, **note, that for `pngs` type, file name prefix is required** * type - output format, currently supported: `png`, `gif`, `pngs` -* resolution - size in pixels of out image, shoul be in `SIZExSIZE` format, default `128x128` -* option - depends of type, default 1 for all: - * `png` - which frame in percents to extract, i.e. if set to `20`, and there's 200 frames in animation, 40th frame will be extracted - * `pngs` - frame rate to try to extract images, i.e. if animation framerate is 30, and `option` set to 10 every 3rd frame will be extracted, - if animation frame rate is 10, and `option` set to 30 every frame will be written 3 times - * `gif` - unused - +* resolution - size in pixels of out image, should be in `SIZExSIZE` format, default `128x128` +* option - depends on type, default **10** for all: + * `png` - which frame in percents to extract; + * `pngs` and `gif` - desired frame rate. + +### Notes +#### PNG Single frame (`png`) +Extract single PNG image, `option` value should be set in percents, +If set to `20`, and there are 200 frames in animation, 40th frame will be extracted. + +#### PNG Series (`pngs`) +Extract series of separate PNG files with prefix `output_file` and specified in `option` framerate. + +If animation's framerate is the same as provided `option`, converter will extract every frame one time. + +Otherwise: +* If animation framerate (i.e.) is 30, and `option` set to 10 (reduce FPS), +every 3rd frame will be extracted; +* If animation frame rate is 10, and `option` set to 30 (increase FPS), +every frame will be written 3 times with the same content. + +#### GIF animation (`gif`) +Convert lottie animation to GIF animation. + +GIF's minimum delay between frames is 1/100 second, so maximum framerate (value of `option`) limited to 100. + +For the same reason, it is better to choose framerate value which is common factor of 100: 1, 2, 5, 10, 20, 25, 50 (100 is not recommended). + +If `option` set to 30, delay will be rounded to 3 'ticks' (3/100 sec.), but GIF speed will be a little faster than original (round from 3.333... to 3), +and if 25 - delay will be exactly 4 'ticks' (5/100 sec.). + +Another GIF's problem is transparency. GIF does not support alpha channel, +but one of colors from frame's image palette can be marked as transparent. + +Now, transparent color is hardcoded to 0'th (nearest to 000 RGB), so if image contains non-background +elements with this color, they will be marked as transparent. + ## Build +### Basics 1. Clone this repo or download sources from releases page -2. If cloned AND you need included `libpng`, `rlottie` or `giflib` fetch submodules +2. If cloned AND you need included `libpng`, `rlottie` or `giflib`, fetch submodules by executing `git submodule update --init` 3. Execute CMake build: 1. `mkdir build && cd build` 2. `cmake -DCMAKE_BUILD_TYPE=Release .. && cmake --build .` 4. Copy or execute ready `lottieconverter` in `build` subdirectory. -## Additional build options -By default, project uses system's shared `libpng` library and header, +### External libraries +By default, project uses system's shared `libpng` library, static `rlottie` and `libgif`. You can change behaviour by providing cmake options `SYSTEM_PNG`, `SYSTEM_RL` and `SYSTEM_GL` to 0 or 1 respectively (`-DSYSTEM_PNG=0 -DSYSTEM_RL=1 -DSYSTEM_GL=0` or any). -_NB: `libz` must be pre-installed in your system._ +Linux's development packages are usually named: +* `libpng-dev` +* `libgif-dev` or `giflib-dev` +* `librlottie-dev` + +and regular library packages: +* `libpng` or `libpng16` +* `libgif` or `libgif7` or `giflib` +* `rlottie` or `librlottie`. + +_NB: `zlib` (`zlib1g`) or `zlib-dev` (`zlib1g-dev`) must be pre-installed in your system._ ## Licencing notice -Up to v0.1.1 project has been licensed under GNU LGPL 2.1. +Versions v0.1.1 and earlier have been licensed under GNU LGPL 2.1. Actual revision is licenced under BSD-3-Clause. \ No newline at end of file diff --git a/lottie_export.cpp b/lottie_export.cpp index 58f9039..de3480b 100644 --- a/lottie_export.cpp +++ b/lottie_export.cpp @@ -87,7 +87,6 @@ int convert_and_write_to(byte *in_file_data, uint8_t convert_to, int w, int h, u return EXIT_FAILURE; } size_t frame_count = animation->totalFrame(); - auto frame_inc = (float)animation->frameRate() / (float)param; unique_ptr buffer = unique_ptr(new uint32_t[w * h]); if (buffer == nullptr) { fputs("Unable to init frame buffer\n", stderr); @@ -95,6 +94,10 @@ int convert_and_write_to(byte *in_file_data, uint8_t convert_to, int w, int h, u } switch (convert_to) { case li_OUT_PNG: { + if(param > 100){ + fputs("Frame percent must be between 0 and 100\n", stderr); + return EXIT_FAILURE; + } size_t frame_to_extract = frame_count * param / 100; if (frame_to_extract > frame_count - 1) frame_to_extract = frame_count - 1; Surface surface(buffer.get(), w, h, w * lp_COLOR_BYTES); @@ -102,7 +105,11 @@ int convert_and_write_to(byte *in_file_data, uint8_t convert_to, int w, int h, u return write_png(reinterpret_cast (buffer.get()), w, h, out_file->file_pointer); } case li_OUT_PNGS: { - float frame_current = 0.0f; + if(param == 0){ + fputs("Framerate must not be 0\n", stderr); + return EXIT_FAILURE; + } + float frame_current = 0.0f, frame_inc = (float)animation->frameRate() / (float)param; auto frame_count_out = (size_t)((float)frame_count / frame_inc); size_t frame_count_out_t = frame_count_out; unsigned int digit_count = 1, frame_number = 0; @@ -146,10 +153,10 @@ int convert_and_write_to(byte *in_file_data, uint8_t convert_to, int w, int h, u } case li_OUT_GIF: { if(param == 0 || param > 100){ - fputs("GIF framerate must be between 1 and 100", stderr); + fputs("GIF framerate must be between 1 and 100\n", stderr); return EXIT_FAILURE; } - float frame_current = 0.0f; + float frame_current = 0.0f, frame_inc = (float)animation->frameRate() / (float)param;; int error_code = 0; GifFileType *writer = EGifOpenFileHandle(fileno(out_file->file_pointer), &error_code); if (writer == nullptr || error_code != 0) { @@ -157,19 +164,24 @@ int convert_and_write_to(byte *in_file_data, uint8_t convert_to, int w, int h, u return EXIT_FAILURE; } int color_map_size = 1 << lp_COLOR_DEPTH; - byte loop[]{1, 0, 0}; //infinite gif loop - static byte delay[4] = {0x0D, // Bit 0 - flag if transparent index given (checked), + byte hs_delay = (byte)lround(100.0f/(float)param); + if(hs_delay == 1){ //if delay set to 1 (1/100 sec) animation became very slo-o-ow + hs_delay = 2; + frame_inc *= 2.0f; + } + byte loop[]{1, 0, 0}, //infinite gif loop + delay[4] = { 0x0D, // Bit 0 - flag if transparent index given (checked), // Bit 1 - User Input Flag (unchecked), // Bits 2-4 - Disposal Method: // 0 - unspecified, // 1 - don't dispose, // 2 - restore to background color, // 3 - restore to previous (checked) - 10, // >Hundredths of - 0, // seconds to wait< + hs_delay, // >Hundredths of + 0, // seconds to wait< 0}; // Transparent color index //TODO: try to calculate ColorMapObject *output_palette = GifMakeMapObject(color_map_size, nullptr); - if(output_palette == nullptr){ + if(output_palette == nullptr) { status = EXIT_FAILURE; goto CLOSE_FILE; } @@ -281,7 +293,7 @@ int convert_and_write_to(byte *in_file_data, uint8_t convert_to, int w, int h, u status = EXIT_FAILURE; } //already closed by EGifCloseFile - out_file->file_pointer = nullptr; +// out_file->file_pointer = nullptr; break; } default: @@ -372,7 +384,7 @@ int unzip(FILE *in_file, byte_buffer *out_data) { int main(int argc, char **argv) { - uint32_t param = 1; + uint32_t param = 10; uint8_t convert_to = li_OUT_PNG; unsigned long w = 128, h = 128; FILE *in_file = stdin; From 5dffc2c89d73814d4d818a8c1ea23f34297d87ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0irhoe=20Biazhkovi=C4=8D?= Date: Fri, 12 Nov 2021 19:36:51 +0300 Subject: [PATCH 6/7] Print GIF error message details. XXX: 'Failed to allocate required memory' on 'Animated Blue Cat' - 'Mouse & keyboard' TG sticker --- lottie_export.cpp | 25 +++++++++++++------------ memcheck.sh | 2 +- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/lottie_export.cpp b/lottie_export.cpp index de3480b..7d9994d 100644 --- a/lottie_export.cpp +++ b/lottie_export.cpp @@ -156,11 +156,11 @@ int convert_and_write_to(byte *in_file_data, uint8_t convert_to, int w, int h, u fputs("GIF framerate must be between 1 and 100\n", stderr); return EXIT_FAILURE; } - float frame_current = 0.0f, frame_inc = (float)animation->frameRate() / (float)param;; + float frame_current = 0.0f, frame_inc = (float)animation->frameRate() / (float)param; int error_code = 0; GifFileType *writer = EGifOpenFileHandle(fileno(out_file->file_pointer), &error_code); if (writer == nullptr || error_code != 0) { - fprintf(stderr, "Unable to initialize GIF writer, error code: %d\n", error_code); + fprintf(stderr, "Unable to initialize GIF writer: %s\n", GifErrorString(error_code)); return EXIT_FAILURE; } int color_map_size = 1 << lp_COLOR_DEPTH; @@ -182,6 +182,7 @@ int convert_and_write_to(byte *in_file_data, uint8_t convert_to, int w, int h, u 0}; // Transparent color index //TODO: try to calculate ColorMapObject *output_palette = GifMakeMapObject(color_map_size, nullptr); if(output_palette == nullptr) { + fputs("Unable to generate gif color palette\n", stderr); status = EXIT_FAILURE; goto CLOSE_FILE; } @@ -191,27 +192,27 @@ int convert_and_write_to(byte *in_file_data, uint8_t convert_to, int w, int h, u w, h, lp_COLOR_DEPTH, 0, output_palette ) == GIF_ERROR) { - fputs("Something went wrong while creating gif\n", stderr); + fprintf(stderr,"Unable to write gif screen description: %s\n", GifErrorString(writer->Error)); status = EXIT_FAILURE; goto FREE_MAP; } if (EGifPutExtensionLeader(writer, APPLICATION_EXT_FUNC_CODE) == GIF_ERROR) { - fputs("Unable to write gif extension\n", stderr); + fprintf(stderr,"Unable to write gif extension: %s\n", GifErrorString(writer->Error)); status = EXIT_FAILURE; goto FREE_MAP; } if (EGifPutExtensionBlock(writer, 11, "NETSCAPE2.0") == GIF_ERROR) { - fputs("Unable to write gif extension\n", stderr); + fprintf(stderr,"Unable to write gif extension: %s\n", GifErrorString(writer->Error)); status = EXIT_FAILURE; goto FREE_MAP; } if (EGifPutExtensionBlock(writer, 3, loop) == GIF_ERROR) { - fputs("Unable to write gif extension\n", stderr); + fprintf(stderr,"Unable to write gif extension: %s\n", GifErrorString(writer->Error)); status = EXIT_FAILURE; goto FREE_MAP; } if (EGifPutExtensionTrailer(writer) == GIF_ERROR) { - fputs("Unable to write gif extension\n", stderr); + fprintf(stderr,"Unable to write gif extension: %s\n", GifErrorString(writer->Error)); status = EXIT_FAILURE; } while (frame_current < (float)frame_count && status == EXIT_SUCCESS) { @@ -224,7 +225,7 @@ int convert_and_write_to(byte *in_file_data, uint8_t convert_to, int w, int h, u *bb = (byte *)calloc(pixel_count, sizeof(byte)), *out = (byte *)calloc(pixel_count, sizeof(byte)); if (rb == nullptr || gb == nullptr || bb == nullptr || out == nullptr) { - perror("Unable to init byte buffer"); + perror("Unable to init color byte buffer"); if(rb != nullptr) free(rb); if(gb != nullptr) free(gb); if(bb != nullptr) free(bb); @@ -268,18 +269,18 @@ int convert_and_write_to(byte *in_file_data, uint8_t convert_to, int w, int h, u if (EGifPutImageDesc(writer, 0, 0, w, h, false, output_palette) == GIF_OK) { for (int line = 0; line < h; ++line) { if (EGifPutLine(writer, line_buffer, w) != GIF_OK) { - fputs("Unable to write GIF line\n", stderr); + fprintf(stderr, "Unable to write GIF line: %s\n", GifErrorString(writer->Error)); status = EXIT_FAILURE; break; } line_buffer += w; } } else{ - fputs("Unable to write gif image info\n", stderr); + fprintf(stderr, "Unable to write gif image info: %s\n", GifErrorString(writer->Error)); status = EXIT_FAILURE; } } else { - fputs("Unable to write gif extension\n", stderr); + fprintf(stderr, "Unable to write gif extension: %s\n", GifErrorString(writer->Error)); status = EXIT_FAILURE; } free(out); @@ -289,7 +290,7 @@ int convert_and_write_to(byte *in_file_data, uint8_t convert_to, int w, int h, u GifFreeMapObject(output_palette); CLOSE_FILE: if (EGifCloseFile(writer, &error_code) != GIF_OK) { - fprintf(stderr, "Unable to finalize GIF writer, error code: %d\n", error_code); + fprintf(stderr, "Unable to finalize GIF writer: %s\n", GifErrorString(error_code)); status = EXIT_FAILURE; } //already closed by EGifCloseFile diff --git a/memcheck.sh b/memcheck.sh index 88ffff5..43a21ad 100755 --- a/memcheck.sh +++ b/memcheck.sh @@ -1,3 +1,3 @@ #!/bin/bash -valgrind --tool=memcheck --leak-check=full --show-reachable=yes --track-origins=yes -v \ +valgrind --tool=memcheck --leak-check=full --show-reachable=yes --track-origins=yes \ build/lottieconverter $@ 2> >(tee -a memcheck.log >&2) From 34e7e04cab0417804fc8be15e177aa565bb657ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0irhoe=20Biazhkovi=C4=8D?= Date: Sat, 13 Nov 2021 00:48:20 +0300 Subject: [PATCH 7/7] Add test files, fix GIF palette ENOMEM error --- .gitignore | 4 +- CMakeLists.txt | 25 +++- README.md | 33 ++--- gif_quantize.c | 333 ++++++++++++++++++++++++++++++++++++++++++++++ lottie_export.cpp | 128 +++++++++--------- lottie_export.h | 1 + memcheck.log | 117 ++++++++++++++++ test/!LICENCE.txt | 8 ++ test/1.tgs | Bin 0 -> 30536 bytes test/2.tgs | Bin 0 -> 65231 bytes test/3.tgs | Bin 0 -> 38043 bytes test/4.tgs | Bin 0 -> 59577 bytes test/5.json | 1 + test/6.json | 1 + test/7.json | 1 + test/run.sh | 26 ++++ 16 files changed, 592 insertions(+), 86 deletions(-) create mode 100644 gif_quantize.c create mode 100644 test/!LICENCE.txt create mode 100644 test/1.tgs create mode 100644 test/2.tgs create mode 100644 test/3.tgs create mode 100644 test/4.tgs create mode 100644 test/5.json create mode 100644 test/6.json create mode 100644 test/7.json create mode 100755 test/run.sh diff --git a/.gitignore b/.gitignore index e9a33a9..92eaedd 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,4 @@ /build /dist /cmake-build* -/AnimatedSticker.tgs -/AnimatedSticker.json -/out* +/test/out diff --git a/CMakeLists.txt b/CMakeLists.txt index bc57994..6bd91ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,9 @@ include(ExternalProject) include(FindPackageMessage) set(CMAKE_CXX_STANDARD 11) +set(CMAKE_C_STANDARD 99) set(CMAKE_CXX_STANDARD_REQUIRED True) +set(CMAKE_C_STANDARD_REQUIRED True) set(ZLIB_MINIMUM 1.2.3) set(PNG_MINIMUM 1.6.0) @@ -12,7 +14,7 @@ set(COMPILE_PARAMS -Wall) set(SOURCE_FILES lottie_export.cpp) set(LIBS z) set(INCLUDES) -add_executable(${PROJECT_NAME} ${SOURCE_FILES}) +add_executable(${PROJECT_NAME}) if (CMAKE_BUILD_TYPE EQUAL "RELEASE") set(COMPILE_PARAMS ${COMPILE_PARAMS} -O2) @@ -24,6 +26,9 @@ option(SYSTEM_PNG "Use system dynamic libpng" 1) option(SYSTEM_RL "Use system dynamic rlottie" 0) option(SYSTEM_GL "Use system shared giflib" 0) +enable_testing() + + find_package(ZLIB ${ZLIB_MINIMUM} REQUIRED) if(SYSTEM_PNG) @@ -57,8 +62,9 @@ endif() if (SYSTEM_RL) find_path(RL_INCLUDEDIR NAMES rlottie.h HINTS ${_RL_INCLUDEDIR} REQUIRED) find_library(RL_LIBDIR NAMES rlottie HINTS ${_RL_LIBDIR} REQUIRED) - find_package_message(rlottie "Found RLOTTIE: ${RL_LIBDIR}" "_") + find_package_message(rlottie "Found RLOTTIE: ${RL_LIBDIR}" "Include path: ${RL_INCLUDEDIR}") set(LIBS ${LIBS} "${RL_LIBDIR}") + set(INCLUDES ${INCLUDES} "${RL_INCLUDEDIR}") else () message(NOTICE "-- Building static rlottie") ExternalProject_Add( @@ -87,8 +93,10 @@ endif () if(SYSTEM_GL) find_path(GL_INCLUDEDIR NAMES gif_lib.h HINTS ${_GL_INCLUDEDIR} REQUIRED) find_library(GL_LIBDIR NAMES gif HINTS ${_GL_LIBDIR} REQUIRED) - find_package_message(gif "Found GIF: ${GL_LIBDIR}" "_") + find_package_message(gif "Found GIF: ${GL_LIBDIR}" "Include path: ${GL_INCLUDEDIR}") + set(INCLUDES ${INCLUDES} "${GL_INCLUDEDIR}") set(LIBS ${LIBS} "${GL_LIBDIR}") + set(SOURCE_FILES ${SOURCE_FILES} gif_quantize.c) else() message(NOTICE "-- Building static giflib") file(COPY ${CMAKE_SOURCE_DIR}/lib/giflib DESTINATION ${CMAKE_BINARY_DIR}/lib) @@ -119,12 +127,17 @@ else() set(LIBS ${LIBS} giflib) add_dependencies(${PROJECT_NAME} giflib) - set(INCLUDES "${INCLUDES}" "${CMAKE_BINARY_DIR}/lib/giflib") + set(INCLUDES ${INCLUDES} "${CMAKE_BINARY_DIR}/lib/giflib") endif() if(INCLUDES) include_directories(${INCLUDES}) endif() - -target_compile_options(${PROJECT_NAME} PUBLIC PRIVATE -std=c++${CMAKE_CXX_STANDARD} ${COMPILE_PARAMS}) +target_sources(${PROJECT_NAME} PRIVATE ${SOURCE_FILES}) +target_compile_options(${PROJECT_NAME} PUBLIC PRIVATE ${COMPILE_PARAMS}) target_link_libraries(${PROJECT_NAME} PUBLIC ${LIBS}) + +add_test(NAME convert + COMMAND run.sh $ + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/test" + ) \ No newline at end of file diff --git a/README.md b/README.md index 727bf7e..d7db82c 100644 --- a/README.md +++ b/README.md @@ -18,10 +18,10 @@ Uses: Parameters: -* input_file - path to lottie json or tgs (gzip-ed json), if set to `-` stdin is used -* output_file - file to be written, if set `-` stdout is used, **note, that for `pngs` type, file name prefix is required** -* type - output format, currently supported: `png`, `gif`, `pngs` -* resolution - size in pixels of out image, should be in `SIZExSIZE` format, default `128x128` +* input_file - path to lottie json or tgs (gzip-ed json), if set to `-` stdin is used; +* output_file - file to be written, if set `-` stdout is used, **note, that for `pngs` type, file name prefix is required**; +* type - output format, currently supported: `png`, `gif`, `pngs`; +* resolution - **desired** size in pixels of out image, should be in `SIZExSIZE` format, default `128x128`. Resulting resolution depends on input; * option - depends on type, default **10** for all: * `png` - which frame in percents to extract; * `pngs` and `gif` - desired frame rate. @@ -55,18 +55,19 @@ and if 25 - delay will be exactly 4 'ticks' (5/100 sec.). Another GIF's problem is transparency. GIF does not support alpha channel, but one of colors from frame's image palette can be marked as transparent. -Now, transparent color is hardcoded to 0'th (nearest to 000 RGB), so if image contains non-background -elements with this color, they will be marked as transparent. +Now, transparent color is hardcoded to 0'th color in palette, so if image contains non-background +elements with this color, they will be marked as transparent and some artifacts will appear. ## Build ### Basics -1. Clone this repo or download sources from releases page +1. Clone this repo or download sources from releases page; 2. If cloned AND you need included `libpng`, `rlottie` or `giflib`, fetch submodules -by executing `git submodule update --init` +by executing `git submodule update --init`; 3. Execute CMake build: - 1. `mkdir build && cd build` - 2. `cmake -DCMAKE_BUILD_TYPE=Release .. && cmake --build .` -4. Copy or execute ready `lottieconverter` in `build` subdirectory. + 1. `mkdir build && cd build`; + 2. `cmake -DCMAKE_BUILD_TYPE=Release .. && cmake --build .`; +4. (optional) Perform test conversions with `ctest` (results will appear in `test/out` directory); +5. Copy or execute ready `lottieconverter` in `build` subdirectory. ### External libraries By default, project uses system's shared `libpng` library, @@ -76,13 +77,13 @@ You can change behaviour by providing cmake options (`-DSYSTEM_PNG=0 -DSYSTEM_RL=1 -DSYSTEM_GL=0` or any). Linux's development packages are usually named: -* `libpng-dev` -* `libgif-dev` or `giflib-dev` -* `librlottie-dev` +* `libpng-dev`; +* `libgif-dev` or `giflib-dev`; +* `librlottie-dev`. and regular library packages: -* `libpng` or `libpng16` -* `libgif` or `libgif7` or `giflib` +* `libpng` or `libpng16`; +* `libgif` or `libgif7` or `giflib`; * `rlottie` or `librlottie`. _NB: `zlib` (`zlib1g`) or `zlib-dev` (`zlib1g-dev`) must be pre-installed in your system._ diff --git a/gif_quantize.c b/gif_quantize.c new file mode 100644 index 0000000..9fe1efb --- /dev/null +++ b/gif_quantize.c @@ -0,0 +1,333 @@ +/* + * Copied from giflib because GifQuantizeBuffer is non-exported and shared library does not contain it + */ + +/***************************************************************************** + + quantize.c - quantize a high resolution image into lower one + + Based on: "Color Image Quantization for frame buffer Display", by + Paul Heckbert SIGGRAPH 1982 page 297-307. + + This doesn't really belong in the core library, was undocumented, + and was removed in 4.2. Then it turned out some client apps were + actually using it, so it was restored in 5.0. + +SPDX-License-Identifier: MIT + +******************************************************************************/ + +#include +#include + +#define ABS(x) ((x) > 0 ? (x) : (-(x))) + +#define COLOR_ARRAY_SIZE 32768 +#define BITS_PER_PRIM_COLOR 5 +#define MAX_PRIM_COLOR 0x1f + +static int SortRGBAxis; + +typedef struct QuantizedColorType { + GifByteType RGB[3]; + GifByteType NewColorIndex; + long Count; + struct QuantizedColorType *Pnext; +} QuantizedColorType; + +typedef struct NewColorMapType { + GifByteType RGBMin[3], RGBWidth[3]; + unsigned int NumEntries; /* # of QuantizedColorType in linked list below */ + unsigned long Count; /* Total number of pixels in all the entries */ + QuantizedColorType *QuantizedColors; +} NewColorMapType; + +static int SubdivColorMap(NewColorMapType * NewColorSubdiv, + unsigned int ColorMapSize, + unsigned int *NewColorMapSize); +static int SortCmpRtn(const void *Entry1, const void *Entry2); + +/****************************************************************************** + Quantize high resolution image into lower one. Input image consists of a + 2D array for each of the RGB colors with size Width by Height. There is no + Color map for the input. Output is a quantized image with 2D array of + indexes into the output color map. + Note input image can be 24 bits at the most (8 for red/green/blue) and + the output has 256 colors at the most (256 entries in the color map.). + ColorMapSize specifies size of color map up to 256 and will be updated to + real size before returning. + Also non of the parameter are allocated by this routine. + This function returns GIF_OK if successful, GIF_ERROR otherwise. +******************************************************************************/ +int +GifQuantizeBuffer(unsigned int Width, + unsigned int Height, + int *ColorMapSize, + const GifByteType * RedInput, + const GifByteType * GreenInput, + const GifByteType * BlueInput, + GifByteType * OutputBuffer, + GifColorType * OutputColorMap) { + + unsigned int Index, NumOfEntries, i, j, NewColorMapSize; + int MaxRGBError[3]; + long Red, Green, Blue; + NewColorMapType NewColorSubdiv[256]; + QuantizedColorType *ColorArrayEntries, *QuantizedColor; + + ColorArrayEntries = (QuantizedColorType *)malloc( + sizeof(QuantizedColorType) * COLOR_ARRAY_SIZE); + if (ColorArrayEntries == NULL) { + return GIF_ERROR; + } + + for (i = 0; i < COLOR_ARRAY_SIZE; i++) { + ColorArrayEntries[i].RGB[0] = i >> (2 * BITS_PER_PRIM_COLOR); + ColorArrayEntries[i].RGB[1] = (i >> BITS_PER_PRIM_COLOR) & + MAX_PRIM_COLOR; + ColorArrayEntries[i].RGB[2] = i & MAX_PRIM_COLOR; + ColorArrayEntries[i].Count = 0; + } + + /* Sample the colors and their distribution: */ + for (i = 0; i < (int)(Width * Height); i++) { + Index = ((RedInput[i] >> (8 - BITS_PER_PRIM_COLOR)) << + (2 * BITS_PER_PRIM_COLOR)) + + ((GreenInput[i] >> (8 - BITS_PER_PRIM_COLOR)) << + BITS_PER_PRIM_COLOR) + + (BlueInput[i] >> (8 - BITS_PER_PRIM_COLOR)); + ColorArrayEntries[Index].Count++; + } + + /* Put all the colors in the first entry of the color map, and call the + * recursive subdivision process. */ + for (i = 0; i < 256; i++) { + NewColorSubdiv[i].QuantizedColors = NULL; + NewColorSubdiv[i].Count = NewColorSubdiv[i].NumEntries = 0; + for (j = 0; j < 3; j++) { + NewColorSubdiv[i].RGBMin[j] = 0; + NewColorSubdiv[i].RGBWidth[j] = 255; + } + } + + /* Find the non empty entries in the color table and chain them: */ + for (i = 0; i < COLOR_ARRAY_SIZE; i++) + if (ColorArrayEntries[i].Count > 0) + break; + QuantizedColor = NewColorSubdiv[0].QuantizedColors = &ColorArrayEntries[i]; + NumOfEntries = 1; + while (++i < COLOR_ARRAY_SIZE) + if (ColorArrayEntries[i].Count > 0) { + QuantizedColor->Pnext = &ColorArrayEntries[i]; + QuantizedColor = &ColorArrayEntries[i]; + NumOfEntries++; + } + QuantizedColor->Pnext = NULL; + + NewColorSubdiv[0].NumEntries = NumOfEntries; /* Different sampled colors */ + NewColorSubdiv[0].Count = ((long)Width) * Height; /* Pixels */ + NewColorMapSize = 1; + if (SubdivColorMap(NewColorSubdiv, *ColorMapSize, &NewColorMapSize) != + GIF_OK) { + free((char *)ColorArrayEntries); + return GIF_ERROR; + } + if (NewColorMapSize < *ColorMapSize) { + /* And clear rest of color map: */ + for (i = NewColorMapSize; i < *ColorMapSize; i++) + OutputColorMap[i].Red = OutputColorMap[i].Green = + OutputColorMap[i].Blue = 0; + } + + /* Average the colors in each entry to be the color to be used in the + * output color map, and plug it into the output color map itself. */ + for (i = 0; i < NewColorMapSize; i++) { + if ((j = NewColorSubdiv[i].NumEntries) > 0) { + QuantizedColor = NewColorSubdiv[i].QuantizedColors; + Red = Green = Blue = 0; + while (QuantizedColor) { + QuantizedColor->NewColorIndex = i; + Red += QuantizedColor->RGB[0]; + Green += QuantizedColor->RGB[1]; + Blue += QuantizedColor->RGB[2]; + QuantizedColor = QuantizedColor->Pnext; + } + OutputColorMap[i].Red = (Red << (8 - BITS_PER_PRIM_COLOR)) / j; + OutputColorMap[i].Green = (Green << (8 - BITS_PER_PRIM_COLOR)) / j; + OutputColorMap[i].Blue = (Blue << (8 - BITS_PER_PRIM_COLOR)) / j; + } + } + + /* Finally scan the input buffer again and put the mapped index in the + * output buffer. */ + MaxRGBError[0] = MaxRGBError[1] = MaxRGBError[2] = 0; + for (i = 0; i < (int)(Width * Height); i++) { + Index = ((RedInput[i] >> (8 - BITS_PER_PRIM_COLOR)) << + (2 * BITS_PER_PRIM_COLOR)) + + ((GreenInput[i] >> (8 - BITS_PER_PRIM_COLOR)) << + BITS_PER_PRIM_COLOR) + + (BlueInput[i] >> (8 - BITS_PER_PRIM_COLOR)); + Index = ColorArrayEntries[Index].NewColorIndex; + OutputBuffer[i] = Index; + if (MaxRGBError[0] < ABS(OutputColorMap[Index].Red - RedInput[i])) + MaxRGBError[0] = ABS(OutputColorMap[Index].Red - RedInput[i]); + if (MaxRGBError[1] < ABS(OutputColorMap[Index].Green - GreenInput[i])) + MaxRGBError[1] = ABS(OutputColorMap[Index].Green - GreenInput[i]); + if (MaxRGBError[2] < ABS(OutputColorMap[Index].Blue - BlueInput[i])) + MaxRGBError[2] = ABS(OutputColorMap[Index].Blue - BlueInput[i]); + } + +#ifdef DEBUG + fprintf(stderr, + "Quantization L(0) errors: Red = %d, Green = %d, Blue = %d.\n", + MaxRGBError[0], MaxRGBError[1], MaxRGBError[2]); +#endif /* DEBUG */ + + free((char *)ColorArrayEntries); + + *ColorMapSize = NewColorMapSize; + + return GIF_OK; +} + +/****************************************************************************** + Routine to subdivide the RGB space recursively using median cut in each + axes alternatingly until ColorMapSize different cubes exists. + The biggest cube in one dimension is subdivide unless it has only one entry. + Returns GIF_ERROR if failed, otherwise GIF_OK. +*******************************************************************************/ +static int +SubdivColorMap(NewColorMapType * NewColorSubdiv, + unsigned int ColorMapSize, + unsigned int *NewColorMapSize) { + + unsigned int i, j, Index = 0; + QuantizedColorType *QuantizedColor, **SortArray; + + while (ColorMapSize > *NewColorMapSize) { + /* Find candidate for subdivision: */ + long Sum, Count; + int MaxSize = -1; + unsigned int NumEntries, MinColor, MaxColor; + for (i = 0; i < *NewColorMapSize; i++) { + for (j = 0; j < 3; j++) { + if ((((int)NewColorSubdiv[i].RGBWidth[j]) > MaxSize) && + (NewColorSubdiv[i].NumEntries > 1)) { + MaxSize = NewColorSubdiv[i].RGBWidth[j]; + Index = i; + SortRGBAxis = j; + } + } + } + + if (MaxSize == -1) + return GIF_OK; + + /* Split the entry Index into two along the axis SortRGBAxis: */ + + /* Sort all elements in that entry along the given axis and split at + * the median. */ + SortArray = (QuantizedColorType **)malloc( + sizeof(QuantizedColorType *) * + NewColorSubdiv[Index].NumEntries); + if (SortArray == NULL) + return GIF_ERROR; + for (j = 0, QuantizedColor = NewColorSubdiv[Index].QuantizedColors; + j < NewColorSubdiv[Index].NumEntries && QuantizedColor != NULL; + j++, QuantizedColor = QuantizedColor->Pnext) + SortArray[j] = QuantizedColor; + + /* + * Because qsort isn't stable, this can produce differing + * results for the order of tuples depending on platform + * details of how qsort() is implemented. + * + * We mitigate this problem by sorting on all three axes rather + * than only the one specied by SortRGBAxis; that way the instability + * can only become an issue if there are multiple color indices + * referring to identical RGB tuples. Older versions of this + * sorted on only the one axis. + */ + qsort(SortArray, NewColorSubdiv[Index].NumEntries, + sizeof(QuantizedColorType *), SortCmpRtn); + + /* Relink the sorted list into one: */ + for (j = 0; j < NewColorSubdiv[Index].NumEntries - 1; j++) + SortArray[j]->Pnext = SortArray[j + 1]; + SortArray[NewColorSubdiv[Index].NumEntries - 1]->Pnext = NULL; + NewColorSubdiv[Index].QuantizedColors = QuantizedColor = SortArray[0]; + free((char *)SortArray); + + /* Now simply add the Counts until we have half of the Count: */ + Sum = (long)NewColorSubdiv[Index].Count / 2 - QuantizedColor->Count; + NumEntries = 1; + Count = QuantizedColor->Count; + while (QuantizedColor->Pnext != NULL && + (Sum -= QuantizedColor->Pnext->Count) >= 0 && + QuantizedColor->Pnext->Pnext != NULL) { + QuantizedColor = QuantizedColor->Pnext; + NumEntries++; + Count += QuantizedColor->Count; + } + /* Save the values of the last color of the first half, and first + * of the second half so we can update the Bounding Boxes later. + * Also as the colors are quantized and the BBoxes are full 0..255, + * they need to be rescaled. + */ + MaxColor = QuantizedColor->RGB[SortRGBAxis]; /* Max. of first half */ + /* coverity[var_deref_op] */ + MinColor = QuantizedColor->Pnext->RGB[SortRGBAxis]; /* of second */ + MaxColor <<= (8 - BITS_PER_PRIM_COLOR); + MinColor <<= (8 - BITS_PER_PRIM_COLOR); + + /* Partition right here: */ + NewColorSubdiv[*NewColorMapSize].QuantizedColors = + QuantizedColor->Pnext; + QuantizedColor->Pnext = NULL; + NewColorSubdiv[*NewColorMapSize].Count = Count; + NewColorSubdiv[Index].Count -= Count; + NewColorSubdiv[*NewColorMapSize].NumEntries = + NewColorSubdiv[Index].NumEntries - NumEntries; + NewColorSubdiv[Index].NumEntries = NumEntries; + for (j = 0; j < 3; j++) { + NewColorSubdiv[*NewColorMapSize].RGBMin[j] = + NewColorSubdiv[Index].RGBMin[j]; + NewColorSubdiv[*NewColorMapSize].RGBWidth[j] = + NewColorSubdiv[Index].RGBWidth[j]; + } + NewColorSubdiv[*NewColorMapSize].RGBWidth[SortRGBAxis] = + NewColorSubdiv[*NewColorMapSize].RGBMin[SortRGBAxis] + + NewColorSubdiv[*NewColorMapSize].RGBWidth[SortRGBAxis] - MinColor; + NewColorSubdiv[*NewColorMapSize].RGBMin[SortRGBAxis] = MinColor; + + NewColorSubdiv[Index].RGBWidth[SortRGBAxis] = + MaxColor - NewColorSubdiv[Index].RGBMin[SortRGBAxis]; + + (*NewColorMapSize)++; + } + + return GIF_OK; +} + +/**************************************************************************** + Routine called by qsort to compare two entries. +*****************************************************************************/ + +static int +SortCmpRtn(const void *Entry1, + const void *Entry2) { + QuantizedColorType *entry1 = (*((QuantizedColorType **) Entry1)); + QuantizedColorType *entry2 = (*((QuantizedColorType **) Entry2)); + + /* sort on all axes of the color space! */ + int hash1 = entry1->RGB[SortRGBAxis] * 256 * 256 + + entry1->RGB[(SortRGBAxis+1) % 3] * 256 + + entry1->RGB[(SortRGBAxis+2) % 3]; + int hash2 = entry2->RGB[SortRGBAxis] * 256 * 256 + + entry2->RGB[(SortRGBAxis+1) % 3] * 256 + + entry2->RGB[(SortRGBAxis+2) % 3]; + + return hash1 - hash2; +} + +/* end */ diff --git a/lottie_export.cpp b/lottie_export.cpp index 7d9994d..dbcd6bf 100644 --- a/lottie_export.cpp +++ b/lottie_export.cpp @@ -94,7 +94,7 @@ int convert_and_write_to(byte *in_file_data, uint8_t convert_to, int w, int h, u } switch (convert_to) { case li_OUT_PNG: { - if(param > 100){ + if (param > 100) { fputs("Frame percent must be between 0 and 100\n", stderr); return EXIT_FAILURE; } @@ -105,12 +105,12 @@ int convert_and_write_to(byte *in_file_data, uint8_t convert_to, int w, int h, u return write_png(reinterpret_cast (buffer.get()), w, h, out_file->file_pointer); } case li_OUT_PNGS: { - if(param == 0){ + if (param == 0) { fputs("Framerate must not be 0\n", stderr); return EXIT_FAILURE; } - float frame_current = 0.0f, frame_inc = (float)animation->frameRate() / (float)param; - auto frame_count_out = (size_t)((float)frame_count / frame_inc); + float frame_current = 0.0f, frame_inc = (float) animation->frameRate() / (float) param; + auto frame_count_out = (size_t) ((float) frame_count / frame_inc); size_t frame_count_out_t = frame_count_out; unsigned int digit_count = 1, frame_number = 0; while (frame_count_out_t > 9) { @@ -152,87 +152,92 @@ int convert_and_write_to(byte *in_file_data, uint8_t convert_to, int w, int h, u return result; } case li_OUT_GIF: { - if(param == 0 || param > 100){ + if (param == 0 || param > 100) { fputs("GIF framerate must be between 1 and 100\n", stderr); return EXIT_FAILURE; } - float frame_current = 0.0f, frame_inc = (float)animation->frameRate() / (float)param; + float frame_current = 0.0f, frame_inc = (float) animation->frameRate() / (float) param; int error_code = 0; GifFileType *writer = EGifOpenFileHandle(fileno(out_file->file_pointer), &error_code); if (writer == nullptr || error_code != 0) { fprintf(stderr, "Unable to initialize GIF writer: %s\n", GifErrorString(error_code)); return EXIT_FAILURE; } - int color_map_size = 1 << lp_COLOR_DEPTH; - byte hs_delay = (byte)lround(100.0f/(float)param); - if(hs_delay == 1){ //if delay set to 1 (1/100 sec) animation became very slo-o-ow + byte hs_delay = (byte) lround(100.0f / (float) param); + if (hs_delay == 1) { //if delay set to 1 (1/100 sec) animation became very slo-o-ow hs_delay = 2; frame_inc *= 2.0f; } - byte loop[]{1, 0, 0}, //infinite gif loop - delay[4] = { 0x0D, // Bit 0 - flag if transparent index given (checked), - // Bit 1 - User Input Flag (unchecked), - // Bits 2-4 - Disposal Method: - // 0 - unspecified, - // 1 - don't dispose, - // 2 - restore to background color, - // 3 - restore to previous (checked) - hs_delay, // >Hundredths of - 0, // seconds to wait< - 0}; // Transparent color index //TODO: try to calculate - ColorMapObject *output_palette = GifMakeMapObject(color_map_size, nullptr); - if(output_palette == nullptr) { - fputs("Unable to generate gif color palette\n", stderr); - status = EXIT_FAILURE; - goto CLOSE_FILE; - } + byte loop[]{1, 0, 0}, //infinite gif loop + delay[4] = {0x0D, // Bit 0 - flag if transparent index given (checked), + // Bit 1 - User Input Flag (unchecked), + // Bits 2-4 - Disposal Method: + // 0 - unspecified, + // 1 - don't dispose, + // 2 - restore to background color, + // 3 - restore to previous (checked) + hs_delay, // >Hundredths of + 0, // seconds to wait< + lp_COLOR_BG // Transparent color index //TODO: try to calculate + }; + int color_count = 1 << lp_COLOR_DEPTH; EGifSetGifVersion(writer, true); if (EGifPutScreenDesc( writer, - w, h, lp_COLOR_DEPTH, 0, - output_palette + w, h, lp_COLOR_DEPTH, lp_COLOR_BG, + nullptr ) == GIF_ERROR) { - fprintf(stderr,"Unable to write gif screen description: %s\n", GifErrorString(writer->Error)); + fprintf(stderr, "Unable to write gif screen description: %s\n", GifErrorString(writer->Error)); status = EXIT_FAILURE; - goto FREE_MAP; + goto CLOSE_FILE; } if (EGifPutExtensionLeader(writer, APPLICATION_EXT_FUNC_CODE) == GIF_ERROR) { - fprintf(stderr,"Unable to write gif extension: %s\n", GifErrorString(writer->Error)); + fprintf(stderr, "Unable to write gif extension: %s\n", GifErrorString(writer->Error)); status = EXIT_FAILURE; - goto FREE_MAP; + goto CLOSE_FILE; } if (EGifPutExtensionBlock(writer, 11, "NETSCAPE2.0") == GIF_ERROR) { - fprintf(stderr,"Unable to write gif extension: %s\n", GifErrorString(writer->Error)); + fprintf(stderr, "Unable to write gif extension: %s\n", GifErrorString(writer->Error)); status = EXIT_FAILURE; - goto FREE_MAP; + goto CLOSE_FILE; } if (EGifPutExtensionBlock(writer, 3, loop) == GIF_ERROR) { - fprintf(stderr,"Unable to write gif extension: %s\n", GifErrorString(writer->Error)); + fprintf(stderr, "Unable to write gif extension: %s\n", GifErrorString(writer->Error)); status = EXIT_FAILURE; - goto FREE_MAP; + goto CLOSE_FILE; } if (EGifPutExtensionTrailer(writer) == GIF_ERROR) { - fprintf(stderr,"Unable to write gif extension: %s\n", GifErrorString(writer->Error)); + fprintf(stderr, "Unable to write gif extension: %s\n", GifErrorString(writer->Error)); status = EXIT_FAILURE; } - while (frame_current < (float)frame_count && status == EXIT_SUCCESS) { + while (frame_current < (float) frame_count && status == EXIT_SUCCESS) { Surface surface(buffer.get(), w, h, w * lp_COLOR_BYTES); animation->renderSync(lround(frame_current), surface); auto *byte_buffer_raw = reinterpret_cast (buffer.get()); size_t pixel_count = w * h; - byte *rb = (byte *)calloc(pixel_count, sizeof(byte)), - *gb = (byte *)calloc(pixel_count, sizeof(byte)), - *bb = (byte *)calloc(pixel_count, sizeof(byte)), - *out = (byte *)calloc(pixel_count, sizeof(byte)); + byte *rb = (byte *) calloc(pixel_count, sizeof(byte)), + *gb = (byte *) calloc(pixel_count, sizeof(byte)), + *bb = (byte *) calloc(pixel_count, sizeof(byte)), + *out = (byte *) calloc(pixel_count, sizeof(byte)); + byte *line_buffer = out; if (rb == nullptr || gb == nullptr || bb == nullptr || out == nullptr) { perror("Unable to init color byte buffer"); - if(rb != nullptr) free(rb); - if(gb != nullptr) free(gb); - if(bb != nullptr) free(bb); - if(out != nullptr) free(out); + if (rb != nullptr) free(rb); + if (gb != nullptr) free(gb); + if (bb != nullptr) free(bb); + if (out != nullptr) free(out); status = EXIT_FAILURE; break; } + ColorMapObject *output_palette = GifMakeMapObject(color_count, nullptr); + if (output_palette == nullptr) { + fputs("Unable to generate gif color palette\n", stderr); + free(rb); + free(gb); + free(bb); + status = EXIT_FAILURE; + goto FREE_GIF; + } for (size_t i = 0; i < pixel_count; ++i) { byte b, g, r, a; b = *byte_buffer_raw++; @@ -246,7 +251,7 @@ int convert_and_write_to(byte *in_file_data, uint8_t convert_to, int w, int h, u b += (byte) (((float) b) * (float) (0xFF - a) / 255.0f); } } else { - r = g = b = 0; //background + r = g = b = lp_COLOR_BG; //background } rb[i] = r; gb[i] = g; @@ -258,14 +263,16 @@ int convert_and_write_to(byte *in_file_data, uint8_t convert_to, int w, int h, u free(rb); free(gb); free(bb); - if(error_code != GIF_OK){ - free(out); + if (error_code != GIF_OK) { fputs("Unable quantize gif colors\n", stderr); status = EXIT_FAILURE; - break; + goto FREE_GIF; } - byte *line_buffer = out; - if(EGifPutExtension(writer, GRAPHICS_EXT_FUNC_CODE, 4, delay) == GIF_OK) { + //GifMakeMapObject inside EGifPutImageDesc needs color count to be power of 2 + if(output_palette->ColorCount < color_count){ + output_palette->ColorCount = color_count; + } + if (EGifPutExtension(writer, GRAPHICS_EXT_FUNC_CODE, 4, delay) == GIF_OK) { if (EGifPutImageDesc(writer, 0, 0, w, h, false, output_palette) == GIF_OK) { for (int line = 0; line < h; ++line) { if (EGifPutLine(writer, line_buffer, w) != GIF_OK) { @@ -275,7 +282,7 @@ int convert_and_write_to(byte *in_file_data, uint8_t convert_to, int w, int h, u } line_buffer += w; } - } else{ + } else { fprintf(stderr, "Unable to write gif image info: %s\n", GifErrorString(writer->Error)); status = EXIT_FAILURE; } @@ -283,18 +290,17 @@ int convert_and_write_to(byte *in_file_data, uint8_t convert_to, int w, int h, u fprintf(stderr, "Unable to write gif extension: %s\n", GifErrorString(writer->Error)); status = EXIT_FAILURE; } - free(out); frame_current += frame_inc; + FREE_GIF: + free(out); + GifFreeMapObject(output_palette); } -FREE_MAP: - GifFreeMapObject(output_palette); -CLOSE_FILE: + + CLOSE_FILE: if (EGifCloseFile(writer, &error_code) != GIF_OK) { fprintf(stderr, "Unable to finalize GIF writer: %s\n", GifErrorString(error_code)); status = EXIT_FAILURE; } - //already closed by EGifCloseFile -// out_file->file_pointer = nullptr; break; } default: @@ -473,7 +479,7 @@ int main(int argc, char **argv) { break; } default: - fputs("Usage: PROG input_file|- output_file|- png|pngs|gif [resolution(128x128)] [param]\n", stderr); + fprintf(stderr, "Usage: %s input_file|- output_file|- png|pngs|gif [resolution(128x128)] [param]\n", argv[0]); return EXIT_FAILURE; } @@ -490,7 +496,7 @@ int main(int argc, char **argv) { if (result == EXIT_SUCCESS) { byte eos[1] = {'\0'}; bb_append(&in_file_data, eos, 1); - result = convert_and_write_to(in_file_data.buffer, convert_to, (int)w, (int)h, param, &out_file); + result = convert_and_write_to(in_file_data.buffer, convert_to, (int) w, (int) h, param, &out_file); } else fputs("zlib error\n", stderr); diff --git a/lottie_export.h b/lottie_export.h index 38742e1..559f0fc 100644 --- a/lottie_export.h +++ b/lottie_export.h @@ -51,6 +51,7 @@ using namespace rlottie; #define lp_COLOR_DEPTH 8 #define lp_COLOR_BYTES 4 +#define lp_COLOR_BG 0 typedef uint8_t byte; diff --git a/memcheck.log b/memcheck.log index 068938f..db82fab 100644 --- a/memcheck.log +++ b/memcheck.log @@ -1075,3 +1075,120 @@ Parameters: AnimatedSticker.tgs - gif 256x256 30 ==50096== suppressed: 0 bytes in 0 blocks ==50096== ==50096== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) +==25029== Memcheck, a memory error detector +==25029== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. +==25029== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info +==25029== Command: build/lottieconverter cmake-build-debug/lottieconverter test/1.tgs out.gif gif 300x300 25 +==25029== +Usage: PROG input_file|- output_file|- png|pngs|gif [resolution(128x128)] [param] +==25029== +==25029== HEAP SUMMARY: +==25029== in use at exit: 0 bytes in 0 blocks +==25029== total heap usage: 1 allocs, 1 frees, 72,704 bytes allocated +==25029== +==25029== All heap blocks were freed -- no leaks are possible +==25029== +==25029== For lists of detected and suppressed errors, rerun with: -s +==25029== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) +==25116== Memcheck, a memory error detector +==25116== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. +==25116== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info +==25116== Command: build/lottieconverter cmake-build-debug/lottieconverter test/1.tgs out.gif gif 300x300 25 +==25116== +Usage: PROG input_file|- output_file|- png|pngs|gif [resolution(128x128)] [param] +==25116== +==25116== HEAP SUMMARY: +==25116== in use at exit: 0 bytes in 0 blocks +==25116== total heap usage: 1 allocs, 1 frees, 72,704 bytes allocated +==25116== +==25116== All heap blocks were freed -- no leaks are possible +==25116== +==25116== For lists of detected and suppressed errors, rerun with: -s +==25116== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) +==25285== Memcheck, a memory error detector +==25285== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. +==25285== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info +==25285== Command: build/lottieconverter cmake-build-debug/lottieconverter test/1.tgs out.gif gif 300x300 25 +==25285== +Usage: PROG input_file|- output_file|- png|pngs|gif [resolution(128x128)] [param] +==25285== +==25285== HEAP SUMMARY: +==25285== in use at exit: 0 bytes in 0 blocks +==25285== total heap usage: 1 allocs, 1 frees, 72,704 bytes allocated +==25285== +==25285== All heap blocks were freed -- no leaks are possible +==25285== +==25285== For lists of detected and suppressed errors, rerun with: -s +==25285== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) +==25770== Memcheck, a memory error detector +==25770== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. +==25770== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info +==25770== Command: build/lottieconverter cmake-build-debug/lottieconverter test/1.tgs out.gif gif 300x300 25 +==25770== +Usage: PROG input_file|- output_file|- png|pngs|gif [resolution(128x128)] [param] +==25770== +==25770== HEAP SUMMARY: +==25770== in use at exit: 0 bytes in 0 blocks +==25770== total heap usage: 1 allocs, 1 frees, 72,704 bytes allocated +==25770== +==25770== All heap blocks were freed -- no leaks are possible +==25770== +==25770== For lists of detected and suppressed errors, rerun with: -s +==25770== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) +==26324== Memcheck, a memory error detector +==26324== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. +==26324== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info +==26324== Command: build/lottieconverter cmake-build-debug/lottieconverter test/1.tgs out.gif gif 300x300 25 +==26324== +Usage: build/lottieconverter input_file|- output_file|- png|pngs|gif [resolution(128x128)] [param] +==26324== +==26324== HEAP SUMMARY: +==26324== in use at exit: 0 bytes in 0 blocks +==26324== total heap usage: 1 allocs, 1 frees, 72,704 bytes allocated +==26324== +==26324== All heap blocks were freed -- no leaks are possible +==26324== +==26324== For lists of detected and suppressed errors, rerun with: -s +==26324== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) +==26334== Memcheck, a memory error detector +==26334== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. +==26334== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info +==26334== Command: build/lottieconverter test/1.tgs out.gif gif 300x300 25 +==26334== +==26334== +==26334== HEAP SUMMARY: +==26334== in use at exit: 0 bytes in 0 blocks +==26334== total heap usage: 6,271 allocs, 6,271 frees, 17,765,588 bytes allocated +==26334== +==26334== All heap blocks were freed -- no leaks are possible +==26334== +==26334== For lists of detected and suppressed errors, rerun with: -s +==26334== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) +==30932== Memcheck, a memory error detector +==30932== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. +==30932== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info +==30932== Command: build/lottieconverter test/1.tgs test/out/1.gif gif 200x200 25 +==30932== +==30932== +==30932== HEAP SUMMARY: +==30932== in use at exit: 0 bytes in 0 blocks +==30932== total heap usage: 4,441 allocs, 4,441 frees, 12,668,229 bytes allocated +==30932== +==30932== All heap blocks were freed -- no leaks are possible +==30932== +==30932== For lists of detected and suppressed errors, rerun with: -s +==30932== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) +==31128== Memcheck, a memory error detector +==31128== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. +==31128== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info +==31128== Command: build/lottieconverter test/1.tgs test/out/1.gif gif 200x200 10 +==31128== +==31128== +==31128== HEAP SUMMARY: +==31128== in use at exit: 0 bytes in 0 blocks +==31128== total heap usage: 3,359 allocs, 3,359 frees, 5,894,416 bytes allocated +==31128== +==31128== All heap blocks were freed -- no leaks are possible +==31128== +==31128== For lists of detected and suppressed errors, rerun with: -s +==31128== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) diff --git a/test/!LICENCE.txt b/test/!LICENCE.txt new file mode 100644 index 0000000..2ebb689 --- /dev/null +++ b/test/!LICENCE.txt @@ -0,0 +1,8 @@ +All stickers located inside this directory received from Telegram (Telegram +Messenger Inc.). + +All rights to these works belong to their authors and are used in this project +for testing purposes only on the principle of "fair use". + +Developer(s) of this project do not declare themselves as authors and do +not claim any other rights. diff --git a/test/1.tgs b/test/1.tgs new file mode 100644 index 0000000000000000000000000000000000000000..b65a5be340beca03ba5d4aa0edc72b45edc357c0 GIT binary patch literal 30536 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

1Jb?*3u6yC^bF#y#1+_;lU1>n<^9 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 iE;BnDyv=RiLZcyUZtjL!Y /dev/null && pwd )" + +OUT="$IN"/out +EXE="$1" + +rm -rf "$OUT" +mkdir "$OUT" + +function ck { + if $@; then + echo PASS + else + >&2 echo "FAIL: $@" + exit 1 + fi +} + +ck "$EXE" "$IN"/1.tgs "$OUT"/1.png png +ck "$EXE" "$IN"/2.tgs "$OUT"/2.png png 200x200 +ck "$EXE" "$IN"/3.tgs "$OUT"/3.png png 500x500 100 +ck "$EXE" "$IN"/4.tgs "$OUT"/4_ pngs 100x100 5 +cat "$IN"/5.json | ck "$EXE" - "$OUT"/5.gif gif 100x100 25 +ck "$EXE" "$IN"/6.json - gif 200x200 50 > "$OUT"/6.gif +cat "$IN"/7.json | ck "$EXE" - - gif 500x500 100 > "$OUT"/7.gif