Update the trunk to the OpenCV's CVS (2008-07-14)
[opencv] / otherlibs / highgui / loadsave.cpp
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                        Intel License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 //   * Redistribution's of source code must retain the above copyright notice,
20 //     this list of conditions and the following disclaimer.
21 //
22 //   * Redistribution's in binary form must reproduce the above copyright notice,
23 //     this list of conditions and the following disclaimer in the documentation
24 //     and/or other materials provided with the distribution.
25 //
26 //   * The name of Intel Corporation may not be used to endorse or promote products
27 //     derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41
42 //
43 //  Loading and saving IPL images.
44 //
45
46 #include "_highgui.h"
47 #include "grfmts.h"
48
49 #if 0
50 /****************************************************************************************\
51 *                              Path class (list of search folders)                       *
52 \****************************************************************************************/
53
54 class  CvFilePath
55 {
56 public:
57     CvFilePath();
58     ~CvFilePath();
59
60     // preprocess folder or file name - calculate its length,
61     // check for invalid symbols in the name and substitute
62     // all backslashes with simple slashes.
63     // the result is put into the specified buffer
64     static int Preprocess( const char* filename, char* buffer );
65
66     // add folder to the path
67     bool Add( const char* path );
68
69     // clear the path
70     void Clear();
71
72     // return the path - string, where folders are separated by ';'
73     const char* Get() const { return m_path; };
74
75     // find the file in the path
76     const char* Find( const char* filename, char* buffer ) const;
77
78     // return the first folder from the path
79     // the returned string is not terminated by '\0'!!!
80     // its length is returned via len parameter
81     const char* First( int& len ) const;
82
83     // return the folder, next in the path after the specified folder.
84     // see also note to First() method
85     const char* Next( const char* folder, int& len ) const;
86
87 protected:
88
89     char* m_path;
90     int m_maxsize;
91     int m_len;
92 };
93
94
95 void CvFilePath::Clear()
96 {
97     delete[] m_path;
98     m_maxsize = m_len = 0;
99 }
100
101
102 CvFilePath::CvFilePath()
103 {
104     m_path = 0;
105     m_maxsize = m_len = 0;
106 }
107
108
109 CvFilePath::~CvFilePath()
110 {
111     Clear();
112 }
113
114
115 bool  CvFilePath::Add( const char* path )
116 {
117     char buffer[_MAX_PATH + 1];
118     int len = Preprocess( path, buffer );
119
120     if( len < 0 )
121         return false;
122
123     if( m_len + len + 3 // +1 for one more ';',
124                         // another +1 for possible additional '/',
125                         // and the last +1 is for '\0'
126                       > m_maxsize )
127     {
128         int new_size = (m_len + len + 3 + 1023) & -1024;
129         char* new_path = new char[new_size];
130
131         if( m_path )
132         {
133             memcpy( new_path, m_path, m_len );
134             delete[] m_path;
135         }
136
137         m_path = new_path;
138         m_maxsize = new_size;
139     }
140
141     m_path[m_len++] = ';';
142     memcpy( m_path + m_len, buffer, len );
143     m_len += len;
144
145     if( m_path[m_len] != '/' )
146         m_path[m_len++] = '/';
147
148     m_path[m_len] = '\0'; // '\0' is not counted in m_len.
149
150     return true;
151 }
152
153
154 const char* CvFilePath::First( int& len ) const
155 {
156     const char* path = (const char*)(m_path ? m_path : "");
157     const char* path_end = path;
158
159     while( *path_end && *path_end != ';' )
160         path_end++;
161
162     len = path_end - path;
163     return path;
164 }
165
166
167 const char* CvFilePath::Next( const char* folder, int& len ) const
168 {
169     if( !folder || folder < m_path || folder >= m_path + m_len )
170         return 0;
171
172     folder = strchr( folder, ';' );
173     if( folder )
174     {
175         const char* folder_end = ++folder;
176         while( *folder_end && *folder_end != ';' )
177             folder_end++;
178
179         len = folder_end - folder;
180     }
181
182     return folder;
183 }
184
185
186 const char* CvFilePath::Find( const char* filename, char* buffer ) const
187 {
188     char path0[_MAX_PATH + 1];
189     int len = Preprocess( filename, path0 );
190     int folder_len = 0;
191     const char* folder = First( folder_len );
192     char* name_only = 0;
193     char* name = path0;
194     FILE* f = 0;
195
196     if( len < 0 )
197         return 0;
198
199     do
200     {
201         if( folder_len + len <= _MAX_PATH )
202         {
203             memcpy( buffer, folder, folder_len );
204             strcpy( buffer + folder_len, name );
205
206             f = fopen( buffer, "rb" );
207             if( f )
208                 break;
209         }
210
211         if( name != name_only )
212         {
213             name_only = strrchr( path0, '/' );
214             if( !name_only )
215                 name_only = path0;
216             else
217                 name_only++;
218             len = strlen( name_only );
219             name = name_only;
220         }
221     }
222     while( (folder = Next( folder, folder_len )) != 0 );
223
224     filename = 0;
225
226     if( f )
227     {
228         filename = (const char*)buffer;
229         fclose(f);
230     }
231
232     return filename;
233 }
234
235
236 int CvFilePath::Preprocess( const char* str, char* buffer )
237 {
238     int i;
239
240     if( !str || !buffer )
241         return -1;
242
243     for( i = 0; i <= _MAX_PATH; i++ )
244     {
245         buffer[i] = str[i];
246
247         if( isalnum(str[i])) // fast check to skip most of characters
248             continue;
249
250         if( str[i] == '\0' )
251             break;
252
253         if( str[i] == '\\' ) // convert back slashes to simple slashes
254                              // (for Win32-*NIX compatibility)
255             buffer[i] = '/';
256
257         if (str[i] == '*' || str[i] == '?' || str[i] == '\"' ||
258             str[i] == '>' || str[i] == '<' ||
259             str[i] == ';' || /* used as a separator in the path */
260         #ifndef WIN32
261             str[i] == ',' || str[i] == '%' ||
262         #endif
263             str[i] == '|')
264             return -1;
265     }
266
267     return i <= _MAX_PATH ? i : -1;
268 }
269 #endif
270
271 /****************************************************************************************\
272 *                              Image Readers & Writers Class                             *
273 \****************************************************************************************/
274
275 class  CvImageFilters
276 {
277 public:
278
279     CvImageFilters();
280     ~CvImageFilters();
281
282     GrFmtReader* FindReader( const char* filename ) const;
283     GrFmtWriter* FindWriter( const char* filename ) const;
284
285     //const CvFilePath& Path() const { return (const CvFilePath&)m_path; };
286     //CvFilePath& Path() { return m_path; };
287
288 protected:
289
290     GrFmtFactoriesList*  m_factories;
291 };
292
293
294 CvImageFilters::CvImageFilters()
295 {
296     m_factories = new GrFmtFactoriesList;
297
298 #ifdef HAVE_IMAGEIO
299     m_factories->AddFactory( new GrFmtImageIO() );
300 #endif
301     m_factories->AddFactory( new GrFmtBmp() );
302     m_factories->AddFactory( new GrFmtJpeg() );
303     m_factories->AddFactory( new GrFmtSunRaster() );
304     m_factories->AddFactory( new GrFmtPxM() );
305     m_factories->AddFactory( new GrFmtTiff() );
306 #ifdef HAVE_PNG
307     m_factories->AddFactory( new GrFmtPng() );
308 #endif
309 #ifdef HAVE_JASPER
310     m_factories->AddFactory( new GrFmtJpeg2000() );
311 #endif
312 #ifdef HAVE_ILMIMF
313     m_factories->AddFactory( new GrFmtExr() );
314 #endif
315 }
316
317
318 CvImageFilters::~CvImageFilters()
319 {
320     delete m_factories;
321 }
322
323
324 GrFmtReader* CvImageFilters::FindReader( const char* filename ) const
325 {
326     return m_factories->FindReader( filename );
327 }
328
329
330 GrFmtWriter* CvImageFilters::FindWriter( const char* filename ) const
331 {
332     return m_factories->FindWriter( filename );
333 }
334
335 /****************************************************************************************\
336 *                         HighGUI loading & saving function implementation               *
337 \****************************************************************************************/
338
339 static int icvSetCXCOREBindings(void)
340 {
341     return CV_SET_IMAGE_IO_FUNCTIONS();
342 }
343
344 int cxcore_bindings_initialized = icvSetCXCOREBindings();
345
346 // global image I/O filters
347 static CvImageFilters  g_Filters;
348
349 #if 0
350 CV_IMPL void
351 cvAddSearchPath( const char* path )
352 {
353     CV_FUNCNAME( "cvAddSearchPath" );
354
355     __BEGIN__;
356
357     if( !path || strlen(path) == 0 )
358         CV_ERROR( CV_StsNullPtr, "Null path" );
359
360     g_Filters.AddPath( path );
361
362     __END__;
363 }
364 #endif
365
366 CV_IMPL int
367 cvHaveImageReader( const char* filename )
368 {
369     GrFmtReader* reader = g_Filters.FindReader( filename );
370     if( reader ) {
371         delete reader;
372         return 1;
373     }
374     return 0;
375 }
376
377 CV_IMPL int cvHaveImageWriter( const char* filename )
378 {
379     GrFmtWriter* writer = g_Filters.FindWriter( filename );
380     if( writer ) {
381         delete writer;
382         return 1;
383     }
384     return 0;
385 }
386
387 static void*
388 icvLoadImage( const char* filename, int flags, bool load_as_matrix )
389 {
390     GrFmtReader* reader = 0;
391     IplImage* image = 0;
392     CvMat hdr, *matrix = 0;
393     int depth = 8;
394
395     CV_FUNCNAME( "cvLoadImage" );
396
397     __BEGIN__;
398
399     CvSize size;
400     int iscolor;
401     int cn;
402
403     if( !filename || strlen(filename) == 0 )
404         CV_ERROR( CV_StsNullPtr, "null filename" );
405
406     reader = g_Filters.FindReader( filename );
407     if( !reader )
408         EXIT;
409
410     if( !reader->ReadHeader() )
411         EXIT;
412
413     size.width = reader->GetWidth();
414     size.height = reader->GetHeight();
415
416     if( flags == -1 )
417         iscolor = reader->IsColor();
418     else
419     {
420         if( (flags & CV_LOAD_IMAGE_COLOR) != 0 ||
421            ((flags & CV_LOAD_IMAGE_ANYCOLOR) != 0 && reader->IsColor()) )
422             iscolor = 1;
423         else
424             iscolor = 0;
425
426         if( (flags & CV_LOAD_IMAGE_ANYDEPTH) != 0 )
427         {
428             reader->UseNativeDepth(true);
429             depth = reader->GetDepth();
430         }
431     }
432
433     cn = iscolor ? 3 : 1;
434
435     if( load_as_matrix )
436     {
437         int type;
438         if(reader->IsFloat() && depth != 8)
439             type = CV_32F;
440         else
441             type = ( depth <= 8 ) ? CV_8U : ( depth <= 16 ) ? CV_16U : CV_32S;
442         CV_CALL( matrix = cvCreateMat( size.height, size.width, CV_MAKETYPE(type, cn) ));
443     }
444     else
445     {
446         int type;
447         if(reader->IsFloat() && depth != 8)
448             type = IPL_DEPTH_32F;
449         else
450             type = ( depth <= 8 ) ? IPL_DEPTH_8U : ( depth <= 16 ) ? IPL_DEPTH_16U : IPL_DEPTH_32S;
451         CV_CALL( image = cvCreateImage( size, type, cn ));
452         matrix = cvGetMat( image, &hdr );
453     }
454
455     if( !reader->ReadData( matrix->data.ptr, matrix->step, iscolor ))
456     {
457         if( load_as_matrix )
458             cvReleaseMat( &matrix );
459         else
460             cvReleaseImage( &image );
461         EXIT;
462     }
463
464     __END__;
465
466     delete reader;
467
468     if( cvGetErrStatus() < 0 )
469     {
470         if( load_as_matrix )
471             cvReleaseMat( &matrix );
472         else
473             cvReleaseImage( &image );
474     }
475
476     return load_as_matrix ? (void*)matrix : (void*)image;
477 }
478
479
480 CV_IMPL IplImage*
481 cvLoadImage( const char* filename, int iscolor )
482 {
483     return (IplImage*)icvLoadImage( filename, iscolor, false );
484 }
485
486 CV_IMPL CvMat*
487 cvLoadImageM( const char* filename, int iscolor )
488 {
489     return (CvMat*)icvLoadImage( filename, iscolor, true );
490 }
491
492
493 CV_IMPL int
494 cvSaveImage( const char* filename, const CvArr* arr )
495 {
496     int origin = 0;
497     GrFmtWriter* writer = 0;
498     CvMat *temp = 0, *temp2 = 0;
499
500     CV_FUNCNAME( "cvSaveImage" );
501
502     __BEGIN__;
503
504     CvMat stub, *image;
505     int channels, ipl_depth;
506
507     if( !filename || strlen(filename) == 0 )
508         CV_ERROR( CV_StsNullPtr, "null filename" );
509
510     CV_CALL( image = cvGetMat( arr, &stub ));
511
512     if( CV_IS_IMAGE( arr ))
513         origin = ((IplImage*)arr)->origin;
514
515     channels = CV_MAT_CN( image->type );
516     if( channels != 1 && channels != 3 && channels != 4 )
517         CV_ERROR( CV_BadNumChannels, "" );
518
519     writer = g_Filters.FindWriter( filename );
520     if( !writer )
521         CV_ERROR( CV_StsError, "could not find a filter for the specified extension" );
522
523     if( origin )
524     {
525         CV_CALL( temp = cvCreateMat(image->rows, image->cols, image->type) );
526         CV_CALL( cvFlip( image, temp, 0 ));
527         image = temp;
528     }
529
530     ipl_depth = cvCvToIplDepth(image->type);
531
532     if( !writer->IsFormatSupported(ipl_depth) )
533     {
534         assert( writer->IsFormatSupported(IPL_DEPTH_8U) );
535         CV_CALL( temp2 = cvCreateMat(image->rows,
536             image->cols, CV_MAKETYPE(CV_8U,channels)) );
537         CV_CALL( cvConvertImage( image, temp2 ));
538         image = temp2;
539         ipl_depth = IPL_DEPTH_8U;
540     }
541
542     if( !writer->WriteImage( image->data.ptr, image->step, image->width,
543                              image->height, ipl_depth, channels ))
544         CV_ERROR( CV_StsError, "could not save the image" );
545
546     __END__;
547
548     delete writer;
549     cvReleaseMat( &temp );
550     cvReleaseMat( &temp2 );
551
552     return cvGetErrStatus() >= 0;
553 }
554
555 /* End of file. */