From a47d5b58fd4b55a3fd3cce451f8839a830baf203 Mon Sep 17 00:00:00 2001 From: Frank Dana Date: Fri, 21 Jun 2019 01:07:49 -0400 Subject: [PATCH] Add backwards-compatible Imagemagick 7 support (#252) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add ImageMagick 7 compatibility A new header, `imclude/MagickUtilities.h`, is created to hold the compatibility `#define`s. The image-conversion code in `src/Frame.cpp` received the only major changes — instead of doing the export by hand (and having to account for changes in the underlying API), it uses the `MagickCore::ExportImagePixels()` function which does basically the same work, but accounts for all of the API changes for us. The API of that function is _unchanged_ from IM6 to IM7. TODO: `MagickCore::ExportImagePixels()` will return an `exception` struct if it encounters any problems. Currently the code ignores that, which it should not. * Add ImageMagick 7 compatibility A new header, `imclude/MagickUtilities.h`, is created to hold the compatibility `#define`s. The image-conversion code in `src/Frame.cpp` received the only major changes — instead of doing the export by hand (and having to account for changes in the underlying API), it uses the `MagickCore::ExportImagePixels()` function which does basically the same work, but accounts for all of the API changes for us. The API of that function is _unchanged_ from IM6 to IM7. TODO: `MagickCore::ExportImagePixels()` will return an `exception` struct if it encounters any problems. Currently the code ignores that, which it should not. Thanks @ferdnyc --- include/Frame.h | 6 ++-- include/ImageReader.h | 8 +++-- include/ImageWriter.h | 9 +++--- include/MagickUtilities.h | 61 +++++++++++++++++++++++++++++++++++++++ include/TextReader.h | 10 +++++-- include/effects/Mask.h | 7 +++-- src/Frame.cpp | 20 ++++--------- src/ImageReader.cpp | 7 ++++- src/ImageWriter.cpp | 6 +++- src/TextReader.cpp | 5 ++++ src/effects/Mask.cpp | 9 +++--- 11 files changed, 112 insertions(+), 36 deletions(-) create mode 100644 include/MagickUtilities.h diff --git a/include/Frame.h b/include/Frame.h index 6b682edb..1c4dd26c 100644 --- a/include/Frame.h +++ b/include/Frame.h @@ -53,14 +53,14 @@ #include #include #include "ZmqLogger.h" -#ifdef USE_IMAGEMAGICK - #include "Magick++.h" -#endif #include "ChannelLayouts.h" #include "AudioBufferSource.h" #include "AudioResampler.h" #include "Fraction.h" #include "JuceHeader.h" +#ifdef USE_IMAGEMAGICK + #include "MagickUtilities.h" +#endif #pragma SWIG nowarn=362 using namespace std; diff --git a/include/ImageReader.h b/include/ImageReader.h index e698e0c1..7ad23173 100644 --- a/include/ImageReader.h +++ b/include/ImageReader.h @@ -28,6 +28,9 @@ #ifndef OPENSHOT_IMAGE_READER_H #define OPENSHOT_IMAGE_READER_H +// Require ImageMagick support +#ifdef USE_IMAGEMAGICK + #include "ReaderBase.h" #include @@ -36,9 +39,9 @@ #include #include #include -#include "Magick++.h" #include "CacheMemory.h" #include "Exceptions.h" +#include "MagickUtilities.h" using namespace std; @@ -113,4 +116,5 @@ namespace openshot } -#endif +#endif //USE_IMAGEMAGICK +#endif //OPENSHOT_IMAGE_READER_H diff --git a/include/ImageWriter.h b/include/ImageWriter.h index 25177134..b7dd7dc2 100644 --- a/include/ImageWriter.h +++ b/include/ImageWriter.h @@ -32,10 +32,11 @@ * along with OpenShot Library. If not, see . */ - #ifndef OPENSHOT_IMAGE_WRITER_H #define OPENSHOT_IMAGE_WRITER_H +#ifdef USE_IMAGEMAGICK + #include "ReaderBase.h" #include "WriterBase.h" @@ -44,11 +45,10 @@ #include #include #include -#include "Magick++.h" #include "CacheMemory.h" #include "Exceptions.h" #include "OpenMPUtilities.h" - +#include "MagickUtilities.h" using namespace std; @@ -145,4 +145,5 @@ namespace openshot } -#endif +#endif //USE_IMAGEMAGICK +#endif //OPENSHOT_IMAGE_WRITER_H diff --git a/include/MagickUtilities.h b/include/MagickUtilities.h new file mode 100644 index 00000000..f3b7ea12 --- /dev/null +++ b/include/MagickUtilities.h @@ -0,0 +1,61 @@ +/** + * @file + * @brief Header file for MagickUtilities (IM6/IM7 compatibility overlay) + * @author Jonathan Thomas + * @author FeRD (Frank Dana) + */ + +/* LICENSE + * + * Copyright (c) 2008-2019 OpenShot Studios, LLC + * . This file is part of + * OpenShot Library (libopenshot), an open-source project dedicated to + * delivering high quality video editing and animation solutions to the + * world. For more information visit . + * + * OpenShot Library (libopenshot) 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 3 of the + * License, or (at your option) any later version. + * + * OpenShot Library (libopenshot) 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 OpenShot Library. If not, see . + */ + +#ifndef OPENSHOT_MAGICK_UTILITIES_H +#define OPENSHOT_MAGICK_UTILITIES_H + +#ifdef USE_IMAGEMAGICK + + #include "Magick++.h" + + // Determine ImageMagick version, as IM7 isn't fully + // backwards compatible + #ifndef NEW_MAGICK + #define NEW_MAGICK (MagickLibVersion >= 0x700) + #endif + + // IM7: ->alpha(bool) + // IM6: ->matte(bool) + #if NEW_MAGICK + #define MAGICK_IMAGE_ALPHA(im, a) im->alpha((a)) + #else + #define MAGICK_IMAGE_ALPHA(im, a) im->matte((a)) + #endif + + // IM7: vector + // IM6: list + // (both have the push_back() method which is all we use) + #if NEW_MAGICK + #define MAGICK_DRAWABLE vector + #else + #define MAGICK_DRAWABLE list + #endif + +#endif +#endif diff --git a/include/TextReader.h b/include/TextReader.h index d7d653d2..bb4bdc22 100644 --- a/include/TextReader.h +++ b/include/TextReader.h @@ -28,6 +28,9 @@ #ifndef OPENSHOT_TEXT_READER_H #define OPENSHOT_TEXT_READER_H +// Require ImageMagick support +#ifdef USE_IMAGEMAGICK + #include "ReaderBase.h" #include @@ -36,10 +39,10 @@ #include #include #include -#include "Magick++.h" #include "CacheMemory.h" #include "Enums.h" #include "Exceptions.h" +#include "MagickUtilities.h" using namespace std; @@ -91,7 +94,7 @@ namespace openshot string text_color; string background_color; std::shared_ptr image; - list lines; + MAGICK_DRAWABLE lines; bool is_open; GravityType gravity; @@ -144,4 +147,5 @@ namespace openshot } -#endif +#endif //USE_IMAGEMAGICK +#endif //OPENSHOT_TEXT_READER_H diff --git a/include/effects/Mask.h b/include/effects/Mask.h index ef707f5f..e5b8f649 100644 --- a/include/effects/Mask.h +++ b/include/effects/Mask.h @@ -25,8 +25,8 @@ * along with OpenShot Library. If not, see . */ -#ifndef OPENSHOT_WIPE_EFFECT_H -#define OPENSHOT_WIPE_EFFECT_H +#ifndef OPENSHOT_MASK_EFFECT_H +#define OPENSHOT_MASK_EFFECT_H #include "../EffectBase.h" @@ -45,6 +45,7 @@ #include "../QtImageReader.h" #include "../ChunkReader.h" #ifdef USE_IMAGEMAGICK + #include "../MagickUtilities.h" #include "../ImageReader.h" #endif @@ -54,7 +55,7 @@ namespace openshot { /** - * @brief This class uses the ImageMagick++ libraries, to apply alpha (or transparency) masks + * @brief This class uses the image libraries to apply alpha (or transparency) masks * to any frame. It can also be animated, and used as a powerful Wipe transition. * * These masks / wipes can also be combined, such as a transparency mask on top of a clip, which diff --git a/src/Frame.cpp b/src/Frame.cpp index aa7c0d87..5e06e61e 100644 --- a/src/Frame.cpp +++ b/src/Frame.cpp @@ -926,7 +926,7 @@ std::shared_ptr Frame::GetMagickImage() // Give image a transparent background color magick_image->backgroundColor(Magick::Color("none")); magick_image->virtualPixelMethod(Magick::TransparentVirtualPixelMethod); - magick_image->matte(true); + MAGICK_IMAGE_ALPHA(magick_image, true); return magick_image; } @@ -945,20 +945,12 @@ void Frame::AddMagickImage(std::shared_ptr new_image) qbuffer = new unsigned char[bufferSize](); unsigned char *buffer = (unsigned char*)qbuffer; - // Iterate through the pixel packets, and load our own buffer - // Each color needs to be scaled to 8 bit (using the ImageMagick built-in ScaleQuantumToChar function) - int numcopied = 0; - Magick::PixelPacket *pixels = new_image->getPixels(0,0, new_image->columns(), new_image->rows()); - for (int n = 0, i = 0; n < new_image->columns() * new_image->rows(); n += 1, i += 4) { - buffer[i+0] = MagickCore::ScaleQuantumToChar((Magick::Quantum) pixels[n].red); - buffer[i+1] = MagickCore::ScaleQuantumToChar((Magick::Quantum) pixels[n].green); - buffer[i+2] = MagickCore::ScaleQuantumToChar((Magick::Quantum) pixels[n].blue); - buffer[i+3] = 255 - MagickCore::ScaleQuantumToChar((Magick::Quantum) pixels[n].opacity); - numcopied+=4; - } + MagickCore::ExceptionInfo exception; + // TODO: Actually do something, if we get an exception here + MagickCore::ExportImagePixels(new_image->constImage(), 0, 0, new_image->columns(), new_image->rows(), "RGBA", Magick::CharPixel, buffer, &exception); - // Create QImage of frame data - image = std::shared_ptr(new QImage(qbuffer, width, height, width * BPP, QImage::Format_RGBA8888, (QImageCleanupFunction) &cleanUpBuffer, (void*) qbuffer)); + // Create QImage of frame data + image = std::shared_ptr(new QImage(qbuffer, width, height, width * BPP, QImage::Format_RGBA8888, (QImageCleanupFunction) &cleanUpBuffer, (void*) qbuffer)); // Update height and width width = image->width(); diff --git a/src/ImageReader.cpp b/src/ImageReader.cpp index 3c1d334a..491e1c5d 100644 --- a/src/ImageReader.cpp +++ b/src/ImageReader.cpp @@ -25,6 +25,9 @@ * along with OpenShot Library. If not, see . */ +// Require ImageMagick support +#ifdef USE_IMAGEMAGICK + #include "../include/ImageReader.h" using namespace openshot; @@ -59,7 +62,7 @@ void ImageReader::Open() // Give image a transparent background color image->backgroundColor(Magick::Color("none")); - image->matte(true); + MAGICK_IMAGE_ALPHA(image, true); } catch (Magick::Exception e) { // raise exception @@ -192,3 +195,5 @@ void ImageReader::SetJsonValue(Json::Value root) { Open(); } } + +#endif //USE_IMAGEMAGICK diff --git a/src/ImageWriter.cpp b/src/ImageWriter.cpp index 41626b09..5bc0367a 100644 --- a/src/ImageWriter.cpp +++ b/src/ImageWriter.cpp @@ -28,6 +28,9 @@ * along with OpenShot Library. If not, see . */ +//Require ImageMagick support +#ifdef USE_IMAGEMAGICK + #include "../include/ImageWriter.h" using namespace openshot; @@ -97,7 +100,7 @@ void ImageWriter::WriteFrame(std::shared_ptr frame) std::shared_ptr frame_image = frame->GetMagickImage(); frame_image->magick( info.vcodec ); frame_image->backgroundColor(Magick::Color("none")); - frame_image->matte(true); + MAGICK_IMAGE_ALPHA(frame_image, true); frame_image->quality(image_quality); frame_image->animationDelay(info.video_timebase.ToFloat() * 100); frame_image->animationIterations(number_of_loops); @@ -153,3 +156,4 @@ void ImageWriter::Close() ZmqLogger::Instance()->AppendDebugMethod("ImageWriter::Close", "", -1, "", -1, "", -1, "", -1, "", -1, "", -1); } +#endif //USE_IMAGEMAGICK diff --git a/src/TextReader.cpp b/src/TextReader.cpp index a24f26e4..b38c5f18 100644 --- a/src/TextReader.cpp +++ b/src/TextReader.cpp @@ -25,6 +25,9 @@ * along with OpenShot Library. If not, see . */ +// Require ImageMagick support +#ifdef USE_IMAGEMAGICK + #include "../include/TextReader.h" using namespace openshot; @@ -258,3 +261,5 @@ void TextReader::SetJsonValue(Json::Value root) { Open(); } } + +#endif //USE_IMAGEMAGICK diff --git a/src/effects/Mask.cpp b/src/effects/Mask.cpp index 95dd3489..e1c2db4d 100644 --- a/src/effects/Mask.cpp +++ b/src/effects/Mask.cpp @@ -238,11 +238,11 @@ void Mask::SetJsonValue(Json::Value root) { reader->SetJsonValue(root["reader"]); #ifdef USE_IMAGEMAGICK - } else if (type == "ImageReader") { + } else if (type == "ImageReader") { - // Create new reader - reader = new ImageReader(root["reader"]["path"].asString()); - reader->SetJsonValue(root["reader"]); + // Create new reader + reader = new ImageReader(root["reader"]["path"].asString()); + reader->SetJsonValue(root["reader"]); #endif } else if (type == "QtImageReader") { @@ -294,4 +294,3 @@ string Mask::PropertiesJSON(int64_t requested_frame) { // Return formatted string return root.toStyledString(); } -