1 /************************************************************************/
2 /* */
3 /* Copyright 2001-2002 by Gunnar Kedenburg */
4 /* Cognitive Systems Group, University of Hamburg, Germany */
5 /* */
6 /* This file is part of the VIGRA computer vision library. */
7 /* ( Version 1.5.0, Dec 07 2006 ) */
8 /* The VIGRA Website is */
9 /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */
10 /* Please direct questions, bug reports, and contributions to */
11 /* koethe@informatik.uni-hamburg.de or */
12 /* vigra@kogs1.informatik.uni-hamburg.de */
13 /* */
14 /* Permission is hereby granted, free of charge, to any person */
15 /* obtaining a copy of this software and associated documentation */
16 /* files (the "Software"), to deal in the Software without */
17 /* restriction, including without limitation the rights to use, */
18 /* copy, modify, merge, publish, distribute, sublicense, and/or */
19 /* sell copies of the Software, and to permit persons to whom the */
20 /* Software is furnished to do so, subject to the following */
21 /* conditions: */
22 /* */
23 /* The above copyright notice and this permission notice shall be */
24 /* included in all copies or substantial portions of the */
25 /* Software. */
26 /* */
27 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
28 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
29 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
30 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
31 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
32 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
33 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
34 /* OTHER DEALINGS IN THE SOFTWARE. */
35 /* */
36 /************************************************************************/
37
38 #include <fstream>
39 #include <algorithm>
40 #include <cctype> // std::tolower
41 #ifdef DEBUG
42 #include <iostream>
43 #endif
44
45 #include "vigra/config.hxx"
46 #include "vigra/error.hxx"
47 #include "codecmanager.hxx"
48
49 // the codecs
50 #include "jpeg.hxx"
51 #include "tiff.hxx"
52 #include "viff.hxx"
53 #include "sun.hxx"
54 #include "png.hxx"
55 #include "pnm.hxx"
56 #include "bmp.hxx"
57 #include "gif.hxx"
58 #include "hdr.hxx"
59
60 namespace vigra
61 {
62 // singleton pattern
63 CodecManager & CodecManager::manager()
64 {
65 static CodecManager manager;
66 return manager;
67 }
68
69 CodecManager::CodecManager()
70 {
71 #ifdef HasPNG
72 import( new PngCodecFactory() );
73 #endif
74 #ifdef HasJPEG
75 import( new JPEGCodecFactory() );
76 #endif
77 #ifdef HasTIFF
78 import( new TIFFCodecFactory() );
reversebytes(T & x) const79 #endif
80 import( new SunCodecFactory() );
81 import( new PnmCodecFactory() );
82 import( new ViffCodecFactory() );
83 import( new BmpCodecFactory() );
84 import( new GIFCodecFactory() );
85 import( new HDRCodecFactory() );
86 }
87
88 CodecManager::~CodecManager() {
89 // release previously allocated codecs
90 // (use erase ideom similar to
91 // S. Meyers' "Effective STL", Item 9)
92 for (std::map< std::string, CodecFactory * >::iterator i
93 = factoryMap.begin();
94 i != factoryMap.end();
95 /* nothing */ ) {
96 delete (*i).second;
97 factoryMap.erase(i++);
98 }
99 }
100
101 // add an encoder to the stores
102 void CodecManager::import( CodecFactory * cf )
103 {
104 CodecDesc desc = cf->getCodecDesc();
convert_to_host(T & x) const105
106 // fill extension map
107 const std::vector<std::string> & ext = desc.fileExtensions;
108 typedef std::vector<std::string>::const_iterator iter_type;
109 for( iter_type iter = ext.begin(); iter < ext.end(); ++iter )
110 extensionMap[*iter] = desc.fileType;
111
convert_to_host(T * x,size_t num) const112 // fill magic vector
113 for( VIGRA_CSTD::size_t i = 0; i < desc.magicStrings.size(); ++i )
114 magicStrings.push_back( std::pair<std::vector<char>, std::string>
115 ( desc.magicStrings[i],desc.fileType ) );
116 // fill factory map
117 factoryMap[desc.fileType] = cf;
118 }
119
convert_from_host(T & x) const120 // find out which pixel types a given codec supports
121 std::vector<std::string>
122 CodecManager::queryCodecPixelTypes( const std::string & filetype ) const
123 {
124 std::map< std::string, CodecFactory * >::const_iterator result
125 = factoryMap.find( filetype );
126 vigra_precondition( result != factoryMap.end(),
127 "the codec that was queried for its pixeltype does not exist" );
128
129 return result->second->getCodecDesc().pixelTypes;
130 }
131
132 // find out which pixel types a given codec supports
133 std::vector<int>
convert_to_host(char & x) const134 CodecManager::queryCodecBandNumbers( const std::string & filetype ) const
135 {
136 std::map< std::string, CodecFactory * >::const_iterator result
137 = factoryMap.find( filetype );
138 vigra_precondition( result != factoryMap.end(),
139 "the codec that was queried for its pixeltype does not exist" );
140
141 return result->second->getCodecDesc().bandNumbers;
142 }
convert_from_host(Int8 & x) const143
144 // find out if a given file type is supported
145 bool CodecManager::fileTypeSupported( const std::string & fileType )
146 {
147 std::map< std::string, CodecFactory * >::const_iterator search
148 = factoryMap.find( fileType );
149 return ( search != factoryMap.end() );
150 }
151
read_field(std::ifstream & stream,const byteorder & bo,T & x)152 // find out which file types are supported
153 std::vector<std::string> CodecManager::supportedFileTypes()
154 {
155 std::vector<std::string> fileTypes;
156 std::map< std::string, CodecFactory * >::const_iterator iter
157 = factoryMap.begin();
158 while ( iter != factoryMap.end() ) {
159 fileTypes.push_back( iter->first );
160 ++iter;
161 }
162 std::sort(fileTypes.begin(), fileTypes.end());
163 return fileTypes;
164 }
165
166 // find out which file extensions are supported
write_field(std::ofstream & stream,const byteorder & bo,T t)167 std::vector<std::string> CodecManager::supportedFileExtensions()
168 {
169 std::vector<std::string> fileExtensions;
170 std::map< std::string, std::string >::const_iterator iter
171 = extensionMap.begin();
172 while ( iter != extensionMap.end() ) {
173 fileExtensions.push_back( iter->first );
174 ++iter;
175 }
176 std::sort(fileExtensions.begin(), fileExtensions.end());
177 return fileExtensions;
178 }
179
180 std::string
181 CodecManager::getFileTypeByMagicString( const std::string & filename )
182 const
183 {
184 // support for reading the magic string from stdin has been dropped
185 // it was not guaranteed to work by the Standard
186
187 // get the magic string
188 const unsigned int magiclen = 4;
189 char fmagic[magiclen];
190 #ifdef VIGRA_NEED_BIN_STREAMS
191 std::ifstream stream(filename.c_str(), std::ios::binary);
192 #else
193 std::ifstream stream(filename.c_str());
194 #endif
195 if(!stream.good())
196 {
197 std::string msg("Unable to open file '");
198 msg += filename;
199 msg += "'.";
200 vigra_precondition(0, msg.c_str());
201 }
202 stream.read( fmagic, magiclen );
203 stream.close();
204
205 // compare with the known magic strings
206 typedef std::vector< std::pair< std::vector<char>, std::string > >
207 magic_type;
208 for( magic_type::const_iterator iter = magicStrings.begin();
209 iter < magicStrings.end(); ++iter ) {
210 const std::vector<char> & magic = iter->first;
211 if ( std::equal( magic.begin(), magic.end(), fmagic ) )
212 return iter->second;
213 }
214
215 // did not find a matching string
216 return std::string();
217 }
218
219 // look up decoder from the list, then return it
220 std::auto_ptr<Decoder>
221 CodecManager::getDecoder( const std::string & filename,
222 const std::string & filetype ) const
223 {
224 std::string fileType = filetype;
225
226 if ( fileType == "undefined" ) {
227
228 fileType = getFileTypeByMagicString(filename);
229 #ifdef DEBUG
230 std::cerr << "detected " << fileType
231 << " file format by magicstring of " << filename
232 << std::endl;
233 #endif
234 vigra_precondition( !fileType.empty(),
235 "did not find a matching file type." );
236
237 }
238
239 // return a codec factory by the file type
240 std::map< std::string, CodecFactory * >::const_iterator search
241 = factoryMap.find(fileType);
242 vigra_precondition( search != factoryMap.end(),
243 "did not find a matching codec for the given filetype" );
244
245 // okay, we can return a decoder
246 std::auto_ptr<Decoder> dec = search->second->getDecoder();
247 dec->init(filename);
248 return dec;
249 }
250
251 // look up encoder from the list, then return it
252 std::auto_ptr<Encoder>
253 CodecManager::getEncoder( const std::string & filename,
254 const std::string & fType ) const
255 {
256 std::string fileType = fType;
257
258 if ( fileType == "undefined" ) {
259 // look up the file type by the file extension
260 std::string ext
261 = filename.substr( filename.find_last_of(".") + 1 );
262 std::transform( ext.begin(), ext.end(), ext.begin(), (int (*)(int))&std::tolower );
263 std::map< std::string, std::string >::const_iterator search
264 = extensionMap.find(ext);
265 vigra_precondition( search != extensionMap.end(),
266 "did not find a matching codec for the given file extension" );
267 // at this point, we have found a valid fileType
268 fileType = search->second;
269 }
270
271 // return a codec factory by the file type
272 std::map< std::string, CodecFactory * >::const_iterator search
273 = factoryMap.find( fileType );
274 vigra_precondition( search != factoryMap.end(),
275 "did not find a matching codec for the given filetype" );
276
277 // okay, we can return an encoder
278 std::auto_ptr<Encoder> enc = search->second->getEncoder();
279 enc->init(filename);
280 return enc;
281 }
282
283 // get a decoder
284 std::auto_ptr<Decoder>
285 getDecoder( const std::string & filename, const std::string & filetype )
286 {
287 return codecManager().getDecoder( filename, filetype );
288 }
289
290 // get an encoder
291 std::auto_ptr<Encoder>
292 getEncoder( const std::string & filename, const std::string & filetype )
293 {
294 return codecManager().getEncoder( filename, filetype );
295 }
296
297 std::vector<std::string>
298 queryCodecPixelTypes( const std::string & codecname )
299 {
300 return codecManager().queryCodecPixelTypes(codecname);
301 }
302
303
304 // return true if downcasting is required, false otherwise
305 bool negotiatePixelType( std::string const & codecname,
306 std::string const & srcPixeltype, std::string & destPixeltype )
307 {
308 std::vector<std::string> ptypes
309 = codecManager().queryCodecPixelTypes(codecname);
310
311 std::vector<std::string>::iterator pend;
312 if(destPixeltype != "")
313 {
314 pend = std::find(ptypes.begin(), ptypes.end(), destPixeltype);
315 if(pend == ptypes.end())
316 {
317 std::string msg("exportImage(): file type ");
318 msg += codecname + " does not support requested pixel type "
319 + destPixeltype + ".";
320 vigra_precondition(false, msg.c_str());
321 }
322 ++pend;
323 }
324 else
325 {
326 pend = ptypes.end();
327 }
328
329 std::vector<std::string>::const_iterator result
330 = std::find( ptypes.begin(), pend, srcPixeltype );
331
332 if( result == pend)
333 {
334 if(destPixeltype == "")
335 destPixeltype = "UINT8";
336 // must always downcast
337 return true;
338 }
339 else
340 {
341 if(destPixeltype == "")
342 destPixeltype = srcPixeltype;
343 // don't downcast
344 return false;
345 }
346 }
347
348 bool isPixelTypeSupported( const std::string & codecname,
349 const std::string & pixeltype )
350 {
351 std::vector<std::string> ptypes
352 = codecManager().queryCodecPixelTypes(codecname);
353 std::vector<std::string>::const_iterator result
354 = std::find( ptypes.begin(), ptypes.end(), pixeltype );
355 return ( result != ptypes.end() );
356 }
357
358 bool isBandNumberSupported( const std::string & codecname,
359 int bands )
360 {
361 std::vector<int> bandNumbers
362 = codecManager().queryCodecBandNumbers(codecname);
363 if(bandNumbers[0] == 0)
364 return true; // any band number supported
365 std::vector<int>::const_iterator result
366 = std::find( bandNumbers.begin(), bandNumbers.end(), bands );
367 return ( result != bandNumbers.end() );
368 }
369
370 } // namespace vigra
371