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