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