From f79f2d1237e1a776fc10abc1d9def3c06c5c12d8 Mon Sep 17 00:00:00 2001 From: Rodolfo Ribeiro Gomes Date: Tue, 30 Jan 2024 02:12:28 -0300 Subject: [PATCH] feat: add Magick++ as possible importer too Suggested in discussion of #2795 https://github.com/synfig/synfig/pull/2795#issuecomment-1242883274 to allow SVG import in .lst files, without imagemagick module --- synfig-core/po/POTFILES.in | 2 + .../src/modules/mod_magickpp/CMakeLists.txt | 1 + .../src/modules/mod_magickpp/Makefile.am | 2 + synfig-core/src/modules/mod_magickpp/main.cpp | 36 +++- .../modules/mod_magickpp/mptr_magickpp.cpp | 164 ++++++++++++++++++ .../src/modules/mod_magickpp/mptr_magickpp.h | 72 ++++++++ 6 files changed, 276 insertions(+), 1 deletion(-) create mode 100644 synfig-core/src/modules/mod_magickpp/mptr_magickpp.cpp create mode 100644 synfig-core/src/modules/mod_magickpp/mptr_magickpp.h diff --git a/synfig-core/po/POTFILES.in b/synfig-core/po/POTFILES.in index 7ec97fdfe97..32c6681ce82 100644 --- a/synfig-core/po/POTFILES.in +++ b/synfig-core/po/POTFILES.in @@ -124,6 +124,8 @@ src/modules/mod_libavcodec/mptr.h src/modules/mod_libavcodec/trgt_av.cpp src/modules/mod_libavcodec/trgt_av.h src/modules/mod_magickpp/main.cpp +src/modules/mod_magickpp/mptr_magickpp.cpp +src/modules/mod_magickpp/mptr_magickpp.h src/modules/mod_magickpp/trgt_magickpp.cpp src/modules/mod_magickpp/trgt_magickpp.h src/modules/mod_mng/main.cpp diff --git a/synfig-core/src/modules/mod_magickpp/CMakeLists.txt b/synfig-core/src/modules/mod_magickpp/CMakeLists.txt index a2b46b68048..a3db6cc5cc4 100644 --- a/synfig-core/src/modules/mod_magickpp/CMakeLists.txt +++ b/synfig-core/src/modules/mod_magickpp/CMakeLists.txt @@ -1,5 +1,6 @@ add_library(mod_magickpp MODULE "${CMAKE_CURRENT_LIST_DIR}/main.cpp" + "${CMAKE_CURRENT_LIST_DIR}/mptr_magickpp.cpp" "${CMAKE_CURRENT_LIST_DIR}/trgt_magickpp.cpp" ) diff --git a/synfig-core/src/modules/mod_magickpp/Makefile.am b/synfig-core/src/modules/mod_magickpp/Makefile.am index 93a2e558e4e..fdc9b861a44 100644 --- a/synfig-core/src/modules/mod_magickpp/Makefile.am +++ b/synfig-core/src/modules/mod_magickpp/Makefile.am @@ -18,6 +18,8 @@ module_LTLIBRARIES = libmod_magickpp.la libmod_magickpp_la_SOURCES = \ main.cpp \ + mptr_magickpp.cpp \ + mpte_magickpp.h \ trgt_magickpp.cpp \ trgt_magickpp.h diff --git a/synfig-core/src/modules/mod_magickpp/main.cpp b/synfig-core/src/modules/mod_magickpp/main.cpp index 5f1f8493385..9d7df117772 100644 --- a/synfig-core/src/modules/mod_magickpp/main.cpp +++ b/synfig-core/src/modules/mod_magickpp/main.cpp @@ -4,6 +4,7 @@ ** ** \legal ** Copyright (c) 2007, 2008 Chris Moore +** Copyright (c) 2024 Synfig Contributors ** ** This file is part of Synfig. ** @@ -37,6 +38,7 @@ #include #include +#include "mptr_magickpp.h" #include "trgt_magickpp.h" #endif @@ -46,7 +48,7 @@ MODULE_DESC_BEGIN(mod_magickpp) MODULE_NAME("Magick++ Module (libMagick++)") MODULE_DESCRIPTION("Provides an animated GIF target") MODULE_AUTHOR("Chris Moore") - MODULE_VERSION("1.0") + MODULE_VERSION("2.0") MODULE_COPYRIGHT(SYNFIG_COPYRIGHT) MODULE_DESC_END @@ -216,4 +218,36 @@ MODULE_INVENTORY_BEGIN(mod_magickpp) TARGET_EXT(magickpp_trgt, "ycbcra") TARGET_EXT(magickpp_trgt, "yuv") END_TARGETS + + BEGIN_IMPORTERS + IMPORTER_EXT(magickpp_mptr,"jpg") + IMPORTER_EXT(magickpp_mptr,"jpeg") + IMPORTER_EXT(magickpp_mptr,"png") + IMPORTER_EXT(magickpp_mptr,"bmp") + IMPORTER_EXT(magickpp_mptr,"gif") + IMPORTER_EXT(magickpp_mptr,"pcx") + IMPORTER_EXT(magickpp_mptr,"tif") + IMPORTER_EXT(magickpp_mptr,"tiff") + IMPORTER_EXT(magickpp_mptr,"tga") + IMPORTER_EXT(magickpp_mptr,"ps") + IMPORTER_EXT(magickpp_mptr,"pdf") + IMPORTER_EXT(magickpp_mptr,"pgm") + IMPORTER_EXT(magickpp_mptr,"psd") + IMPORTER_EXT(magickpp_mptr,"xcf") + IMPORTER_EXT(magickpp_mptr,"svg") + IMPORTER_EXT(magickpp_mptr,"tim") + IMPORTER_EXT(magickpp_mptr,"xpm") + IMPORTER_EXT(magickpp_mptr,"miff") + IMPORTER_EXT(magickpp_mptr,"ico") + IMPORTER_EXT(magickpp_mptr,"eps") + IMPORTER_EXT(magickpp_mptr,"ttf") + IMPORTER_EXT(magickpp_mptr,"pix") + IMPORTER_EXT(magickpp_mptr,"rla") + IMPORTER_EXT(magickpp_mptr,"mat") + IMPORTER_EXT(magickpp_mptr,"html") + IMPORTER_EXT(magickpp_mptr,"ept") + IMPORTER_EXT(magickpp_mptr,"dcm") + IMPORTER_EXT(magickpp_mptr,"fig") + IMPORTER_EXT(magickpp_mptr,"webp") + END_IMPORTERS MODULE_INVENTORY_END diff --git a/synfig-core/src/modules/mod_magickpp/mptr_magickpp.cpp b/synfig-core/src/modules/mod_magickpp/mptr_magickpp.cpp new file mode 100644 index 00000000000..a30ce0b947b --- /dev/null +++ b/synfig-core/src/modules/mod_magickpp/mptr_magickpp.cpp @@ -0,0 +1,164 @@ +/* === S Y N F I G ========================================================= */ +/*! \file mptr_magickpp.cpp +** \brief Magick++ Importer (magickpp_mptr) +** +** \legal +** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley +** Copyright (c) 2024 Synfig Contributors +** +** This file is part of Synfig. +** +** Synfig is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Synfig 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 General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with Synfig. If not, see . +** \endlegal +** +** ========================================================================= */ + +/* === H E A D E R S ======================================================= */ + +#ifdef USING_PCH +# include "pch.h" +#else +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "mptr_magickpp.h" + +#include +#include +#include + +#include + +#endif + +/* === M A C R O S ========================================================= */ + +using namespace synfig; + +/* === G L O B A L S ======================================================= */ + +SYNFIG_IMPORTER_INIT(magickpp_mptr); +SYNFIG_IMPORTER_SET_NAME(magickpp_mptr,"magick++"); +SYNFIG_IMPORTER_SET_EXT(magickpp_mptr,"svg"); +SYNFIG_IMPORTER_SET_VERSION(magickpp_mptr,"0.1"); +SYNFIG_IMPORTER_SET_SUPPORTS_FILE_SYSTEM_WRAPPER(magickpp_mptr, false); + +/* === M E T H O D S ======================================================= */ + +magickpp_mptr::magickpp_mptr(const synfig::FileSystem::Identifier& identifier) + : synfig::Importer(identifier), animation_repetitions_(0) +{ + Magick::InitializeMagick(synfig::OS::get_binary_path().u8_str()); + + try { + std::string filename = identifier.file_system->get_real_filename(identifier.filename.u8string()); + Magick::Image image; + image.ping(filename+"[-1]"); + auto n_frames = image.scene() + 1; + if (n_frames <= 1) { + animation_repetitions_ = 0; + } else { + frame_time_list_.resize(n_frames); + synfig::Time current_time; + for (size_t i = 0; i < n_frames; ++i) { + image.ping(strprintf("%s[%zu]", filename.c_str(), i)); + frame_time_list_[i] = current_time; + current_time += image.animationDelay() * 0.01; // The delay is in multiple of 10ms + } + animation_length_ = current_time; + animation_repetitions_ = image.animationIterations(); + } + } catch (Magick::Error& err) { + // because 'Error' is derived from the standard C++ exception, it has a 'what()' method + synfig::error(_("Magick++ importer: error occurred reading a file: %s"), err.what()); + } catch (...) { + synfig::error(_("Magick++ importer: an unhandled error has occurred on reading file %s"), identifier.filename.u8_str()); + } +} + +magickpp_mptr::~magickpp_mptr() +{ +} + +bool +magickpp_mptr::is_animated() +{ + return frame_time_list_.size() > 0; +} + +bool +magickpp_mptr::get_frame(synfig::Surface& surface, const synfig::RendDesc& /*renddesc*/, synfig::Time time, synfig::ProgressCallback* /*callback*/) +{ + const std::string filename = identifier.file_system->get_real_filename(identifier.filename.u8string()); + + try { + Magick::Image image; + if (!is_animated()) { + image.read(filename); + } else { + int repetition_n = 0; + while (time >= animation_length_) { + ++repetition_n; + time -= animation_length_; + } + + auto frame_index = frame_time_list_.size() - 1; + if (animation_repetitions_ == 0 || repetition_n < animation_repetitions_) { + for (frame_index = frame_time_list_.size() - 1; frame_index > 0; --frame_index) { + if (time >= frame_time_list_[frame_index]) + break; + } + } + + image.read(strprintf("%s[%zu]", filename.c_str(), frame_index)); + } + const auto width = image.size().width(); + const auto height = image.size().height(); + surface.set_wh(width, height); + + const Magick::PixelPacket* packet = image.getConstPixels(0, 0, width, height); + if (!packet) { + synfig::error(_("Magick++ importer: couldn't get pixel packet")); + return false; + } + + // Sadly ImageMagick is a mess with this QuantumRange macro - it needs Magick namespace in its parsing... + // constexpr synfig::Color::value_type factor = 1. / QuantumRange; + // alternative way: + synfig::Color::value_type factor = 1.; + { + using namespace Magick; + + factor = QuantumRange; + } + + for (size_t y = 0, i = 0; y < height; ++y) { + for (size_t x = 0; x < width; ++x, ++i) { + const auto& color = packet[i]; + auto surface_color = synfig::Color(color.red / factor, color.green / factor, color.blue / factor, 1. - color.opacity / factor); + + surface[y][x] = surface_color; + } + } + } catch (Magick::Error& err) { + synfig::error(_("Magick++ importer: error occurred fetching pixels: %s"), err.what()); + return false; + } catch (...) { + synfig::error(_("Magick++ importer: an unhandled error has occurred on fetching pixels from file %s"), identifier.filename.u8_str()); + return false; + } + + return true; +} diff --git a/synfig-core/src/modules/mod_magickpp/mptr_magickpp.h b/synfig-core/src/modules/mod_magickpp/mptr_magickpp.h new file mode 100644 index 00000000000..4cdafcdd220 --- /dev/null +++ b/synfig-core/src/modules/mod_magickpp/mptr_magickpp.h @@ -0,0 +1,72 @@ +/* === S Y N F I G ========================================================= */ +/*! \file mptr_magickpp.h +** \brief Header for Magick++ Importer (magickpp_mptr) +** +** \legal +** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley +** Copyright (c) 2024 Synfig Contributors +** +** This file is part of Synfig. +** +** Synfig is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Synfig 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 General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with Synfig. If not, see . +** \endlegal +** +** ========================================================================= */ + +/* === S T A R T =========================================================== */ + +#ifndef SYNFIG_MPTR_MAGICKPP_H +#define SYNFIG_MPTR_MAGICKPP_H + +/* === H E A D E R S ======================================================= */ + +#include +#include + +/* === M A C R O S ========================================================= */ + +/* === T Y P E D E F S ===================================================== */ + +/* === C L A S S E S & S T R U C T S ======================================= */ + +/** + * Import static images, animated images or, possibly, videos + * by using Magick++ library + */ +class magickpp_mptr : public synfig::Importer +{ + SYNFIG_IMPORTER_MODULE_EXT + +public: + magickpp_mptr(const synfig::FileSystem::Identifier& identifier); + + ~magickpp_mptr(); + + bool is_animated() override; + + bool get_frame(synfig::Surface& surface, const synfig::RendDesc& renddesc, synfig::Time time, synfig::ProgressCallback* callback) override; + +private: + // Info for animations + /** number of repetitions. Zero means infinity */ + ssize_t animation_repetitions_; + /** Initial time of each frame */ + std::vector frame_time_list_; + /** Total duration of an animation cycle */ + synfig::Time animation_length_; +}; + +/* === E N D =============================================================== */ + +#endif