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
54class  CvFilePath
55{
56public:
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
87protected:
88
89    char* m_path;
90    int m_maxsize;
91    int m_len;
92};
93
94
95void CvFilePath::Clear()
96{
97    delete[] m_path;
98    m_maxsize = m_len = 0;
99}
100
101
102CvFilePath::CvFilePath()
103{
104    m_path = 0;
105    m_maxsize = m_len = 0;
106}
107
108
109CvFilePath::~CvFilePath()
110{
111    Clear();
112}
113
114
115bool  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
154const 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
167const 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
186const 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
236int 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
275class  CvImageFilters
276{
277public:
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
288protected:
289
290    GrFmtFactoriesList*  m_factories;
291};
292
293
294CvImageFilters::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
318CvImageFilters::~CvImageFilters()
319{
320    delete m_factories;
321}
322
323
324GrFmtReader* CvImageFilters::FindReader( const char* filename ) const
325{
326    return m_factories->FindReader( filename );
327}
328
329
330GrFmtWriter* CvImageFilters::FindWriter( const char* filename ) const
331{
332    return m_factories->FindWriter( filename );
333}
334
335/****************************************************************************************\
336*                         HighGUI loading & saving function implementation               *
337\****************************************************************************************/
338
339static int icvSetCXCOREBindings(void)
340{
341    return CV_SET_IMAGE_IO_FUNCTIONS();
342}
343
344int cxcore_bindings_initialized = icvSetCXCOREBindings();
345
346// global image I/O filters
347static CvImageFilters  g_Filters;
348
349#if 0
350CV_IMPL void
351cvAddSearchPath( 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
366CV_IMPL int
367cvHaveImageReader( 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
377CV_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
387static void*
388icvLoadImage( 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
480CV_IMPL IplImage*
481cvLoadImage( const char* filename, int iscolor )
482{
483    return (IplImage*)icvLoadImage( filename, iscolor, false );
484}
485
486CV_IMPL CvMat*
487cvLoadImageM( const char* filename, int iscolor )
488{
489    return (CvMat*)icvLoadImage( filename, iscolor, true );
490}
491
492
493CV_IMPL int
494cvSaveImage( 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. */
556