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