1 /******************************************************************************
2  *
3  * Purpose:  Implementation of the CPixelInterleavedChannel class.
4  *
5  ******************************************************************************
6  * Copyright (c) 2009
7  * PCI Geomatics, 50 West Wilmot Street, Richmond Hill, Ont, 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 #include "cpl_port.h"
36 
37 using namespace PCIDSK;
38 
39 /************************************************************************/
40 /*                      CPixelInterleavedChannel()                      */
41 /************************************************************************/
42 
CPixelInterleavedChannel(PCIDSKBuffer & image_header,uint64 ih_offset,CPL_UNUSED PCIDSKBuffer & file_header,int channelnum,CPCIDSKFile * file,int image_offset,eChanType pixel_type)43 CPixelInterleavedChannel::CPixelInterleavedChannel( PCIDSKBuffer &image_header,
44                                                     uint64 ih_offset,
45                                                     CPL_UNUSED PCIDSKBuffer &file_header,
46                                                     int channelnum,
47                                                     CPCIDSKFile *file,
48                                                     int image_offset,
49                                                     eChanType pixel_type )
50         : CPCIDSKChannel( image_header, ih_offset, file, pixel_type, channelnum)
51 
52 {
53     this->image_offset = image_offset;
54 }
55 
56 /************************************************************************/
57 /*                     ~CPixelInterleavedChannel()                      */
58 /************************************************************************/
59 
~CPixelInterleavedChannel()60 CPixelInterleavedChannel::~CPixelInterleavedChannel()
61 
62 {
63 }
64 
65 /************************************************************************/
66 /*                             ReadBlock()                              */
67 /************************************************************************/
68 
ReadBlock(int block_index,void * buffer,int win_xoff,int win_yoff,int win_xsize,int win_ysize)69 int CPixelInterleavedChannel::ReadBlock( int block_index, void *buffer,
70                                          int win_xoff, int win_yoff,
71                                          int win_xsize, int win_ysize )
72 
73 {
74 /* -------------------------------------------------------------------- */
75 /*      Default window if needed.                                       */
76 /* -------------------------------------------------------------------- */
77     if( win_xoff == -1 && win_yoff == -1 && win_xsize == -1 && win_ysize == -1 )
78     {
79         win_xoff = 0;
80         win_yoff = 0;
81         win_xsize = GetBlockWidth();
82         win_ysize = GetBlockHeight();
83     }
84 
85 /* -------------------------------------------------------------------- */
86 /*      Validate Window                                                 */
87 /* -------------------------------------------------------------------- */
88     if( win_xoff < 0 || win_xoff + win_xsize > GetBlockWidth()
89         || win_yoff < 0 || win_yoff + win_ysize > GetBlockHeight() )
90     {
91         ThrowPCIDSKException(
92             "Invalid window in ReadBloc(): win_xoff=%d,win_yoff=%d,xsize=%d,ysize=%d",
93             win_xoff, win_yoff, win_xsize, win_ysize );
94     }
95 
96 /* -------------------------------------------------------------------- */
97 /*      Work out sizes and offsets.                                     */
98 /* -------------------------------------------------------------------- */
99     int pixel_group = file->GetPixelGroupSize();
100     int pixel_size = DataTypeSize(GetType());
101 
102 /* -------------------------------------------------------------------- */
103 /*      Read and lock the scanline.                                     */
104 /* -------------------------------------------------------------------- */
105     uint8 *pixel_buffer = (uint8 *)
106         file->ReadAndLockBlock( block_index, win_xoff, win_xsize);
107 
108 /* -------------------------------------------------------------------- */
109 /*      Copy the data into our callers buffer.  Try to do this          */
110 /*      reasonably efficiently.  We might consider adding faster        */
111 /*      cases for 16/32bit data that is word aligned.                   */
112 /* -------------------------------------------------------------------- */
113     if( pixel_size == pixel_group )
114         memcpy( buffer, pixel_buffer, pixel_size * win_xsize );
115     else
116     {
117         int i;
118         uint8  *src = ((uint8 *)pixel_buffer) + image_offset;
119         uint8  *dst = (uint8 *) buffer;
120 
121         if( pixel_size == 1 )
122         {
123             for( i = win_xsize; i != 0; i-- )
124             {
125                 *dst = *src;
126                 dst++;
127                 src += pixel_group;
128             }
129         }
130         else if( pixel_size == 2 )
131         {
132             for( i = win_xsize; i != 0; i-- )
133             {
134                 *(dst++) = *(src++);
135                 *(dst++) = *(src++);
136                 src += pixel_group-2;
137             }
138         }
139         else if( pixel_size == 4 )
140         {
141             for( i = win_xsize; i != 0; i-- )
142             {
143                 *(dst++) = *(src++);
144                 *(dst++) = *(src++);
145                 *(dst++) = *(src++);
146                 *(dst++) = *(src++);
147                 src += pixel_group-4;
148             }
149         }
150         else
151             ThrowPCIDSKException( "Unsupported pixel type..." );
152     }
153 
154     file->UnlockBlock( 0 );
155 
156 /* -------------------------------------------------------------------- */
157 /*      Do byte swapping if needed.                                     */
158 /* -------------------------------------------------------------------- */
159     if( needs_swap )
160         SwapPixels( buffer, pixel_type, win_xsize );
161 
162     return 1;
163 }
164 
165 template <typename T>
CopyPixels(const T * const src,T * const dst,std::size_t offset,std::size_t count)166 void CopyPixels(const T* const src, T* const dst,
167                 std::size_t offset, std::size_t count)
168 {
169     for (std::size_t i = 0; i < count; i++)
170     {
171         dst[i] = src[(i + 1) * offset];
172     }
173 }
174 
175 /************************************************************************/
176 /*                             WriteBlock()                             */
177 /************************************************************************/
178 
WriteBlock(int block_index,void * buffer)179 int CPixelInterleavedChannel::WriteBlock( int block_index, void *buffer )
180 
181 {
182     if( !file->GetUpdatable() )
183         throw PCIDSKException( "File not open for update in WriteBlock()" );
184 
185     InvalidateOverviews();
186 
187 /* -------------------------------------------------------------------- */
188 /*      Work out sizes and offsets.                                     */
189 /* -------------------------------------------------------------------- */
190     int pixel_group = file->GetPixelGroupSize();
191     int pixel_size = DataTypeSize(GetType());
192 
193 /* -------------------------------------------------------------------- */
194 /*      Read and lock the scanline.                                     */
195 /* -------------------------------------------------------------------- */
196     uint8 *pixel_buffer = (uint8 *) file->ReadAndLockBlock( block_index );
197 
198 /* -------------------------------------------------------------------- */
199 /*      Copy the data into our callers buffer.  Try to do this          */
200 /*      reasonably efficiently.  We might consider adding faster        */
201 /*      cases for 16/32bit data that is word aligned.                   */
202 /* -------------------------------------------------------------------- */
203     // TODO: fixup for the complex case
204     if( pixel_size == pixel_group )
205         memcpy( pixel_buffer, buffer, pixel_size * width );
206     else
207     {
208         int i;
209         uint8  *dst = ((uint8 *)pixel_buffer) + image_offset;
210         uint8  *src = (uint8 *) buffer;
211 
212         if( pixel_size == 1 )
213         {
214             for( i = width; i != 0; i-- )
215             {
216                 *dst = *src;
217                 src++;
218                 dst += pixel_group;
219             }
220         }
221         else if( pixel_size == 2 )
222         {
223             for( i = width; i != 0; i-- )
224             {
225                 *(dst++) = *(src++);
226                 *(dst++) = *(src++);
227 
228                 if( needs_swap )
229                     SwapData( dst-2, 2, 1 );
230 
231                 dst += pixel_group-2;
232             }
233         }
234         else if( pixel_size == 4 )
235         {
236             for( i = width; i != 0; i-- )
237             {
238                 *(dst++) = *(src++);
239                 *(dst++) = *(src++);
240                 *(dst++) = *(src++);
241                 *(dst++) = *(src++);
242 
243                 if( needs_swap )
244                     SwapData( dst-4, 4, 1);
245 
246                 dst += pixel_group-4;
247 
248             }
249         }
250         else
251             ThrowPCIDSKException( "Unsupported pixel type..." );
252     }
253 
254     file->UnlockBlock( 1 );
255 
256 /* -------------------------------------------------------------------- */
257 /*      Do byte swapping if needed.                                     */
258 /* -------------------------------------------------------------------- */
259 
260     return 1;
261 }
262