708098683b0b3de4bcdacef95b7edaa67a4fd605
[opencv] / src / 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 #undef min
49 #undef max
50
51 /****************************************************************************************\
52 *                                      Image Codecs                                      *
53 \****************************************************************************************/
54 namespace cv
55 {
56
57 static vector<ImageDecoder> decoders;
58 static vector<ImageEncoder> encoders;
59
60 ImageDecoder findDecoder( const string& filename )
61 {
62     size_t i, maxlen = 0;
63     for( i = 0; i < decoders.size(); i++ )
64     {
65         size_t len = decoders[i]->signatureLength();
66         maxlen = std::max(maxlen, len);
67     }
68
69     FILE* f= fopen( filename.c_str(), "rb" );
70     if( !f )
71         return ImageDecoder();
72     string signature(maxlen, ' ');
73     maxlen = fread( &signature[0], 1, maxlen, f );
74     fclose(f);
75     signature = signature.substr(0, maxlen);
76
77     for( i = 0; i < decoders.size(); i++ )
78     {
79         if( decoders[i]->checkSignature(signature) )
80             return decoders[i]->newDecoder();
81     }
82
83     return ImageDecoder();
84 }
85
86 ImageDecoder findDecoder( const Mat& buf )
87 {
88     size_t i, maxlen = 0;
89
90     if( buf.rows*buf.cols < 1 || !buf.isContinuous() )
91         return ImageDecoder();
92
93     for( i = 0; i < decoders.size(); i++ )
94     {
95         size_t len = decoders[i]->signatureLength();
96         maxlen = std::max(maxlen, len);
97     }
98
99     size_t bufSize = buf.rows*buf.cols*buf.elemSize();
100     maxlen = std::min(maxlen, bufSize);
101     string signature(maxlen, ' ');
102     memcpy( &signature[0], buf.data, maxlen );
103
104     for( i = 0; i < decoders.size(); i++ )
105     {
106         if( decoders[i]->checkSignature(signature) )
107             return decoders[i]->newDecoder();
108     }
109
110     return ImageDecoder();
111 }
112
113 ImageEncoder findEncoder( const string& _ext )
114 {
115     if( _ext.size() <= 1 )
116         return ImageEncoder();
117
118     const char* ext = strrchr( _ext.c_str(), '.' );
119     if( !ext )
120         return ImageEncoder();
121     int len = 0;
122     for( ext++; isalnum(ext[len]) && len < 128; len++ )
123         ;
124
125     for( size_t i = 0; i < encoders.size(); i++ )
126     {
127         string description = encoders[i]->getDescription();
128         const char* descr = strchr( description.c_str(), '(' );
129
130         while( descr )
131         {
132             descr = strchr( descr + 1, '.' );
133             if( !descr )
134                 break;
135             int j = 0;
136             for( descr++; isalnum(descr[j]) && j < len; j++ )
137             {
138                 int c1 = tolower(ext[j]);
139                 int c2 = tolower(descr[j]);
140                 if( c1 != c2 )
141                     break;
142             }
143             if( j == len && !isalnum(descr[j]))
144                 return encoders[i]->newEncoder();
145             descr += j;
146         }
147     }
148
149     return ImageEncoder();
150 }
151
152 struct ImageCodecInitializer
153 {
154     ImageCodecInitializer()
155     {
156         decoders.push_back( new BmpDecoder );
157         encoders.push_back( new BmpEncoder );
158     #ifdef HAVE_JPEG
159         decoders.push_back( new JpegDecoder );
160         encoders.push_back( new JpegEncoder );
161     #endif
162         decoders.push_back( new SunRasterDecoder );
163         encoders.push_back( new SunRasterEncoder );
164         decoders.push_back( new PxMDecoder );
165         encoders.push_back( new PxMEncoder );
166     #ifdef HAVE_TIFF
167         decoders.push_back( new TiffDecoder );
168     #endif
169         encoders.push_back( new TiffEncoder );
170     #ifdef HAVE_PNG
171         decoders.push_back( new PngDecoder );
172         encoders.push_back( new PngEncoder );
173     #endif
174     #ifdef HAVE_JASPER
175         decoders.push_back( new Jpeg2KDecoder );
176         encoders.push_back( new Jpeg2KEncoder );
177     #endif
178     #ifdef HAVE_ILMIMF
179         decoders.push_back( new ExrDecoder );
180         encoders.push_back( new ExrEncoder );
181     #endif
182     // because it is a generic image I/O API, supporting many formats,
183     // it should be last in the list.
184     #ifdef HAVE_IMAGEIO
185         decoders.push_back( new ImageIODecoder );
186         encoders.push_back( new ImageIOEncoder );
187     #endif
188     }
189 };
190
191 static ImageCodecInitializer initialize_codecs;
192
193
194 enum { LOAD_CVMAT=0, LOAD_IMAGE=1, LOAD_MAT=2 };
195
196 static void*
197 imread_( const string& filename, int flags, int hdrtype, Mat* mat=0 )
198 {
199     IplImage* image = 0;
200     CvMat *matrix = 0;
201     Mat temp, *data = &temp;
202
203     ImageDecoder decoder = findDecoder(filename);
204     if( decoder.empty() )
205         return 0;
206     decoder->setSource(filename);
207     if( !decoder->readHeader() )
208         return 0;
209
210     CvSize size;
211     size.width = decoder->width();
212     size.height = decoder->height();
213
214     int type = decoder->type();
215     if( flags != -1 )
216     {
217         if( (flags & CV_LOAD_IMAGE_ANYDEPTH) == 0 )
218             type = CV_MAKETYPE(CV_8U, CV_MAT_CN(type));
219
220         if( (flags & CV_LOAD_IMAGE_COLOR) != 0 ||
221            ((flags & CV_LOAD_IMAGE_ANYCOLOR) != 0 && CV_MAT_CN(type) > 1) )
222             type = CV_MAKETYPE(CV_MAT_DEPTH(type), 3);
223         else
224             type = CV_MAKETYPE(CV_MAT_DEPTH(type), 1);
225     }
226
227     if( hdrtype == LOAD_CVMAT || hdrtype == LOAD_MAT )
228     {
229         if( hdrtype == LOAD_CVMAT )
230         {
231             matrix = cvCreateMat( size.height, size.width, type );
232             temp = cvarrToMat(matrix);
233         }
234         else
235         {
236             mat->create( size.height, size.width, type );
237             data = mat;
238         }
239     }
240     else
241     {
242         image = cvCreateImage( size, cvIplDepth(type), CV_MAT_CN(type) );
243         temp = cvarrToMat(image);
244     }
245
246     if( !decoder->readData( *data ))
247     {
248         cvReleaseImage( &image );
249         cvReleaseMat( &matrix );
250         if( mat )
251             mat->release();
252         return 0;
253     }
254
255     return hdrtype == LOAD_CVMAT ? (void*)matrix :
256         hdrtype == LOAD_IMAGE ? (void*)image : (void*)mat;
257 }
258
259 Mat imread( const string& filename, int flags )
260 {
261     Mat img;
262     imread_( filename, flags, LOAD_MAT, &img );
263     return img;
264 }
265
266 static bool imwrite_( const string& filename, const Mat& image,
267                       const vector<int>& params, bool flipv )
268 {
269     Mat temp;
270     const Mat* pimage = &image;
271
272     CV_Assert( image.channels() == 1 || image.channels() == 3 || image.channels() == 4 );
273
274     ImageEncoder encoder = findEncoder( filename );
275     if( encoder.empty() )
276         CV_Error( CV_StsError, "could not find a writer for the specified extension" );
277
278     if( !encoder->isFormatSupported(image.depth()) )
279     {
280         CV_Assert( encoder->isFormatSupported(CV_8U) );
281         image.convertTo( temp, CV_8U );
282         pimage = &temp;
283     }
284
285     if( flipv )
286     {
287         flip(*pimage, temp, 0);
288         pimage = &temp;
289     }
290
291     encoder->setDestination( filename );
292     bool code = encoder->write( *pimage, params );
293
294     CV_Assert( code );
295     return code;
296 }
297
298 bool imwrite( const string& filename, const Mat& img,
299               const vector<int>& params )
300 {
301     return imwrite_(filename, img, params, false);
302 }
303
304 static void*
305 imdecode_( const Mat& buf, int flags, int hdrtype, Mat* mat=0 )
306 {
307     CV_Assert(buf.data && buf.isContinuous());
308     IplImage* image = 0;
309     CvMat *matrix = 0;
310     Mat temp, *data = &temp;
311     char fnamebuf[L_tmpnam];
312     const char* filename = 0;
313
314     ImageDecoder decoder = findDecoder(buf);
315     if( decoder.empty() )
316         return 0;
317
318     if( !decoder->setSource(buf) )
319     {
320         filename = tmpnam(fnamebuf);
321         FILE* f = fopen( filename, "wb" );
322         if( !f )
323             return 0;
324         size_t bufSize = buf.cols*buf.rows*buf.elemSize();
325         fwrite( &buf.data, 1, bufSize, f );
326         fclose(f);
327         decoder->setSource(filename);
328     }
329
330     if( !decoder->readHeader() )
331     {
332         if( filename )
333             unlink(filename);
334         return 0;
335     }
336
337     CvSize size;
338     size.width = decoder->width();
339     size.height = decoder->height();
340
341     int type = decoder->type();
342     if( flags != -1 )
343     {
344         if( (flags & CV_LOAD_IMAGE_ANYDEPTH) == 0 )
345             type = CV_MAKETYPE(CV_8U, CV_MAT_CN(type));
346
347         if( (flags & CV_LOAD_IMAGE_COLOR) != 0 ||
348            ((flags & CV_LOAD_IMAGE_ANYCOLOR) != 0 && CV_MAT_CN(type) > 1) )
349             type = CV_MAKETYPE(CV_MAT_DEPTH(type), 3);
350         else
351             type = CV_MAKETYPE(CV_MAT_DEPTH(type), 1);
352     }
353
354     if( hdrtype == LOAD_CVMAT || hdrtype == LOAD_MAT )
355     {
356         if( hdrtype == LOAD_CVMAT )
357         {
358             matrix = cvCreateMat( size.height, size.width, type );
359             temp = cvarrToMat(matrix);
360         }
361         else
362         {
363             mat->create( size.height, size.width, type );
364             data = mat;
365         }
366     }
367     else
368     {
369         image = cvCreateImage( size, cvIplDepth(type), CV_MAT_CN(type) );
370         temp = cvarrToMat(image);
371     }
372
373     bool code = decoder->readData( *data );
374     if( filename )
375         unlink(filename);
376
377     if( !code )
378     {
379         cvReleaseImage( &image );
380         cvReleaseMat( &matrix );
381         if( mat )
382             mat->release();
383         return 0;
384     }
385
386     return hdrtype == LOAD_CVMAT ? (void*)matrix :
387         hdrtype == LOAD_IMAGE ? (void*)image : (void*)mat;
388 }
389
390
391 Mat imdecode( const Mat& buf, int flags )
392 {
393     Mat img;
394     imdecode_( buf, flags, LOAD_MAT, &img );
395     return img;
396 }
397     
398 bool imencode( const string& ext, const Mat& image,
399                vector<uchar>& buf, const vector<int>& params )
400 {
401     Mat temp;
402     const Mat* pimage = &image;
403
404     int channels = image.channels();
405     CV_Assert( channels == 1 || channels == 3 || channels == 4 );
406
407     ImageEncoder encoder = findEncoder( ext );
408     if( encoder.empty() )
409         CV_Error( CV_StsError, "could not find encoder for the specified extension" );
410
411     if( !encoder->isFormatSupported(image.depth()) )
412     {
413         CV_Assert( encoder->isFormatSupported(CV_8U) );
414         image.convertTo(temp, CV_8U);
415         pimage = &temp;
416     }
417
418     bool code;
419     if( encoder->setDestination(buf) )
420     {
421         code = encoder->write(image, params);
422         CV_Assert( code );
423     }
424     else
425     {
426         char fnamebuf[L_tmpnam];
427         const char* filename = tmpnam(fnamebuf);
428         code = encoder->setDestination(filename);
429         CV_Assert( code );
430         code = encoder->write(image, params);
431         CV_Assert( code );
432         FILE* f = fopen( filename, "rb" );
433         CV_Assert(f != 0);
434         fseek( f, 0, SEEK_END );
435         long pos = ftell(f);
436         buf.resize((size_t)pos);
437         fseek( f, 0, SEEK_SET );
438         buf.resize(fread( &buf[0], 1, buf.size(), f ));
439         fclose(f);
440         unlink(filename);
441     }
442     return code;
443 }
444
445 }
446
447 /****************************************************************************************\
448 *                         HighGUI loading & saving function implementation               *
449 \****************************************************************************************/
450
451 static int icvSetCXCOREBindings(void)
452 {
453     return CV_SET_IMAGE_IO_FUNCTIONS();
454 }
455
456 int cxcore_bindings_initialized = icvSetCXCOREBindings();
457
458 CV_IMPL int
459 cvHaveImageReader( const char* filename )
460 {
461     cv::ImageDecoder decoder = cv::findDecoder(filename);
462     return !decoder.empty();
463 }
464
465 CV_IMPL int cvHaveImageWriter( const char* filename )
466 {
467     cv::ImageEncoder encoder = cv::findEncoder(filename);
468     return !encoder.empty();
469 }
470
471 CV_IMPL IplImage*
472 cvLoadImage( const char* filename, int iscolor )
473 {
474     return (IplImage*)cv::imread_(filename, iscolor, cv::LOAD_IMAGE );
475 }
476
477 CV_IMPL CvMat*
478 cvLoadImageM( const char* filename, int iscolor )
479 {
480     return (CvMat*)cv::imread_( filename, iscolor, cv::LOAD_CVMAT );
481 }
482
483 CV_IMPL int
484 cvSaveImage( const char* filename, const CvArr* arr, const int* _params )
485 {
486     int i = 0;
487     if( _params )
488     {
489         for( ; _params[i] > 0; i += 2 )
490             ;
491     }
492     return cv::imwrite_(filename, cv::cvarrToMat(arr),
493         i > 0 ? cv::vector<int>(_params, _params+i) : cv::vector<int>(),
494         CV_IS_IMAGE(arr) && ((const IplImage*)arr)->origin == IPL_ORIGIN_BL );
495 }
496
497 /* decode image stored in the buffer */
498 CV_IMPL IplImage*
499 cvDecodeImage( const CvMat* _buf, int iscolor )
500 {
501     CV_Assert( _buf && CV_IS_MAT_CONT(_buf->type) );
502     cv::Mat buf(1, _buf->rows*_buf->cols*CV_ELEM_SIZE(_buf->type), CV_8U, _buf->data.ptr);
503     return (IplImage*)cv::imdecode_(buf, iscolor, cv::LOAD_IMAGE );
504 }
505
506 CV_IMPL CvMat*
507 cvDecodeImageM( const CvMat* _buf, int iscolor )
508 {
509     CV_Assert( _buf && CV_IS_MAT_CONT(_buf->type) );
510     cv::Mat buf(1, _buf->rows*_buf->cols*CV_ELEM_SIZE(_buf->type), CV_8U, _buf->data.ptr);
511     return (CvMat*)cv::imdecode_(buf, iscolor, cv::LOAD_CVMAT );
512 }
513
514 CV_IMPL CvMat*
515 cvEncodeImage( const char* ext, const CvArr* arr, const int* _params )
516 {
517     int i = 0;
518     if( _params )
519     {
520         for( ; _params[i] > 0; i += 2 )
521             ;
522     }
523     cv::Mat img = cv::cvarrToMat(arr);
524     if( CV_IS_IMAGE(arr) && ((const IplImage*)arr)->origin == IPL_ORIGIN_BL )
525     {
526         cv::Mat temp;
527         cv::flip(img, temp, 0);
528         img = temp;
529     }
530     cv::vector<uchar> buf;
531
532     bool code = cv::imencode(ext, img, buf,
533         i > 0 ? std::vector<int>(_params, _params+i) : std::vector<int>() );
534     if( !code )
535         return 0;
536     CvMat* _buf = cvCreateMat(1, (int)buf.size(), CV_8U);
537     memcpy( _buf->data.ptr, &buf[0], buf.size() );
538
539     return _buf;
540 }
541
542 /* End of file. */