1 /******************************************************************************
2  *
3  * Purpose:  Implementation of the CPixelInterleavedChannel class.
4  *
5  ******************************************************************************
6  * Copyright (c) 2009
7  * PCI Geomatics, 90 Allstate Parkway, Markham, Ontario, Canada.
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a
10  * copy of this software and associated documentation files (the "Software"),
11  * to deal in the Software without restriction, including without limitation
12  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13  * and/or sell copies of the Software, and to permit persons to whom the
14  * Software is furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be included
17  * in all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25  * DEALINGS IN THE SOFTWARE.
26  ****************************************************************************/
27 
28 #include "pcidsk_exception.h"
29 #include "core/pcidsk_utils.h"
30 #include "core/cpcidskfile.h"
31 #include "channel/cpixelinterleavedchannel.h"
32 #include <cassert>
33 #include <cstring>
34 
35 using namespace PCIDSK;
36 
37 /************************************************************************/
38 /*                      CPixelInterleavedChannel()                      */
39 /************************************************************************/
40 
CPixelInterleavedChannel(PCIDSKBuffer & image_headerIn,uint64 ih_offsetIn,CPL_UNUSED PCIDSKBuffer & file_headerIn,int channelnumIn,CPCIDSKFile * fileIn,int image_offsetIn,eChanType pixel_typeIn)41 CPixelInterleavedChannel::CPixelInterleavedChannel( PCIDSKBuffer &image_headerIn,
42                                                     uint64 ih_offsetIn,
43                                                     CPL_UNUSED PCIDSKBuffer &file_headerIn,
44                                                     int channelnumIn,
45                                                     CPCIDSKFile *fileIn,
46                                                     int image_offsetIn,
47                                                     eChanType pixel_typeIn )
48         : CPCIDSKChannel( image_headerIn, ih_offsetIn, fileIn, pixel_typeIn, channelnumIn)
49 
50 {
51     this->image_offset = image_offsetIn;
52 }
53 
54 /************************************************************************/
55 /*                     ~CPixelInterleavedChannel()                      */
56 /************************************************************************/
57 
~CPixelInterleavedChannel()58 CPixelInterleavedChannel::~CPixelInterleavedChannel()
59 
60 {
61 }
62 
63 /************************************************************************/
64 /*                             ReadBlock()                              */
65 /************************************************************************/
66 
ReadBlock(int block_index,void * buffer,int win_xoff,int win_yoff,int win_xsize,int win_ysize)67 int CPixelInterleavedChannel::ReadBlock( int block_index, void *buffer,
68                                          int win_xoff, int win_yoff,
69                                          int win_xsize, int win_ysize )
70 
71 {
72 /* -------------------------------------------------------------------- */
73 /*      Default window if needed.                                       */
74 /* -------------------------------------------------------------------- */
75     if( win_xoff == -1 && win_yoff == -1 && win_xsize == -1 && win_ysize == -1 )
76     {
77         win_xoff = 0;
78         win_yoff = 0;
79         win_xsize = GetBlockWidth();
80         win_ysize = GetBlockHeight();
81     }
82 
83 /* -------------------------------------------------------------------- */
84 /*      Validate Window                                                 */
85 /* -------------------------------------------------------------------- */
86     if( win_xoff < 0 || win_xoff + win_xsize > GetBlockWidth()
87         || win_yoff < 0 || win_yoff + win_ysize > GetBlockHeight() )
88     {
89         return ThrowPCIDSKException(0,
90             "Invalid window in ReadBloc(): win_xoff=%d,win_yoff=%d,xsize=%d,ysize=%d",
91             win_xoff, win_yoff, win_xsize, win_ysize );
92     }
93 
94 /* -------------------------------------------------------------------- */
95 /*      Work out sizes and offsets.                                     */
96 /* -------------------------------------------------------------------- */
97     int pixel_group = file->GetPixelGroupSize();
98     int pixel_size = DataTypeSize(GetType());
99 
100 /* -------------------------------------------------------------------- */
101 /*      Read and lock the scanline.                                     */
102 /* -------------------------------------------------------------------- */
103     uint8 *pixel_buffer = (uint8 *)
104         file->ReadAndLockBlock( block_index, win_xoff, win_xsize);
105 
106 /* -------------------------------------------------------------------- */
107 /*      Copy the data into our callers buffer.  Try to do this          */
108 /*      reasonably efficiently.  We might consider adding faster        */
109 /*      cases for 16/32bit data that is word aligned.                   */
110 /* -------------------------------------------------------------------- */
111     if( pixel_size == pixel_group )
112         memcpy( buffer, pixel_buffer, pixel_size * win_xsize );
113     else
114     {
115         int i;
116         uint8  *src = ((uint8 *)pixel_buffer) + image_offset;
117         uint8  *dst = (uint8 *) buffer;
118 
119         if( pixel_size == 1 )
120         {
121             for( i = win_xsize; i != 0; i-- )
122             {
123                 *dst = *src;
124                 dst++;
125                 src += pixel_group;
126             }
127         }
128         else if( pixel_size == 2 )
129         {
130             for( i = win_xsize; i != 0; i-- )
131             {
132                 *(dst++) = *(src++);
133                 *(dst++) = *(src++);
134                 src += pixel_group-2;
135             }
136         }
137         else if( pixel_size == 4 )
138         {
139             for( i = win_xsize; i != 0; i-- )
140             {
141                 *(dst++) = *(src++);
142                 *(dst++) = *(src++);
143                 *(dst++) = *(src++);
144                 *(dst++) = *(src++);
145                 src += pixel_group-4;
146             }
147         }
148         else if( pixel_size == 8 )
149         {
150             for( i = win_xsize; i != 0; i-- )
151             {
152                 *(dst++) = *(src++);
153                 *(dst++) = *(src++);
154                 *(dst++) = *(src++);
155                 *(dst++) = *(src++);
156                 *(dst++) = *(src++);
157                 *(dst++) = *(src++);
158                 *(dst++) = *(src++);
159                 *(dst++) = *(src++);
160                 src += pixel_group-8;
161             }
162         }
163         else
164             return ThrowPCIDSKException(0, "Unsupported pixel type..." );
165     }
166 
167     file->UnlockBlock( false );
168 
169 /* -------------------------------------------------------------------- */
170 /*      Do byte swapping if needed.                                     */
171 /* -------------------------------------------------------------------- */
172     if( needs_swap )
173         SwapPixels( buffer, pixel_type, win_xsize );
174 
175     return 1;
176 }
177 
178 /************************************************************************/
179 /*                             CopyPixels()                             */
180 /************************************************************************/
181 
182 template <typename T>
CopyPixels(const T * const src,T * const dst,std::size_t offset,std::size_t count)183 void CopyPixels(const T* const src, T* const dst,
184                 std::size_t offset, std::size_t count)
185 {
186     for (std::size_t i = 0; i < count; i++)
187     {
188         dst[i] = src[(i + 1) * offset];
189     }
190 }
191 
192 /************************************************************************/
193 /*                             WriteBlock()                             */
194 /************************************************************************/
195 
WriteBlock(int block_index,void * buffer)196 int CPixelInterleavedChannel::WriteBlock( int block_index, void *buffer )
197 
198 {
199     if( !file->GetUpdatable() )
200         return ThrowPCIDSKException(0, "File not open for update in WriteBlock()" );
201 
202     InvalidateOverviews();
203 
204 /* -------------------------------------------------------------------- */
205 /*      Work out sizes and offsets.                                     */
206 /* -------------------------------------------------------------------- */
207     int pixel_group = file->GetPixelGroupSize();
208     int pixel_size = DataTypeSize(GetType());
209 
210 /* -------------------------------------------------------------------- */
211 /*      Read and lock the scanline.                                     */
212 /* -------------------------------------------------------------------- */
213     uint8 *pixel_buffer = (uint8 *) file->ReadAndLockBlock( block_index );
214 
215 /* -------------------------------------------------------------------- */
216 /*      Copy the data into our callers buffer.  Try to do this          */
217 /*      reasonably efficiently.  We might consider adding faster        */
218 /*      cases for 16/32bit data that is word aligned.                   */
219 /* -------------------------------------------------------------------- */
220     if( pixel_size == pixel_group )
221     {
222         memcpy( pixel_buffer, buffer, pixel_size * width );
223 
224         if( needs_swap )
225         {
226             bool complex = IsDataTypeComplex( GetType() );
227 
228             if( complex )
229                 SwapData( pixel_buffer, pixel_size/2, width*2 );
230             else
231                 SwapData( pixel_buffer, pixel_size, width );
232         }
233     }
234     else
235     {
236         int i;
237         uint8  *dst = ((uint8 *)pixel_buffer) + image_offset;
238         uint8  *src = (uint8 *) buffer;
239 
240         if( pixel_size == 1 )
241         {
242             for( i = width; i != 0; i-- )
243             {
244                 *dst = *src;
245                 src++;
246                 dst += pixel_group;
247             }
248         }
249         else if( pixel_size == 2 )
250         {
251             for( i = width; i != 0; i-- )
252             {
253                 *(dst++) = *(src++);
254                 *(dst++) = *(src++);
255 
256                 if( needs_swap )
257                     SwapData( dst-2, 2, 1 );
258 
259                 dst += pixel_group-2;
260             }
261         }
262         else if( pixel_size == 4 )
263         {
264             bool complex = IsDataTypeComplex( GetType() );
265 
266             for( i = width; i != 0; i-- )
267             {
268                 *(dst++) = *(src++);
269                 *(dst++) = *(src++);
270                 *(dst++) = *(src++);
271                 *(dst++) = *(src++);
272 
273                 if( needs_swap )
274                 {
275                     if( complex )
276                         SwapData( dst-4, 2, 2);
277                     else
278                         SwapData( dst-4, 4, 1);
279                 }
280 
281                 dst += pixel_group-4;
282             }
283         }
284         else if( pixel_size == 8 )
285         {
286             bool complex = IsDataTypeComplex( GetType() );
287 
288             for( i = width; i != 0; i-- )
289             {
290                 *(dst++) = *(src++);
291                 *(dst++) = *(src++);
292                 *(dst++) = *(src++);
293                 *(dst++) = *(src++);
294                 *(dst++) = *(src++);
295                 *(dst++) = *(src++);
296                 *(dst++) = *(src++);
297                 *(dst++) = *(src++);
298 
299                 if( needs_swap )
300                 {
301                     if( complex )
302                         SwapData( dst-8, 4, 2);
303                     else
304                         SwapData( dst-8, 8, 1);
305                 }
306 
307                 dst += pixel_group-8;
308             }
309         }
310         else
311             return ThrowPCIDSKException(0, "Unsupported pixel type..." );
312     }
313 
314     file->UnlockBlock( true );
315 
316     return 1;
317 }
318