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