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_sunras.hpp"
45 
46 #ifdef HAVE_IMGCODEC_SUNRASTER
47 
48 namespace cv
49 {
50 
51 static const char* fmtSignSunRas = "\x59\xA6\x6A\x95";
52 
53 /************************ Sun Raster reader *****************************/
54 
SunRasterDecoder()55 SunRasterDecoder::SunRasterDecoder()
56 {
57     m_offset = -1;
58     m_signature = fmtSignSunRas;
59     m_bpp = 0;
60     m_encoding = RAS_STANDARD;
61     m_maptype = RMT_NONE;
62     m_maplength = 0;
63 }
64 
65 
~SunRasterDecoder()66 SunRasterDecoder::~SunRasterDecoder()
67 {
68 }
69 
newDecoder() const70 ImageDecoder SunRasterDecoder::newDecoder() const
71 {
72     return makePtr<SunRasterDecoder>();
73 }
74 
close()75 void  SunRasterDecoder::close()
76 {
77     m_strm.close();
78 }
79 
80 
readHeader()81 bool  SunRasterDecoder::readHeader()
82 {
83     bool result = false;
84 
85     if( !m_strm.open( m_filename )) return false;
86 
87     try
88     {
89         m_strm.skip( 4 );
90         m_width  = m_strm.getDWord();
91         m_height = m_strm.getDWord();
92         m_bpp    = m_strm.getDWord();
93         int palSize = (m_bpp > 0 && m_bpp <= 8) ? (3*(1 << m_bpp)) : 0;
94 
95         m_strm.skip( 4 );
96         m_encoding = (SunRasType)m_strm.getDWord();
97         m_maptype = (SunRasMapType)m_strm.getDWord();
98         m_maplength = m_strm.getDWord();
99 
100         if( m_width > 0 && m_height > 0 &&
101             (m_bpp == 1 || m_bpp == 8 || m_bpp == 24 || m_bpp == 32) &&
102             (m_encoding == RAS_OLD || m_encoding == RAS_STANDARD ||
103              (m_type == RAS_BYTE_ENCODED && m_bpp == 8) || m_type == RAS_FORMAT_RGB) &&
104             ((m_maptype == RMT_NONE && m_maplength == 0) ||
105              (m_maptype == RMT_EQUAL_RGB && m_maplength <= palSize && m_maplength > 0 && m_bpp <= 8)))
106         {
107             memset( m_palette, 0, sizeof(m_palette));
108 
109             if( m_maplength != 0 )
110             {
111                 uchar buffer[256*3];
112 
113                 if( m_strm.getBytes( buffer, m_maplength ) == m_maplength )
114                 {
115                     int i;
116                     palSize = m_maplength/3;
117 
118                     for( i = 0; i < palSize; i++ )
119                     {
120                         m_palette[i].b = buffer[i + 2*palSize];
121                         m_palette[i].g = buffer[i + palSize];
122                         m_palette[i].r = buffer[i];
123                         m_palette[i].a = 0;
124                     }
125 
126                     m_type = IsColorPalette( m_palette, m_bpp ) ? CV_8UC3 : CV_8UC1;
127                     m_offset = m_strm.getPos();
128 
129                     CV_Assert(m_offset == 32 + m_maplength);
130                     result = true;
131                 }
132             }
133             else
134             {
135                 m_type = m_bpp > 8 ? CV_8UC3 : CV_8UC1;
136 
137                 if( CV_MAT_CN(m_type) == 1 )
138                     FillGrayPalette( m_palette, m_bpp );
139 
140                 m_offset = m_strm.getPos();
141 
142                 CV_Assert(m_offset == 32 + m_maplength);
143                 result = true;
144             }
145         }
146     }
147     catch(...)
148     {
149     }
150 
151     if( !result )
152     {
153         m_offset = -1;
154         m_width = m_height = -1;
155         m_strm.close();
156     }
157     return result;
158 }
159 
160 
readData(Mat & img)161 bool  SunRasterDecoder::readData( Mat& img )
162 {
163     bool color = img.channels() > 1;
164     uchar* data = img.ptr();
165     size_t step = img.step;
166     uchar  gray_palette[256] = {0};
167     bool   result = false;
168     int  src_pitch = ((m_width*m_bpp + 7)/8 + 1) & -2;
169     int  nch = color ? 3 : 1;
170     int  width3 = m_width*nch;
171     int  y;
172 
173     if( m_offset < 0 || !m_strm.isOpened())
174         return false;
175 
176     AutoBuffer<uchar> _src(src_pitch + 32);
177     uchar* src = _src.data();
178 
179     if( !color && m_maptype == RMT_EQUAL_RGB )
180         CvtPaletteToGray( m_palette, gray_palette, 1 << m_bpp );
181 
182     try
183     {
184         m_strm.setPos( m_offset );
185 
186         switch( m_bpp )
187         {
188         /************************* 1 BPP ************************/
189         case 1:
190             if( m_type != RAS_BYTE_ENCODED )
191             {
192                 for( y = 0; y < m_height; y++, data += step )
193                 {
194                     m_strm.getBytes( src, src_pitch );
195                     if( color )
196                         FillColorRow1( data, src, m_width, m_palette );
197                     else
198                         FillGrayRow1( data, src, m_width, gray_palette );
199                 }
200                 result = true;
201             }
202             else
203             {
204                 uchar* line_end = src + (m_width*m_bpp + 7)/8;
205                 uchar* tsrc = src;
206                 y = 0;
207 
208                 for(;;)
209                 {
210                     int max_count = (int)(line_end - tsrc);
211                     int code = 0, len = 0, len1 = 0;
212 
213                     do
214                     {
215                         code = m_strm.getByte();
216                         if( code == 0x80 )
217                         {
218                             len = m_strm.getByte();
219                             if( len != 0 ) break;
220                         }
221                         tsrc[len1] = (uchar)code;
222                     }
223                     while( ++len1 < max_count );
224 
225                     tsrc += len1;
226 
227                     if( len > 0 ) // encoded mode
228                     {
229                         ++len;
230                         code = m_strm.getByte();
231                         if( len > line_end - tsrc )
232                         {
233                             CV_Error(Error::StsInternal, "");
234                             goto bad_decoding_1bpp;
235                         }
236 
237                         memset( tsrc, code, len );
238                         tsrc += len;
239                     }
240 
241                     if( tsrc >= line_end )
242                     {
243                         tsrc = src;
244                         if( color )
245                             FillColorRow1( data, src, m_width, m_palette );
246                         else
247                             FillGrayRow1( data, src, m_width, gray_palette );
248                         data += step;
249                         if( ++y >= m_height ) break;
250                     }
251                 }
252                 result = true;
253 bad_decoding_1bpp:
254                 ;
255             }
256             break;
257         /************************* 8 BPP ************************/
258         case 8:
259             if( m_type != RAS_BYTE_ENCODED )
260             {
261                 for( y = 0; y < m_height; y++, data += step )
262                 {
263                     m_strm.getBytes( src, src_pitch );
264                     if( color )
265                         FillColorRow8( data, src, m_width, m_palette );
266                     else
267                         FillGrayRow8( data, src, m_width, gray_palette );
268                 }
269                 result = true;
270             }
271             else // RLE-encoded
272             {
273                 uchar* line_end = data + width3;
274                 y = 0;
275 
276                 for(;;)
277                 {
278                     int max_count = (int)(line_end - data);
279                     int code = 0, len = 0, len1;
280                     uchar* tsrc = src;
281 
282                     do
283                     {
284                         code = m_strm.getByte();
285                         if( code == 0x80 )
286                         {
287                             len = m_strm.getByte();
288                             if( len != 0 ) break;
289                         }
290                         *tsrc++ = (uchar)code;
291                     }
292                     while( (max_count -= nch) > 0 );
293 
294                     len1 = (int)(tsrc - src);
295 
296                     if( len1 > 0 )
297                     {
298                         if( color )
299                             FillColorRow8( data, src, len1, m_palette );
300                         else
301                             FillGrayRow8( data, src, len1, gray_palette );
302                         data += len1*nch;
303                     }
304 
305                     if( len > 0 ) // encoded mode
306                     {
307                         len = (len + 1)*nch;
308                         code = m_strm.getByte();
309 
310                         if( color )
311                             data = FillUniColor( data, line_end, validateToInt(step), width3,
312                                                  y, m_height, len,
313                                                  m_palette[code] );
314                         else
315                             data = FillUniGray( data, line_end, validateToInt(step), width3,
316                                                 y, m_height, len,
317                                                 gray_palette[code] );
318                         if( y >= m_height )
319                             break;
320                     }
321 
322                     if( data == line_end )
323                     {
324                         if( m_strm.getByte() != 0 )
325                             goto bad_decoding_end;
326                         line_end += step;
327                         data = line_end - width3;
328                         if( ++y >= m_height ) break;
329                     }
330                 }
331 
332                 result = true;
333 bad_decoding_end:
334                 ;
335             }
336             break;
337         /************************* 24 BPP ************************/
338         case 24:
339             for( y = 0; y < m_height; y++, data += step )
340             {
341                 m_strm.getBytes(src, src_pitch );
342 
343                 if( color )
344                 {
345                     if( m_type == RAS_FORMAT_RGB )
346                         icvCvt_RGB2BGR_8u_C3R(src, 0, data, 0, Size(m_width,1) );
347                     else
348                         memcpy(data, src, std::min(step, (size_t)src_pitch));
349                 }
350                 else
351                 {
352                     icvCvt_BGR2Gray_8u_C3C1R(src, 0, data, 0, Size(m_width,1),
353                                               m_type == RAS_FORMAT_RGB ? 2 : 0 );
354                 }
355             }
356             result = true;
357             break;
358         /************************* 32 BPP ************************/
359         case 32:
360             for( y = 0; y < m_height; y++, data += step )
361             {
362                 /* hack: a0 b0 g0 r0 a1 b1 g1 r1 ... are written to src + 3,
363                    so when we look at src + 4, we see b0 g0 r0 x b1 g1 g1 x ... */
364                 m_strm.getBytes( src + 3, src_pitch );
365 
366                 if( color )
367                     icvCvt_BGRA2BGR_8u_C4C3R( src + 4, 0, data, 0, Size(m_width,1),
368                                               m_type == RAS_FORMAT_RGB ? 2 : 0 );
369                 else
370                     icvCvt_BGRA2Gray_8u_C4C1R( src + 4, 0, data, 0, Size(m_width,1),
371                                                m_type == RAS_FORMAT_RGB ? 2 : 0 );
372             }
373             result = true;
374             break;
375         default:
376             CV_Error(Error::StsInternal, "");
377         }
378     }
379     catch( ... )
380     {
381     }
382 
383     return result;
384 }
385 
386 
387 //////////////////////////////////////////////////////////////////////////////////////////
388 
SunRasterEncoder()389 SunRasterEncoder::SunRasterEncoder()
390 {
391     m_description = "Sun raster files (*.sr;*.ras)";
392 }
393 
394 
newEncoder() const395 ImageEncoder SunRasterEncoder::newEncoder() const
396 {
397     return makePtr<SunRasterEncoder>();
398 }
399 
~SunRasterEncoder()400 SunRasterEncoder::~SunRasterEncoder()
401 {
402 }
403 
write(const Mat & img,const std::vector<int> &)404 bool  SunRasterEncoder::write( const Mat& img, const std::vector<int>& )
405 {
406     bool result = false;
407     int y, width = img.cols, height = img.rows, channels = img.channels();
408     int fileStep = (width*channels + 1) & -2;
409     WMByteStream  strm;
410 
411     if( strm.open(m_filename) )
412     {
413         strm.putBytes( fmtSignSunRas, (int)strlen(fmtSignSunRas) );
414         strm.putDWord( width );
415         strm.putDWord( height );
416         strm.putDWord( channels*8 );
417         strm.putDWord( fileStep*height );
418         strm.putDWord( RAS_STANDARD );
419         strm.putDWord( RMT_NONE );
420         strm.putDWord( 0 );
421 
422         for( y = 0; y < height; y++ )
423             strm.putBytes( img.ptr(y), fileStep );
424 
425         strm.close();
426         result = true;
427     }
428     return result;
429 }
430 
431 }
432 
433 #endif // HAVE_IMGCODEC_SUNRASTER
434