Move the sources to trunk
[opencv] / otherlibs / VlGrFmts / 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 //                        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 #include "grfmt_bmp.h"
43 #include <assert.h>
44 #include <string.h>
45
46 /************************ BMP reader *****************************/
47
48 GrFmtBmpReader::GrFmtBmpReader()
49 {
50     m_sign_len = 2;
51     m_signature ="BM";
52     m_description = "Windows bitmap (*.bmp;*.dib)";
53     m_offset = -1;
54 }
55
56
57 int  GrFmtBmpReader::GetColor()
58 {
59     return m_bpp > 8 ? 1 : -1;
60 }
61
62
63 void  GrFmtBmpReader::Close()
64 {
65     m_strm.Close();
66 }
67
68
69 bool  GrFmtBmpReader::ReadHeader()
70 {
71     bool result = false;
72     
73     assert( strlen(m_filename) != 0 );
74     if( !m_strm.Open( m_filename )) return false;
75
76     try
77     {
78         m_strm.Skip( 10 );
79         m_offset = m_strm.GetDWord();
80
81         int  size = m_strm.GetDWord();
82
83         if( size >= 36 )
84         {
85             m_width  = m_strm.GetDWord();
86             m_height = m_strm.GetDWord();
87             m_bpp    = m_strm.GetDWord() >> 16;
88             m_rle_code = m_strm.GetDWord();
89             m_strm.Skip(12);
90             int clrused = m_strm.GetDWord();
91             m_strm.Skip( size - 36 );
92
93             if( m_width > 0 && m_height > 0 &&
94              (((m_bpp == 1 || m_bpp == 4 || m_bpp == 8 || 
95                 m_bpp == 24 || m_bpp == 32 ) && m_rle_code == 0) || 
96                (m_bpp == 4 && m_rle_code == 2) || (m_bpp == 8 && m_rle_code == 1))) 
97             {
98                 if( m_bpp <= 8 )
99                 {
100                     memset( m_palette, 0, sizeof(m_palette));
101                     m_strm.GetBytes( m_palette, (clrused == 0? 1<<m_bpp : clrused)*4 );
102                 }
103                 result = true;
104             }
105         }
106         else if( size == 12 )
107         {
108             m_width  = m_strm.GetWord();
109             m_height = m_strm.GetWord();
110             m_bpp    = m_strm.GetDWord() >> 16;
111             m_rle_code = 0;
112
113             if( m_width > 0 && m_height > 0 &&
114                (m_bpp == 1 || m_bpp == 4 || m_bpp == 8 ||
115                 m_bpp == 24 || m_bpp == 32 )) 
116             {
117                 if( m_bpp <= 8 )
118                 {
119                     uchar buffer[256*3];
120                     int j, clrused = 1 << m_bpp;
121                     m_strm.GetBytes( buffer, clrused*3 );
122                     for( j = 0; j < clrused; j++ )
123                     {
124                         m_palette[j].b = buffer[3*j+0];
125                         m_palette[j].g = buffer[3*j+1];
126                         m_palette[j].r = buffer[3*j+2];
127                     }
128                 }
129                 result = true;
130             }
131         }
132     }
133     catch( int )
134     {
135     }
136
137     if( !result )
138     {
139         m_offset = -1;
140         m_width = m_height = -1;
141         m_strm.Close();
142     }
143     return result;
144 }
145
146 bool  GrFmtBmpReader::ReadData( uchar* data, int step, int color )
147 {
148     const  int buffer_size = 1 << 12;
149     uchar  buffer[buffer_size];
150     uchar  bgr_buffer[buffer_size];
151     uchar  gray_palette[256];
152     bool   result = false;
153     uchar* src = buffer;
154     uchar* bgr = bgr_buffer;
155     int  src_pitch = ((m_width*m_bpp + 7)/8 + 3) & -4;
156     int  nch = color ? 3 : 1;
157     int  width3 = m_width*nch;
158     int  delta  = -(width3 + step);
159     int  y;
160
161     if( m_offset < 0 || !m_strm.IsOpened())
162         return false;
163     
164     data += (m_height - 1)*step;
165
166     if( m_bpp != 24 )
167     {
168         if( src_pitch+32 > buffer_size ) src = new uchar[src_pitch+32];
169     }
170
171     if( !color )
172     {
173         if( m_bpp <= 8 )
174         {
175             CvtPaletteToGray( m_palette, gray_palette, 1 << m_bpp );
176         }
177         if( m_width*3 + 32 > buffer_size ) bgr = new uchar[m_width*3 + 32];
178     }
179     
180     try
181     {
182         m_strm.SetPos( m_offset );
183         
184         switch( m_bpp )
185         {
186         /************************* 1 BPP ************************/
187         case 1:
188             for( y = 0; y < m_height; y++, data -= step )
189             {
190                 m_strm.GetBytes( src, src_pitch );
191                 FillColorRow1( color ? data : bgr, src, m_width, m_palette );
192                 if( !color ) CvtBGRToGray( bgr, data, m_width );
193             }
194             result = true;
195             break;
196         
197         /************************* 4 BPP ************************/
198         case 4:
199             if( m_rle_code == 0 )
200             {
201                 for( y = 0; y < m_height; y++, data -= step )
202                 {
203                     m_strm.GetBytes( src, src_pitch );
204                     if( color )
205                         FillColorRow4( data, src, m_width, m_palette );
206                     else
207                         FillGrayRow4( data, src, m_width, gray_palette );
208                 }
209                 result = true;
210             }
211             else if( m_rle_code == 2 ) // rle4 compression
212             {
213                 uchar* line_end = data + width3;
214                 y = 0;
215
216                 for(;;)
217                 {
218                     int code = m_strm.GetWord();
219                     int len = code & 255;
220                     code >>= 8;
221                     if( len != 0 ) // encoded mode
222                     {
223                         PaletteEntry clr[2];
224                         int t = 0;
225                         clr[0] = m_palette[code >> 4];
226                         clr[1] = m_palette[code & 15];
227                         uchar* end = data + len*nch;
228                         if( end > line_end ) goto decode_rle4_bad;
229                         do
230                         {
231                             if( color )
232                             {
233                                 WRITE_PIX( data, clr[t] );
234                             }
235                             else
236                             {
237                                 WRITE_PIX( bgr, clr[t] );
238                                 CvtBGRToGray( bgr, data, 1 );
239                             }
240                             t ^= 1;
241                         }
242                         while( (data += nch) < end );
243                     }
244                     else if( code > 2 ) // absolute mode
245                     {
246                         if( data + code*nch > line_end ) goto decode_rle4_bad;
247                         m_strm.GetBytes( src, (((code + 1)>>1) + 1) & -2 );
248                         if( color )
249                             data = FillColorRow4( data, src, code, m_palette );
250                         else
251                             data = FillGrayRow4( data, src, code, gray_palette );
252                     }
253                     else
254                     {
255                         if( code == 0 ) // line end
256                         {
257                             if( data < line_end )
258                             {
259                                 FillUni( data, line_end, width3, delta, 
260                                          line_end - data, 0, m_palette[0], color );
261                             }
262                             data = line_end + delta;
263                             line_end = data + width3;
264                             if( ++y == m_height ) goto decode_rle4_good;
265                         }
266                         else if( code == 1 ) // image end
267                             goto decode_rle4_good;
268                         else // delta
269                         {
270                             int x_shift3 = m_strm.GetByte()*nch;
271                             int y_shift = m_strm.GetByte();
272
273                             if( (y += y_shift) >= m_height ||
274                                 data + x_shift3 > line_end ) goto decode_rle4_bad;
275                             
276                             data = FillUni( data, line_end, width3, delta, 
277                                              x_shift3, y_shift, m_palette[0], color );
278                             line_end -= step*y_shift;
279                         }
280                     }
281                 }
282 decode_rle4_good:
283                 result = true;
284 decode_rle4_bad: ;
285             }
286             break;
287
288         /************************* 8 BPP ************************/
289         case 8:
290             if( m_rle_code == 0 )
291             {
292                 for( y = 0; y < m_height; y++, data -= step )
293                 {
294                     m_strm.GetBytes( src, src_pitch );
295                     if( color )
296                         FillColorRow8( data, src, m_width, m_palette );
297                     else
298                         FillGrayRow8( data, src, m_width, gray_palette );
299                 }
300                 result = true;
301             }
302             else if( m_rle_code == 1 ) // rle8 compression
303             {
304                 uchar* line_end = data + width3;
305                 y = 0;
306
307                 for(;;)
308                 {
309                     int code = m_strm.GetWord();
310                     int len = code & 255;
311                     code >>= 8;
312                     if( len != 0 ) // encoded mode
313                     {
314                         len *= nch;
315                         if( data + len > line_end ) goto decode_rle8_bad;
316                         data = FillUni( data, line_end, width3, delta, 
317                                          len, 0, m_palette[code], color );
318                     }
319                     else if( code > 2 ) // absolute mode
320                     {
321                         int code3 = code*nch;
322                         if( data + code3 > line_end ) goto decode_rle8_bad;
323                         m_strm.GetBytes( src, (code + 1) & -2 );
324                         if( color )
325                             data = FillColorRow8( data, src, code, m_palette );
326                         else
327                             data = FillGrayRow8( data, src, code, gray_palette );
328                     }
329                     else
330                     {
331                         if( code == 0 ) // line end
332                         {
333                             if( data < line_end )
334                             {
335                                 FillUni( data, line_end, width3, delta, 
336                                           line_end - data, 0, m_palette[0], color );
337                             }
338                             data = line_end + delta;
339                             line_end = data + width3;
340                             if( ++y == m_height ) goto decode_rle8_good;
341                         }
342                         else if( code == 1 ) // image end
343                             goto decode_rle8_good;
344                         else // delta
345                         {
346                             int x_shift3 = m_strm.GetByte()*nch;
347                             int y_shift = m_strm.GetByte();
348
349                             if( (y += y_shift) >= m_height ||
350                                 data + x_shift3 > line_end ) goto decode_rle8_bad;
351
352                             data = FillUni( data, line_end, width3, delta, 
353                                              x_shift3, y_shift, m_palette[0], color );
354                             line_end -= step*y_shift;
355                         }
356                     }
357                 }
358 decode_rle8_good:
359                 result = true;
360 decode_rle8_bad: ;
361             }
362             break;
363         /************************* 24 BPP ************************/
364         case 24:
365             for( y = 0; y < m_height; y++, data -= step )
366             {
367                 m_strm.GetBytes( color ? data : bgr, src_pitch );
368                 if( !color ) CvtBGRToGray( bgr, data, m_width );
369             }
370             result = true;
371             break;
372         /************************* 32 BPP ************************/
373         case 32:
374             for( y = 0; y < m_height; y++, data -= step )
375             {
376                 m_strm.GetBytes( src, src_pitch );
377                 FillRow32( color ? data : bgr, src, m_width );
378                 if( !color ) CvtBGRToGray( bgr, data, m_width );
379             }
380             result = true;
381             break;
382         default:
383             assert(0);
384         }
385     }
386     catch( int )
387     {
388     }
389
390     if( src != buffer ) delete src; 
391     if( bgr != bgr_buffer ) delete bgr;
392     return true;
393 }
394
395
396 /************************ Sun Raster reader *****************************/
397
398 GrFmtSunRasterReader::GrFmtSunRasterReader()
399 {
400     m_sign_len = 4;
401     m_signature ="\x59\xA6\x6A\x95";
402     m_description = "Sun raster files (*.sr)";
403     m_offset = -1;
404 }
405
406
407 void  GrFmtSunRasterReader::Close()
408 {
409     m_strm.Close();
410 }
411
412
413 bool  GrFmtSunRasterReader::ReadHeader()
414 {
415     bool result = false;
416     
417     assert( strlen(m_filename) != 0 );
418     if( !m_strm.Open( m_filename )) return false;
419
420     try
421     {
422         m_strm.Skip( 4 );
423         m_width  = m_strm.GetDWord();
424         m_height = m_strm.GetDWord();
425         m_bpp    = m_strm.GetDWord();
426         int palSize = 3*(1 << m_bpp);
427
428         m_strm.Skip( 4 );
429         m_type   = (SunRasType)m_strm.GetDWord();
430         m_maptype = (SunRasMapType)m_strm.GetDWord();
431         m_maplength = m_strm.GetDWord();
432
433         if( m_width > 0 && m_height > 0 &&
434             (m_bpp == 1 || m_bpp == 8 || m_bpp == 24 || m_bpp == 32) &&
435             (m_type == RT_OLD || m_type == RT_STANDARD ||
436              (m_type == RT_BYTE_ENCODED && m_bpp == 8) || m_type == RT_FORMAT_RGB) &&
437             (m_maptype == RMT_NONE && m_maplength == 0 ||
438              m_maptype == RMT_EQUAL_RGB && m_maplength == palSize && m_bpp <= 8))
439         {
440             if( m_maplength != 0 )
441             {
442                 int readed;
443                 uchar buffer[256*3];
444
445                 m_strm.GetBytes( buffer, palSize, &readed );
446                 if( readed == palSize )
447                 {
448                     int i;
449                     palSize /= 3;
450
451                     for( i = 0; i < palSize; i++ )
452                     {
453                         m_palette[i].b = buffer[i*3 + 2];
454                         m_palette[i].g = buffer[i*3 + 1];
455                         m_palette[i].r = buffer[i*3];
456                         m_palette[i].a = 0;
457                     }
458
459                     m_offset = m_strm.GetPos();
460
461                     assert( m_offset == 32 + m_maplength );
462                     result = true;
463                 }
464             }
465             else
466             {
467                 if( m_bpp <= 8 )
468                     FillGrayPalette( m_palette, m_bpp );
469
470                 m_offset = m_strm.GetPos();
471
472                 assert( m_offset == 32 + m_maplength );
473                 result = true;
474             }
475         }
476     }
477     catch( int )
478     {
479     }
480
481     if( !result )
482     {
483         m_offset = -1;
484         m_width = m_height = -1;
485         m_strm.Close();
486     }
487     return result;
488 }
489
490
491 int  GrFmtSunRasterReader::GetColor()
492 {
493     return m_bpp > 8 || m_maptype == RMT_EQUAL_RGB ? 1 : 0;
494 }
495
496
497 bool  GrFmtSunRasterReader::ReadData( uchar* data, int step, int color )
498 {
499     const  int buffer_size = 1 << 12;
500     uchar  buffer[buffer_size];
501     uchar  bgr_buffer[buffer_size];
502     uchar  gray_palette[256];
503     bool   result = false;
504     uchar* src = buffer;
505     uchar* bgr = bgr_buffer;
506     int  src_pitch = ((m_width*m_bpp + 7)/8 + 3) & -4;
507     int  nch = color ? 3 : 1;
508     int  width3 = m_width*nch;
509     int  delta = step - width3;
510     int  y;
511
512     if( m_offset < 0 || !m_strm.IsOpened())
513         return false;
514     
515     if( src_pitch+32 > buffer_size )
516         src = new uchar[src_pitch+32];
517
518     if( m_width*3 + 32 > buffer_size )
519         bgr = new uchar[m_width*3 + 32];
520
521     if( !color && m_maptype == RMT_EQUAL_RGB )
522         CvtPaletteToGray( m_palette, gray_palette, 1 << m_bpp );
523
524     try
525     {
526         m_strm.SetPos( m_offset );
527         
528         switch( m_bpp )
529         {
530         /************************* 1 BPP ************************/
531         case 1:
532             for( y = 0; y < m_height; y++, data += step )
533             {
534                 m_strm.GetBytes( src, src_pitch );
535                 FillColorRow1( color ? data : bgr, src, m_width, m_palette );
536                 if( !color ) CvtBGRToGray( bgr, data, m_width );
537             }
538             result = true;
539             break;
540         /************************* 8 BPP ************************/
541         case 8:
542             if( m_type != RT_BYTE_ENCODED )
543             {
544                 for( y = 0; y < m_height; y++, data += step )
545                 {
546                     m_strm.GetBytes( src, src_pitch );
547                     if( color )
548                         FillColorRow8( data, src, m_width, m_palette );
549                     else
550                         FillGrayRow8( data, src, m_width, gray_palette );
551                 }
552                 result = true;
553             }
554             else // RLE-encoded
555             {
556                 uchar* line_end = data + width3;
557                 y = 0;
558
559                 for(;;)
560                 {
561                     int max_count = line_end - data;
562                     int code = 0, len = 0, len1;
563                     uchar* tsrc = src;
564
565                     do
566                     {
567                         code = m_strm.GetByte();
568                         if( code == 0x80 )
569                         {
570                             len = m_strm.GetByte();
571                             if( len != 0 ) break;
572                         }
573                         *tsrc++ = (uchar)code;
574                     }
575                     while( (max_count -= nch) > 0 );
576
577                     len1 = tsrc - src;
578
579                     if( len1 > 0 )
580                     {
581                         if( color )
582                             FillColorRow8( data, src, len1, m_palette );
583                         else
584                             FillGrayRow8( data, src, len1, gray_palette );
585                         data += len1*nch;
586                     }
587
588                     if( len > 0 ) // encoded mode
589                     {
590                         int y_shift = 0;
591                         len = (len + 1)*nch;
592                         code = m_strm.GetByte();
593
594                         CalcShifts( data, line_end, width3, y, m_height, len, y_shift );
595
596                         data = FillUni( data, line_end, width3, delta,
597                                         len, y_shift, m_palette[code], color );
598                         y += y_shift;
599                         line_end += y_shift*step;
600                     }
601
602                     if( data == line_end )
603                     {
604                         data += delta;
605                         line_end += step;
606                         if( ++y >= m_height ) break;
607                     }
608                 }
609
610                 result = true;
611             }
612             break;
613         /************************* 24 BPP ************************/
614         case 24:
615             for( y = 0; y < m_height; y++, data += step )
616             {
617                 m_strm.GetBytes( color ? data : bgr, src_pitch );
618
619                 if( color )
620                 {
621                     if( m_type == RT_FORMAT_RGB )
622                         CvtRGBToBGR( data, data, m_width );
623                 }
624                 else
625                 {
626                     if( m_type == RT_FORMAT_RGB )
627                         CvtRGBToGray( bgr, data, m_width );
628                     else
629                         CvtBGRToGray( bgr, data, m_width );
630                 }
631             }
632             result = true;
633             break;
634         /************************* 32 BPP ************************/
635         case 32:
636             for( y = 0; y < m_height; y++, data += step )
637             {
638                 /* hack: a0 b0 g0 r0 a1 b1 g1 r1 ... are written to src + 3,
639                    so when we look at src + 4, we see b0 g0 r0 x b1 g1 g1 x ... */
640                 m_strm.GetBytes( src + 3, src_pitch );
641                 FillRow32( color ? data : bgr, src + 4, m_width );
642                 
643                 if( color )
644                 {
645                     if( m_type == RT_FORMAT_RGB )
646                         CvtRGBToBGR( data, data, m_width );
647                 }
648                 else
649                 {
650                     if( m_type == RT_FORMAT_RGB )
651                         CvtRGBToGray( bgr, data, m_width );
652                     else
653                         CvtBGRToGray( bgr, data, m_width );
654                 }
655             }
656             result = true;
657             break;
658         default:
659             assert(0);
660         }
661     }
662     catch( int )
663     {
664     }
665
666     if( src != buffer ) delete src; 
667     if( bgr != bgr_buffer ) delete bgr;
668
669     return true;
670 }