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