1 /*
2  * This file is part of openfx-arena <https://github.com/olear/openfx-arena>,
3  * Copyright (C) 2016 INRIA
4  *
5  * openfx-arena is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as published
7  * by the Free Software Foundation.
8  *
9  * openfx-arena is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with openfx-arena.  If not, see <http://www.gnu.org/licenses/gpl-2.0.html>
16 */
17 
18 #include <iostream>
19 #include <stdint.h>
20 #include <Magick++.h>
21 #include "GenericReader.h"
22 #include "GenericOCIO.h"
23 #include "ofxsMacros.h"
24 #include "ofxsMultiThread.h"
25 #include "ofxsImageEffect.h"
26 
27 #define kPluginName "ReadMisc"
28 #define kPluginGrouping "Image/Readers"
29 #define kPluginIdentifier "fr.inria.openfx.ReadMisc"
30 #define kPluginVersionMajor 1
31 #define kPluginVersionMinor 1
32 #define kPluginEvaluation 80 // less than ReadOIIO
33 
34 #define kSupportsRGBA true
35 #define kSupportsRGB false
36 #define kSupportsXY false
37 #define kSupportsAlpha false
38 #define kSupportsTiles false
39 #define kIsMultiPlanar false
40 
41 using namespace OFX::IO;
42 
43 #ifdef OFX_IO_USING_OCIO
44 namespace OCIO = OCIO_NAMESPACE;
45 #endif
46 
47 OFXS_NAMESPACE_ANONYMOUS_ENTER
48 
49 class ReadMiscPlugin : public GenericReaderPlugin
50 {
51 public:
52     ReadMiscPlugin(OfxImageEffectHandle handle, const std::vector<std::string>& extensions);
53     virtual ~ReadMiscPlugin();
54 private:
isVideoStream(const std::string &)55     virtual bool isVideoStream(const std::string& /*filename*/) OVERRIDE FINAL { return false; }
56     virtual void decode(const std::string& filename, OfxTime time, int view, bool isPlayback, const OfxRectI& renderWindow, float *pixelData, const OfxRectI& bounds, OFX::PixelComponentEnum pixelComponents, int pixelComponentCount, int rowBytes) OVERRIDE FINAL;
57     virtual bool getFrameBounds(const std::string& filename, OfxTime time, int view, OfxRectI *bounds, OfxRectI* format, double *par, std::string *error, int *tile_width, int *tile_height) OVERRIDE FINAL;
58     virtual bool guessParamsFromFilename(const std::string& filename, std::string *colorspace, OFX::PreMultiplicationEnum *filePremult, OFX::PixelComponentEnum *components, int *componentCount) OVERRIDE FINAL;
59 };
60 
ReadMiscPlugin(OfxImageEffectHandle handle,const std::vector<std::string> & extensions)61 ReadMiscPlugin::ReadMiscPlugin(OfxImageEffectHandle handle, const std::vector<std::string>& extensions)
62 : GenericReaderPlugin(handle, extensions, kSupportsRGBA, kSupportsRGB, kSupportsXY, kSupportsAlpha, kSupportsTiles, kIsMultiPlanar)
63 {
64     Magick::InitializeMagick(NULL);
65 }
66 
~ReadMiscPlugin()67 ReadMiscPlugin::~ReadMiscPlugin()
68 {
69 }
70 
71 void
decode(const std::string & filename,OfxTime time,int,bool,const OfxRectI & renderWindow,float * pixelData,const OfxRectI & bounds,OFX::PixelComponentEnum,int,int)72 ReadMiscPlugin::decode(const std::string& filename,
73                       OfxTime time,
74                       int /*view*/,
75                       bool /*isPlayback*/,
76                       const OfxRectI& renderWindow,
77                       float *pixelData,
78                       const OfxRectI& bounds,
79                       OFX::PixelComponentEnum /*pixelComponents*/,
80                       int /*pixelComponentCount*/,
81                       int /*rowBytes*/)
82 {
83     #ifdef DEBUG
84     std::cout << "decode ..." << std::endl;
85     #endif
86 
87     Magick::Image image;
88     try {
89         image.backgroundColor("none"); // must be set to avoid bg
90     }
91     catch(Magick::Warning &warning) { // ignore since warns interupt render
92         #ifdef DEBUG
93         std::cout << warning.what() << std::endl;
94         #endif
95         image.backgroundColor("none"); // must be set to avoid bg
96     }
97     if (!filename.empty())
98         image.read(filename);
99     if (image.columns()>0 && image.rows()>0) {
100         image.flip();
101         image.write(0,0,renderWindow.x2 - renderWindow.x1,renderWindow.y2 - renderWindow.y1,"RGBA",Magick::FloatPixel,pixelData);
102     }
103     else {
104         setPersistentMessage(OFX::Message::eMessageError, "", "Unable to read image");
105         OFX::throwSuiteStatusException(kOfxStatErrFormat);
106     }
107 }
108 
getFrameBounds(const std::string & filename,OfxTime,int,OfxRectI * bounds,OfxRectI * format,double * par,std::string *,int * tile_width,int * tile_height)109 bool ReadMiscPlugin::getFrameBounds(const std::string& filename,
110                                     OfxTime /*time*/,
111                                     int /*view*/,
112                                     OfxRectI *bounds,
113                                     OfxRectI* format,
114                                     double *par,
115                                     std::string* /*error*/,int *tile_width, int *tile_height)
116 {
117 #ifdef DEBUG
118     std::cout << "getFrameBounds ..." << std::endl;
119     #endif
120 
121     Magick::Image image;
122     if (!filename.empty())
123         image.ping(filename);
124     if (image.columns()>0 && image.rows()>0) {
125         bounds->x1 = 0;
126         bounds->x2 = image.columns();
127         bounds->y1 = 0;
128         bounds->y2 = image.rows();
129         *format = *bounds;
130         *par = 1.0;
131     }
132     *tile_width = *tile_height = 0;
133     return true;
134 }
135 
guessParamsFromFilename(const std::string &,std::string * colorspace,OFX::PreMultiplicationEnum * filePremult,OFX::PixelComponentEnum * components,int * componentCount)136 bool ReadMiscPlugin::guessParamsFromFilename(const std::string& /*newFile*/,
137                                        std::string *colorspace,
138                                        OFX::PreMultiplicationEnum *filePremult,
139                                        OFX::PixelComponentEnum *components,
140                                        int *componentCount)
141 {
142     assert(colorspace && filePremult && components && componentCount);
143 # ifdef OFX_IO_USING_OCIO
144     *colorspace = "sRGB";
145 # endif
146     int startingTime = getStartingTime();
147     std::string filename;
148     OfxStatus st = getFilenameAtTime(startingTime, &filename);
149     if ( st != kOfxStatOK || filename.empty() ) {
150         return false;
151     }
152 
153     Magick::Image image;
154     try {
155         image.ping(filename);
156     }
157     catch(Magick::Warning &warning) { // ignore since warns interupt render
158         #ifdef DEBUG
159         std::cout << warning.what() << std::endl;
160         #endif
161     }
162     if (image.columns()==0 && image.rows()==0) {
163         setPersistentMessage(OFX::Message::eMessageError, "", "Unable to read image");
164         OFX::throwSuiteStatusException(kOfxStatErrFormat);
165     }
166 
167     *components = OFX::ePixelComponentRGBA;
168     *filePremult = OFX::eImageUnPreMultiplied;
169 
170     return true;
171 }
172 
173 using namespace OFX;
174 
175 mDeclareReaderPluginFactory(ReadMiscPluginFactory, {}, false);
176 
177 void
load()178 ReadMiscPluginFactory::load()
179 {
180     _extensions.clear();
181     _extensions.push_back("bmp"); // also handled by ReadOIIO (which has a higher evaluation)
182     _extensions.push_back("pcx");
183     _extensions.push_back("xpm");
184     //_extensions.push_back("gif"); // may be animated - better handled by ReadFFmpeg
185     _extensions.push_back("miff");
186 }
187 
188 /** @brief The basic describe function, passed a plugin descriptor */
describe(OFX::ImageEffectDescriptor & desc)189 void ReadMiscPluginFactory::describe(OFX::ImageEffectDescriptor &desc)
190 {
191     GenericReaderDescribe(desc, _extensions, kPluginEvaluation, kSupportsTiles, false);
192     desc.setLabel(kPluginName);
193 
194     desc.setPluginDescription("Read Misc image format.");
195 }
196 
197 /** @brief The describe in context function, passed a plugin descriptor and a context */
describeInContext(OFX::ImageEffectDescriptor & desc,ContextEnum context)198 void ReadMiscPluginFactory::describeInContext(OFX::ImageEffectDescriptor &desc, ContextEnum context)
199 {
200     PageParamDescriptor *page = GenericReaderDescribeInContextBegin(desc, context, isVideoStreamPlugin(), kSupportsRGBA, kSupportsRGB, kSupportsXY,kSupportsAlpha, kSupportsTiles, true);
201     GenericReaderDescribeInContextEnd(desc, context, page, "reference", "scene_linear");
202 }
203 
204 /** @brief The create instance function, the plugin must return an object derived from the \ref OFX::ImageEffect class */
createInstance(OfxImageEffectHandle handle,ContextEnum)205 ImageEffect* ReadMiscPluginFactory::createInstance(OfxImageEffectHandle handle,
206                                      ContextEnum /*context*/)
207 {
208     ReadMiscPlugin* ret =  new ReadMiscPlugin(handle, _extensions);
209     ret->restoreStateFromParams();
210     return ret;
211 }
212 
213 static ReadMiscPluginFactory p(kPluginIdentifier, kPluginVersionMajor, kPluginVersionMinor);
214 mRegisterPluginFactoryInstance(p)
215 
216 OFXS_NAMESPACE_ANONYMOUS_EXIT
217