Fix CVEs for opencv 2.4
[platform/upstream/opencv.git] / modules / highgui / src / grfmt_bmp.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 //                           License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14 // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
15 // Third party copyrights are property of their respective owners.
16 //
17 // Redistribution and use in source and binary forms, with or without modification,
18 // are permitted provided that the following conditions are met:
19 //
20 //   * Redistribution's of source code must retain the above copyright notice,
21 //     this list of conditions and the following disclaimer.
22 //
23 //   * Redistribution's in binary form must reproduce the above copyright notice,
24 //     this list of conditions and the following disclaimer in the documentation
25 //     and/or other materials provided with the distribution.
26 //
27 //   * The name of the copyright holders may not be used to endorse or promote products
28 //     derived from this software without specific prior written permission.
29 //
30 // This software is provided by the copyright holders and contributors "as is" and
31 // any express or implied warranties, including, but not limited to, the implied
32 // warranties of merchantability and fitness for a particular purpose are disclaimed.
33 // In no event shall the Intel Corporation or contributors be liable for any direct,
34 // indirect, incidental, special, exemplary, or consequential damages
35 // (including, but not limited to, procurement of substitute goods or services;
36 // loss of use, data, or profits; or business interruption) however caused
37 // and on any theory of liability, whether in contract, strict liability,
38 // or tort (including negligence or otherwise) arising in any way out of
39 // the use of this software, even if advised of the possibility of such damage.
40 //
41 //M*/
42
43 #include "precomp.hpp"
44 #include "grfmt_bmp.hpp"
45
46 namespace cv
47 {
48
49 static const char* fmtSignBmp = "BM";
50
51 /************************ BMP decoder *****************************/
52
53 BmpDecoder::BmpDecoder()
54 {
55     m_signature = fmtSignBmp;
56     m_offset = -1;
57     m_buf_supported = true;
58 }
59
60
61 BmpDecoder::~BmpDecoder()
62 {
63 }
64
65
66 void  BmpDecoder::close()
67 {
68     m_strm.close();
69 }
70
71 ImageDecoder BmpDecoder::newDecoder() const
72 {
73     return new BmpDecoder;
74 }
75
76 bool  BmpDecoder::readHeader()
77 {
78     bool result = false;
79     bool iscolor = false;
80
81     if( !m_buf.empty() )
82     {
83         if( !m_strm.open( m_buf ) )
84             return false;
85     }
86     else if( !m_strm.open( m_filename ))
87         return false;
88
89     try
90     {
91         m_strm.skip( 10 );
92         m_offset = m_strm.getDWord();
93
94         int  size = m_strm.getDWord();
95
96         if( size >= 36 )
97         {
98             m_width  = m_strm.getDWord();
99             m_height = m_strm.getDWord();
100             m_bpp    = m_strm.getDWord() >> 16;
101             m_rle_code = (BmpCompression)m_strm.getDWord();
102             m_strm.skip(12);
103             int clrused = m_strm.getDWord();
104             m_strm.skip( size - 36 );
105
106             if( m_width > 0 && m_height != 0 &&
107              (((m_bpp == 1 || m_bpp == 4 || m_bpp == 8 ||
108                 m_bpp == 24 || m_bpp == 32 ) && m_rle_code == BMP_RGB) ||
109                (m_bpp == 16 && (m_rle_code == BMP_RGB || m_rle_code == BMP_BITFIELDS)) ||
110                (m_bpp == 4 && m_rle_code == BMP_RLE4) ||
111                (m_bpp == 8 && m_rle_code == BMP_RLE8)))
112             {
113                 iscolor = true;
114                 result = true;
115
116                 if( m_bpp <= 8 )
117                 {
118                     CV_Assert(clrused < 256);
119                     memset(m_palette, 0, sizeof(m_palette));
120                     m_strm.getBytes(m_palette, (clrused == 0? 1<<m_bpp : clrused)*4 );
121                     iscolor = IsColorPalette( m_palette, m_bpp );
122                 }
123                 else if( m_bpp == 16 && m_rle_code == BMP_BITFIELDS )
124                 {
125                     int redmask = m_strm.getDWord();
126                     int greenmask = m_strm.getDWord();
127                     int bluemask = m_strm.getDWord();
128
129                     if( bluemask == 0x1f && greenmask == 0x3e0 && redmask == 0x7c00 )
130                         m_bpp = 15;
131                     else if( bluemask == 0x1f && greenmask == 0x7e0 && redmask == 0xf800 )
132                         ;
133                     else
134                         result = false;
135                 }
136                 else if( m_bpp == 16 && m_rle_code == BMP_RGB )
137                     m_bpp = 15;
138             }
139         }
140         else if( size == 12 )
141         {
142             m_width  = m_strm.getWord();
143             m_height = m_strm.getWord();
144             m_bpp    = m_strm.getDWord() >> 16;
145             m_rle_code = BMP_RGB;
146
147             if( m_width > 0 && m_height != 0 &&
148                (m_bpp == 1 || m_bpp == 4 || m_bpp == 8 ||
149                 m_bpp == 24 || m_bpp == 32 ))
150             {
151                 if( m_bpp <= 8 )
152                 {
153                     uchar buffer[256*3];
154                     int j, clrused = 1 << m_bpp;
155                     m_strm.getBytes( buffer, clrused*3 );
156                     for( j = 0; j < clrused; j++ )
157                     {
158                         m_palette[j].b = buffer[3*j+0];
159                         m_palette[j].g = buffer[3*j+1];
160                         m_palette[j].r = buffer[3*j+2];
161                     }
162                 }
163                 result = true;
164             }
165         }
166     }
167     catch(...)
168     {
169     }
170
171     m_type = iscolor ? CV_8UC3 : CV_8UC1;
172     m_origin = m_height > 0 ? IPL_ORIGIN_BL : IPL_ORIGIN_TL;
173     m_height = std::abs(m_height);
174
175     if( !result )
176     {
177         m_offset = -1;
178         m_width = m_height = -1;
179         m_strm.close();
180     }
181     return result;
182 }
183
184
185 bool  BmpDecoder::readData( Mat& img )
186 {
187     uchar* data = img.data;
188     int step = (int)img.step;
189     bool color = img.channels() > 1;
190     uchar  gray_palette[256];
191     bool   result = false;
192     int  src_pitch = ((m_width*(m_bpp != 15 ? m_bpp : 16) + 7)/8 + 3) & -4;
193     int  nch = color ? 3 : 1;
194     int  y, width3 = m_width*nch;
195
196     if( m_offset < 0 || !m_strm.isOpened())
197         return false;
198
199     if( m_origin == IPL_ORIGIN_BL )
200     {
201         data += (m_height - 1)*step;
202         step = -step;
203     }
204
205     AutoBuffer<uchar> _src, _bgr;
206     _src.allocate(src_pitch + 32);
207
208     if( !color )
209     {
210         if( m_bpp <= 8 )
211         {
212             CvtPaletteToGray( m_palette, gray_palette, 1 << m_bpp );
213         }
214         _bgr.allocate(m_width*3 + 32);
215     }
216     uchar *src = _src, *bgr = _bgr;
217
218     try
219     {
220         m_strm.setPos( m_offset );
221
222         switch( m_bpp )
223         {
224         /************************* 1 BPP ************************/
225         case 1:
226             for( y = 0; y < m_height; y++, data += step )
227             {
228                 m_strm.getBytes( src, src_pitch );
229                 FillColorRow1( color ? data : bgr, src, m_width, m_palette );
230                 if( !color )
231                     icvCvt_BGR2Gray_8u_C3C1R( bgr, 0, data, 0, cvSize(m_width,1) );
232             }
233             result = true;
234             break;
235
236         /************************* 4 BPP ************************/
237         case 4:
238             if( m_rle_code == BMP_RGB )
239             {
240                 for( y = 0; y < m_height; y++, data += step )
241                 {
242                     m_strm.getBytes( src, src_pitch );
243                     if( color )
244                         FillColorRow4( data, src, m_width, m_palette );
245                     else
246                         FillGrayRow4( data, src, m_width, gray_palette );
247                 }
248                 result = true;
249             }
250             else if( m_rle_code == BMP_RLE4 ) // rle4 compression
251             {
252                 uchar* line_end = data + width3;
253                 y = 0;
254
255                 for(;;)
256                 {
257                     int code = m_strm.getWord();
258                     int len = code & 255;
259                     code >>= 8;
260                     if( len != 0 ) // encoded mode
261                     {
262                         PaletteEntry clr[2];
263                         uchar gray_clr[2];
264                         int t = 0;
265
266                         clr[0] = m_palette[code >> 4];
267                         clr[1] = m_palette[code & 15];
268                         gray_clr[0] = gray_palette[code >> 4];
269                         gray_clr[1] = gray_palette[code & 15];
270
271                         uchar* end = data + len*nch;
272                         if( end > line_end ) goto decode_rle4_bad;
273                         do
274                         {
275                             if( color )
276                                 WRITE_PIX( data, clr[t] );
277                             else
278                                 *data = gray_clr[t];
279                             t ^= 1;
280                         }
281                         while( (data += nch) < end );
282                     }
283                     else if( code > 2 ) // absolute mode
284                     {
285                         if( data + code*nch > line_end ) goto decode_rle4_bad;
286                         int sz = (((code + 1)>>1) + 1) & (~1);
287                         CV_Assert((size_t)sz < _src.getSize());
288                         m_strm.getBytes(src, sz);
289                         if( color )
290                             data = FillColorRow4( data, src, code, m_palette );
291                         else
292                             data = FillGrayRow4( data, src, code, gray_palette );
293                     }
294                     else
295                     {
296                         int x_shift3 = (int)(line_end - data);
297                         int y_shift = m_height - y;
298
299                         if( code == 2 )
300                         {
301                             x_shift3 = m_strm.getByte()*nch;
302                             y_shift = m_strm.getByte();
303                         }
304
305                         len = x_shift3 + ((y_shift * width3) & ((code == 0) - 1));
306
307                         if( color )
308                             data = FillUniColor( data, line_end, step, width3,
309                                                  y, m_height, x_shift3,
310                                                  m_palette[0] );
311                         else
312                             data = FillUniGray( data, line_end, step, width3,
313                                                 y, m_height, x_shift3,
314                                                 gray_palette[0] );
315
316                         if( y >= m_height )
317                             break;
318                     }
319                 }
320
321                 result = true;
322 decode_rle4_bad: ;
323             }
324             break;
325
326         /************************* 8 BPP ************************/
327         case 8:
328             if( m_rle_code == BMP_RGB )
329             {
330                 for( y = 0; y < m_height; y++, data += step )
331                 {
332                     m_strm.getBytes( src, src_pitch );
333                     if( color )
334                         FillColorRow8( data, src, m_width, m_palette );
335                     else
336                         FillGrayRow8( data, src, m_width, gray_palette );
337                 }
338                 result = true;
339             }
340             else if( m_rle_code == BMP_RLE8 ) // rle8 compression
341             {
342                 uchar* line_end = data + width3;
343                 int line_end_flag = 0;
344                 y = 0;
345
346                 for(;;)
347                 {
348                     int code = m_strm.getWord();
349                     int len = code & 255;
350                     code >>= 8;
351                     if( len != 0 ) // encoded mode
352                     {
353                         int prev_y = y;
354                         len *= nch;
355
356                         if( data + len > line_end )
357                             goto decode_rle8_bad;
358
359                         if( color )
360                             data = FillUniColor( data, line_end, step, width3,
361                                                  y, m_height, len,
362                                                  m_palette[code] );
363                         else
364                             data = FillUniGray( data, line_end, step, width3,
365                                                 y, m_height, len,
366                                                 gray_palette[code] );
367
368                         line_end_flag = y - prev_y;
369                     }
370                     else if( code > 2 ) // absolute mode
371                     {
372                         int prev_y = y;
373                         int code3 = code*nch;
374
375                         if( data + code3 > line_end )
376                             goto decode_rle8_bad;
377                         int sz = (code + 1) & (~1);
378                         CV_Assert((size_t)sz < _src.getSize());
379                         m_strm.getBytes(src, sz);
380                         if( color )
381                             data = FillColorRow8( data, src, code, m_palette );
382                         else
383                             data = FillGrayRow8( data, src, code, gray_palette );
384
385                         line_end_flag = y - prev_y;
386                     }
387                     else
388                     {
389                         int x_shift3 = (int)(line_end - data);
390                         int y_shift = m_height - y;
391
392                         if( code || !line_end_flag || x_shift3 < width3 )
393                         {
394                             if( code == 2 )
395                             {
396                                 x_shift3 = m_strm.getByte()*nch;
397                                 y_shift = m_strm.getByte();
398                             }
399
400                             x_shift3 += (y_shift * width3) & ((code == 0) - 1);
401
402                             if( y >= m_height )
403                                 break;
404
405                             if( color )
406                                 data = FillUniColor( data, line_end, step, width3,
407                                                      y, m_height, x_shift3,
408                                                      m_palette[0] );
409                             else
410                                 data = FillUniGray( data, line_end, step, width3,
411                                                     y, m_height, x_shift3,
412                                                     gray_palette[0] );
413
414                             if( y >= m_height )
415                                 break;
416                         }
417
418                         line_end_flag = 0;
419                         if( y >= m_height )
420                             break;
421                     }
422                 }
423
424                 result = true;
425 decode_rle8_bad: ;
426             }
427             break;
428         /************************* 15 BPP ************************/
429         case 15:
430             for( y = 0; y < m_height; y++, data += step )
431             {
432                 m_strm.getBytes( src, src_pitch );
433                 if( !color )
434                     icvCvt_BGR5552Gray_8u_C2C1R( src, 0, data, 0, cvSize(m_width,1) );
435                 else
436                     icvCvt_BGR5552BGR_8u_C2C3R( src, 0, data, 0, cvSize(m_width,1) );
437             }
438             result = true;
439             break;
440         /************************* 16 BPP ************************/
441         case 16:
442             for( y = 0; y < m_height; y++, data += step )
443             {
444                 m_strm.getBytes( src, src_pitch );
445                 if( !color )
446                     icvCvt_BGR5652Gray_8u_C2C1R( src, 0, data, 0, cvSize(m_width,1) );
447                 else
448                     icvCvt_BGR5652BGR_8u_C2C3R( src, 0, data, 0, cvSize(m_width,1) );
449             }
450             result = true;
451             break;
452         /************************* 24 BPP ************************/
453         case 24:
454             for( y = 0; y < m_height; y++, data += step )
455             {
456                 m_strm.getBytes( src, src_pitch );
457                 if(!color)
458                     icvCvt_BGR2Gray_8u_C3C1R( src, 0, data, 0, cvSize(m_width,1) );
459                 else
460                     memcpy( data, src, m_width*3 );
461             }
462             result = true;
463             break;
464         /************************* 32 BPP ************************/
465         case 32:
466             for( y = 0; y < m_height; y++, data += step )
467             {
468                 m_strm.getBytes( src, src_pitch );
469
470                 if( !color )
471                     icvCvt_BGRA2Gray_8u_C4C1R( src, 0, data, 0, cvSize(m_width,1) );
472                 else
473                     icvCvt_BGRA2BGR_8u_C4C3R( src, 0, data, 0, cvSize(m_width,1) );
474             }
475             result = true;
476             break;
477         default:
478             assert(0);
479         }
480     }
481     catch(...)
482     {
483     }
484
485     return result;
486 }
487
488
489 //////////////////////////////////////////////////////////////////////////////////////////
490
491 BmpEncoder::BmpEncoder()
492 {
493     m_description = "Windows bitmap (*.bmp;*.dib)";
494     m_buf_supported = true;
495 }
496
497
498 BmpEncoder::~BmpEncoder()
499 {
500 }
501
502 ImageEncoder BmpEncoder::newEncoder() const
503 {
504     return new BmpEncoder;
505 }
506
507 bool  BmpEncoder::write( const Mat& img, const vector<int>& )
508 {
509     int width = img.cols, height = img.rows, channels = img.channels();
510     int fileStep = (width*channels + 3) & -4;
511     uchar zeropad[] = "\0\0\0\0";
512     WLByteStream strm;
513
514     if( m_buf )
515     {
516         if( !strm.open( *m_buf ) )
517             return false;
518     }
519     else if( !strm.open( m_filename ))
520         return false;
521
522     int  bitmapHeaderSize = 40;
523     int  paletteSize = channels > 1 ? 0 : 1024;
524     int  headerSize = 14 /* fileheader */ + bitmapHeaderSize + paletteSize;
525     int  fileSize = fileStep*height + headerSize;
526     PaletteEntry palette[256];
527
528     if( m_buf )
529         m_buf->reserve( alignSize(fileSize + 16, 256) );
530
531     // write signature 'BM'
532     strm.putBytes( fmtSignBmp, (int)strlen(fmtSignBmp) );
533
534     // write file header
535     strm.putDWord( fileSize ); // file size
536     strm.putDWord( 0 );
537     strm.putDWord( headerSize );
538
539     // write bitmap header
540     strm.putDWord( bitmapHeaderSize );
541     strm.putDWord( width );
542     strm.putDWord( height );
543     strm.putWord( 1 );
544     strm.putWord( channels << 3 );
545     strm.putDWord( BMP_RGB );
546     strm.putDWord( 0 );
547     strm.putDWord( 0 );
548     strm.putDWord( 0 );
549     strm.putDWord( 0 );
550     strm.putDWord( 0 );
551
552     if( channels == 1 )
553     {
554         FillGrayPalette( palette, 8 );
555         strm.putBytes( palette, sizeof(palette));
556     }
557
558     width *= channels;
559     for( int y = height - 1; y >= 0; y-- )
560     {
561         strm.putBytes( img.data + img.step*y, width );
562         if( fileStep > width )
563             strm.putBytes( zeropad, fileStep - width );
564     }
565
566     strm.close();
567     return true;
568 }
569
570 }