1 : /******************************************************************************
2 : * $Id: rasterio.cpp 19888 2010-06-19 04:26:59Z pvachon $
3 : *
4 : * Project: GDAL Core
5 : * Purpose: Contains default implementation of GDALRasterBand::IRasterIO()
6 : * and supporting functions of broader utility.
7 : * Author: Frank Warmerdam, warmerdam@pobox.com
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 1998, Frank Warmerdam
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "gdal_priv.h"
32 :
33 : // Define a list of "C++" compilers that have broken template support or
34 : // broken scoping so we can fall back on the legacy implementation of
35 : // GDALCopyWords
36 : #define NOT_BROKEN_COMPILER \
37 : (!(defined(_MSC_VER) && _MSC_VER <= 1200) && !defined(__BORLANDC__) && \
38 : !defined(__SUNPRO_CC))
39 :
40 : #if NOT_BROKEN_COMPILER
41 : #include <stdexcept>
42 : #include <limits>
43 :
44 : // For now, work around MSVC++ 6.0's broken template support. If this value
45 : // is not defined, the old GDALCopyWords implementation is used.
46 : #define USE_NEW_COPYWORDS 1
47 : #endif
48 :
49 :
50 : CPL_CVSID("$Id: rasterio.cpp 19888 2010-06-19 04:26:59Z pvachon $");
51 :
52 : /************************************************************************/
53 : /* IRasterIO() */
54 : /* */
55 : /* Default internal implementation of RasterIO() ... utilizes */
56 : /* the Block access methods to satisfy the request. This would */
57 : /* normally only be overridden by formats with overviews. */
58 : /************************************************************************/
59 :
60 : CPLErr GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
61 : int nXOff, int nYOff, int nXSize, int nYSize,
62 : void * pData, int nBufXSize, int nBufYSize,
63 : GDALDataType eBufType,
64 782325 : int nPixelSpace, int nLineSpace )
65 :
66 : {
67 782325 : int nBandDataSize = GDALGetDataTypeSize( eDataType ) / 8;
68 782325 : int nBufDataSize = GDALGetDataTypeSize( eBufType ) / 8;
69 782325 : GByte *pabySrcBlock = NULL;
70 782325 : GDALRasterBlock *poBlock = NULL;
71 782325 : int nLBlockX=-1, nLBlockY=-1, iBufYOff, iBufXOff, iSrcY;
72 :
73 : /* ==================================================================== */
74 : /* A common case is the data requested with the destination */
75 : /* is packed, and the block width is the raster width. */
76 : /* ==================================================================== */
77 782325 : if( nPixelSpace == nBufDataSize
78 : && nLineSpace == nPixelSpace * nXSize
79 : && nBlockXSize == GetXSize()
80 : && nBufXSize == nXSize
81 : && nBufYSize == nYSize )
82 : {
83 : // printf( "IRasterIO(%d,%d,%d,%d) rw=%d case 1\n",
84 : // nXOff, nYOff, nXSize, nYSize,
85 : // (int) eRWFlag );
86 :
87 813179 : for( iBufYOff = 0; iBufYOff < nBufYSize; iBufYOff++ )
88 : {
89 : int nSrcByteOffset;
90 :
91 489715 : iSrcY = iBufYOff + nYOff;
92 :
93 489715 : if( iSrcY < nLBlockY * nBlockYSize
94 : || iSrcY >= (nLBlockY+1) * nBlockYSize )
95 : {
96 381993 : nLBlockY = iSrcY / nBlockYSize;
97 : int bJustInitialize =
98 : eRWFlag == GF_Write
99 : && nXOff == 0 && nXSize == nBlockXSize
100 : && nYOff <= nLBlockY * nBlockYSize
101 381993 : && nYOff + nYSize >= (nLBlockY+1) * nBlockYSize;
102 :
103 381993 : if( poBlock )
104 58523 : poBlock->DropLock();
105 :
106 381993 : poBlock = GetLockedBlockRef( 0, nLBlockY, bJustInitialize );
107 381993 : if( poBlock == NULL )
108 : {
109 : CPLError( CE_Failure, CPLE_AppDefined,
110 : "GetBlockRef failed at X block offset %d, "
111 6 : "Y block offset %d", 0, nLBlockY );
112 6 : return( CE_Failure );
113 : }
114 :
115 381987 : if( eRWFlag == GF_Write )
116 26327 : poBlock->MarkDirty();
117 :
118 381987 : pabySrcBlock = (GByte *) poBlock->GetDataRef();
119 381987 : if( pabySrcBlock == NULL )
120 : {
121 0 : poBlock->DropLock();
122 0 : return CE_Failure;
123 : }
124 : }
125 :
126 : nSrcByteOffset = ((iSrcY-nLBlockY*nBlockYSize)*nBlockXSize + nXOff)
127 489709 : * nBandDataSize;
128 :
129 489709 : if( eDataType == eBufType )
130 : {
131 199749 : if( eRWFlag == GF_Read )
132 : memcpy( ((GByte *) pData) + (size_t)iBufYOff * nLineSpace,
133 : pabySrcBlock + nSrcByteOffset,
134 137928 : nLineSpace );
135 : else
136 : memcpy( pabySrcBlock + nSrcByteOffset,
137 : ((GByte *) pData) + (size_t)iBufYOff * nLineSpace,
138 61821 : nLineSpace );
139 : }
140 : else
141 : {
142 : /* type to type conversion */
143 :
144 289960 : if( eRWFlag == GF_Read )
145 : GDALCopyWords( pabySrcBlock + nSrcByteOffset,
146 : eDataType, nBandDataSize,
147 : ((GByte *) pData) + (size_t)iBufYOff * nLineSpace,
148 286447 : eBufType, nPixelSpace, nBufXSize );
149 : else
150 : GDALCopyWords( ((GByte *) pData) + (size_t)iBufYOff * nLineSpace,
151 : eBufType, nPixelSpace,
152 : pabySrcBlock + nSrcByteOffset,
153 3513 : eDataType, nBandDataSize, nBufXSize );
154 : }
155 : }
156 :
157 323464 : if( poBlock )
158 323464 : poBlock->DropLock();
159 :
160 323464 : return CE_None;
161 : }
162 :
163 : /* ==================================================================== */
164 : /* Do we have overviews that would be appropriate to satisfy */
165 : /* this request? */
166 : /* ==================================================================== */
167 458855 : if( (nBufXSize < nXSize || nBufYSize < nYSize)
168 : && GetOverviewCount() > 0 && eRWFlag == GF_Read )
169 : {
170 9 : if( OverviewRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
171 : pData, nBufXSize, nBufYSize,
172 : eBufType, nPixelSpace, nLineSpace ) == CE_None )
173 5 : return CE_None;
174 : }
175 :
176 : /* ==================================================================== */
177 : /* The second case when we don't need subsample data but likely */
178 : /* need data type conversion. */
179 : /* ==================================================================== */
180 : int iSrcX;
181 :
182 458850 : if ( /* nPixelSpace == nBufDataSize
183 : && */ nXSize == nBufXSize
184 : && nYSize == nBufYSize )
185 : {
186 : // printf( "IRasterIO(%d,%d,%d,%d) rw=%d case 2\n",
187 : // nXOff, nYOff, nXSize, nYSize,
188 : // (int) eRWFlag );
189 :
190 : /* -------------------------------------------------------------------- */
191 : /* Loop over buffer computing source locations. */
192 : /* -------------------------------------------------------------------- */
193 : int nLBlockXStart, nXSpanEnd;
194 :
195 : // Calculate starting values out of loop
196 127730 : nLBlockXStart = nXOff / nBlockXSize;
197 127730 : nXSpanEnd = nBufXSize + nXOff;
198 :
199 127730 : int nYInc = 0;
200 256719 : for( iBufYOff = 0, iSrcY = nYOff; iBufYOff < nBufYSize; iBufYOff+=nYInc, iSrcY+=nYInc )
201 : {
202 : size_t iBufOffset, iSrcOffset;
203 : int nXSpan;
204 :
205 128994 : iBufOffset = (size_t)iBufYOff * nLineSpace;
206 128994 : nLBlockY = iSrcY / nBlockYSize;
207 128994 : nLBlockX = nLBlockXStart;
208 128994 : iSrcX = nXOff;
209 1904028 : while( iSrcX < nXSpanEnd )
210 : {
211 : int nXSpanSize;
212 :
213 1646045 : nXSpan = (nLBlockX + 1) * nBlockXSize;
214 1646045 : nXSpan = ( ( nXSpan < nXSpanEnd )?nXSpan:nXSpanEnd ) - iSrcX;
215 1646045 : nXSpanSize = nXSpan * nPixelSpace;
216 :
217 : int bJustInitialize =
218 : eRWFlag == GF_Write
219 : && nYOff <= nLBlockY * nBlockYSize
220 : && nYOff + nYSize >= (nLBlockY+1) * nBlockYSize
221 : && nXOff <= nLBlockX * nBlockXSize
222 1646045 : && nXOff + nXSize >= (nLBlockX+1) * nBlockXSize;
223 :
224 : // printf( "bJustInitialize = %d (%d,%d,%d,%d)\n",
225 : // bJustInitialize,
226 : // nYOff, nYSize,
227 : // nLBlockY, nBlockYSize );
228 : // bJustInitialize = FALSE;
229 :
230 :
231 : /* -------------------------------------------------------------------- */
232 : /* Ensure we have the appropriate block loaded. */
233 : /* -------------------------------------------------------------------- */
234 1646045 : poBlock = GetLockedBlockRef( nLBlockX, nLBlockY, bJustInitialize );
235 1646045 : if( !poBlock )
236 : {
237 : CPLError( CE_Failure, CPLE_AppDefined,
238 : "GetBlockRef failed at X block offset %d, "
239 5 : "Y block offset %d", nLBlockX, nLBlockY );
240 5 : return( CE_Failure );
241 : }
242 :
243 1646040 : if( eRWFlag == GF_Write )
244 49460 : poBlock->MarkDirty();
245 :
246 1646040 : pabySrcBlock = (GByte *) poBlock->GetDataRef();
247 1646040 : if( pabySrcBlock == NULL )
248 : {
249 0 : poBlock->DropLock();
250 0 : return CE_Failure;
251 : }
252 :
253 : /* -------------------------------------------------------------------- */
254 : /* Copy over this chunk of data. */
255 : /* -------------------------------------------------------------------- */
256 : iSrcOffset = ((size_t)iSrcX - (size_t)nLBlockX*nBlockXSize
257 1646040 : + ((size_t)(iSrcY) - (size_t)nLBlockY*nBlockYSize) * nBlockXSize)*nBandDataSize;
258 : /* Fill up as many rows as possible for the loaded block */
259 1646040 : int kmax = MIN(nBlockYSize - (iSrcY % nBlockYSize), nBufYSize - iBufYOff);
260 3708051 : for(int k=0; k<kmax;k++)
261 : {
262 2400073 : if( eDataType == eBufType
263 : && nPixelSpace == nBufDataSize )
264 : {
265 338062 : if( eRWFlag == GF_Read )
266 : memcpy( ((GByte *) pData) + iBufOffset + k * nLineSpace,
267 169365 : pabySrcBlock + iSrcOffset, nXSpanSize );
268 : else
269 : memcpy( pabySrcBlock + iSrcOffset,
270 168697 : ((GByte *) pData) + iBufOffset + k * nLineSpace, nXSpanSize );
271 : }
272 : else
273 : {
274 : /* type to type conversion */
275 :
276 1723949 : if( eRWFlag == GF_Read )
277 : GDALCopyWords( pabySrcBlock + iSrcOffset,
278 : eDataType, nBandDataSize,
279 : ((GByte *) pData) + iBufOffset + k * nLineSpace,
280 1685410 : eBufType, nPixelSpace, nXSpan );
281 : else
282 : GDALCopyWords( ((GByte *) pData) + iBufOffset + k * nLineSpace,
283 : eBufType, nPixelSpace,
284 : pabySrcBlock + iSrcOffset,
285 38539 : eDataType, nBandDataSize, nXSpan );
286 : }
287 :
288 2062011 : iSrcOffset += nBlockXSize * nBandDataSize;
289 : }
290 :
291 1646040 : iBufOffset += nXSpanSize;
292 1646040 : nLBlockX++;
293 1646040 : iSrcX+=nXSpan;
294 :
295 1646040 : poBlock->DropLock();
296 1646040 : poBlock = NULL;
297 : }
298 :
299 : /* Compute the increment to go on a block boundary */
300 128989 : nYInc = nBlockYSize - (iSrcY % nBlockYSize);
301 : }
302 :
303 127725 : return CE_None;
304 : }
305 :
306 : /* ==================================================================== */
307 : /* Loop reading required source blocks to satisfy output */
308 : /* request. This is the most general implementation. */
309 : /* ==================================================================== */
310 :
311 : /* -------------------------------------------------------------------- */
312 : /* Compute stepping increment. */
313 : /* -------------------------------------------------------------------- */
314 : double dfSrcXInc, dfSrcYInc;
315 331120 : dfSrcXInc = nXSize / (double) nBufXSize;
316 331120 : dfSrcYInc = nYSize / (double) nBufYSize;
317 :
318 :
319 : // printf( "IRasterIO(%d,%d,%d,%d) rw=%d case 3\n",
320 : // nXOff, nYOff, nXSize, nYSize,
321 : // (int) eRWFlag );
322 331120 : if (eRWFlag == GF_Write)
323 : {
324 : /* -------------------------------------------------------------------- */
325 : /* Write case */
326 : /* Loop over raster window computing source locations in the buffer. */
327 : /* -------------------------------------------------------------------- */
328 : int iDstX, iDstY;
329 165533 : GByte* pabyDstBlock = NULL;
330 :
331 1251211 : for( iDstY = nYOff; iDstY < nYOff + nYSize; iDstY ++)
332 : {
333 : size_t iBufOffset, iDstOffset;
334 1085678 : iBufYOff = (int)((iDstY - nYOff) / dfSrcYInc);
335 :
336 8670116 : for( iDstX = nXOff; iDstX < nXOff + nXSize; iDstX ++)
337 : {
338 7584438 : iBufXOff = (int)((iDstX - nXOff) / dfSrcXInc);
339 7584438 : iBufOffset = (size_t)iBufYOff * nLineSpace + iBufXOff * nPixelSpace;
340 :
341 : /* -------------------------------------------------------------------- */
342 : /* Ensure we have the appropriate block loaded. */
343 : /* -------------------------------------------------------------------- */
344 7584438 : if( iDstX < nLBlockX * nBlockXSize
345 : || iDstX >= (nLBlockX+1) * nBlockXSize
346 : || iDstY < nLBlockY * nBlockYSize
347 : || iDstY >= (nLBlockY+1) * nBlockYSize )
348 : {
349 734375 : nLBlockX = iDstX / nBlockXSize;
350 734375 : nLBlockY = iDstY / nBlockYSize;
351 :
352 : int bJustInitialize =
353 : nYOff <= nLBlockY * nBlockYSize
354 : && nYOff + nYSize >= (nLBlockY+1) * nBlockYSize
355 : && nXOff <= nLBlockX * nBlockXSize
356 734375 : && nXOff + nXSize >= (nLBlockX+1) * nBlockXSize;
357 :
358 734375 : if( poBlock != NULL )
359 568842 : poBlock->DropLock();
360 :
361 : poBlock = GetLockedBlockRef( nLBlockX, nLBlockY,
362 734375 : bJustInitialize );
363 734375 : if( poBlock == NULL )
364 : {
365 0 : return( CE_Failure );
366 : }
367 :
368 734375 : poBlock->MarkDirty();
369 :
370 734375 : pabyDstBlock = (GByte *) poBlock->GetDataRef();
371 734375 : if( pabyDstBlock == NULL )
372 : {
373 0 : poBlock->DropLock();
374 0 : return CE_Failure;
375 : }
376 : }
377 :
378 : /* -------------------------------------------------------------------- */
379 : /* Copy over this pixel of data. */
380 : /* -------------------------------------------------------------------- */
381 : iDstOffset = ((size_t)iDstX - (size_t)nLBlockX*nBlockXSize
382 7584438 : + ((size_t)iDstY - (size_t)nLBlockY*nBlockYSize) * nBlockXSize)*nBandDataSize;
383 :
384 7584438 : if( eDataType == eBufType )
385 : {
386 : memcpy( pabyDstBlock + iDstOffset,
387 7583838 : ((GByte *) pData) + iBufOffset, nBandDataSize );
388 : }
389 : else
390 : {
391 : /* type to type conversion ... ouch, this is expensive way
392 : of handling single words */
393 :
394 : GDALCopyWords( ((GByte *) pData) + iBufOffset, eBufType, 0,
395 : pabyDstBlock + iDstOffset, eDataType, 0,
396 600 : 1 );
397 : }
398 : }
399 : }
400 : }
401 : else
402 : {
403 : double dfSrcX, dfSrcY;
404 : /* -------------------------------------------------------------------- */
405 : /* Read case */
406 : /* Loop over buffer computing source locations. */
407 : /* -------------------------------------------------------------------- */
408 582464 : for( iBufYOff = 0; iBufYOff < nBufYSize; iBufYOff++ )
409 : {
410 : size_t iBufOffset, iSrcOffset;
411 :
412 416877 : dfSrcY = (iBufYOff+0.5) * dfSrcYInc + nYOff;
413 416877 : iSrcY = (int) dfSrcY;
414 :
415 416877 : iBufOffset = (size_t)iBufYOff * nLineSpace;
416 :
417 3832550 : for( iBufXOff = 0; iBufXOff < nBufXSize; iBufXOff++ )
418 : {
419 3415673 : dfSrcX = (iBufXOff+0.5) * dfSrcXInc + nXOff;
420 :
421 3415673 : iSrcX = (int) dfSrcX;
422 :
423 : /* -------------------------------------------------------------------- */
424 : /* Ensure we have the appropriate block loaded. */
425 : /* -------------------------------------------------------------------- */
426 3415673 : if( iSrcX < nLBlockX * nBlockXSize
427 : || iSrcX >= (nLBlockX+1) * nBlockXSize
428 : || iSrcY < nLBlockY * nBlockYSize
429 : || iSrcY >= (nLBlockY+1) * nBlockYSize )
430 : {
431 561407 : nLBlockX = iSrcX / nBlockXSize;
432 561407 : nLBlockY = iSrcY / nBlockYSize;
433 :
434 561407 : if( poBlock != NULL )
435 395820 : poBlock->DropLock();
436 :
437 : poBlock = GetLockedBlockRef( nLBlockX, nLBlockY,
438 561407 : FALSE );
439 561407 : if( poBlock == NULL )
440 : {
441 0 : return( CE_Failure );
442 : }
443 :
444 561407 : pabySrcBlock = (GByte *) poBlock->GetDataRef();
445 561407 : if( pabySrcBlock == NULL )
446 : {
447 0 : poBlock->DropLock();
448 0 : return CE_Failure;
449 : }
450 : }
451 :
452 : /* -------------------------------------------------------------------- */
453 : /* Copy over this pixel of data. */
454 : /* -------------------------------------------------------------------- */
455 : iSrcOffset = ((size_t)iSrcX - (size_t)nLBlockX*nBlockXSize
456 3415673 : + ((size_t)iSrcY - (size_t)nLBlockY*nBlockYSize) * nBlockXSize)*nBandDataSize;
457 :
458 3415673 : if( eDataType == eBufType )
459 : {
460 : memcpy( ((GByte *) pData) + iBufOffset,
461 3413973 : pabySrcBlock + iSrcOffset, nBandDataSize );
462 : }
463 : else
464 : {
465 : /* type to type conversion ... ouch, this is expensive way
466 : of handling single words */
467 : GDALCopyWords( pabySrcBlock + iSrcOffset, eDataType, 0,
468 : ((GByte *) pData) + iBufOffset, eBufType, 0,
469 1700 : 1 );
470 : }
471 :
472 3415673 : iBufOffset += nPixelSpace;
473 : }
474 : }
475 : }
476 :
477 331120 : if( poBlock != NULL )
478 331120 : poBlock->DropLock();
479 :
480 331120 : return( CE_None );
481 : }
482 :
483 : /************************************************************************/
484 : /* GDALSwapWords() */
485 : /************************************************************************/
486 :
487 : /**
488 : * Byte swap words in-place.
489 : *
490 : * This function will byte swap a set of 2, 4 or 8 byte words "in place" in
491 : * a memory array. No assumption is made that the words being swapped are
492 : * word aligned in memory. Use the CPL_LSB and CPL_MSB macros from cpl_port.h
493 : * to determine if the current platform is big endian or little endian. Use
494 : * The macros like CPL_SWAP32() to byte swap single values without the overhead
495 : * of a function call.
496 : *
497 : * @param pData pointer to start of data buffer.
498 : * @param nWordSize size of words being swapped in bytes. Normally 2, 4 or 8.
499 : * @param nWordCount the number of words to be swapped in this call.
500 : * @param nWordSkip the byte offset from the start of one word to the start of
501 : * the next. For packed buffers this is the same as nWordSize.
502 : */
503 :
504 : void CPL_STDCALL GDALSwapWords( void *pData, int nWordSize, int nWordCount,
505 8641 : int nWordSkip )
506 :
507 : {
508 8641 : if (nWordCount > 0)
509 8641 : VALIDATE_POINTER0( pData , "GDALSwapWords" );
510 :
511 : int i;
512 8641 : GByte *pabyData = (GByte *) pData;
513 :
514 8641 : switch( nWordSize )
515 : {
516 : case 1:
517 0 : break;
518 :
519 : case 2:
520 8559 : CPLAssert( nWordSkip >= 2 || nWordCount == 1 );
521 10521207 : for( i = 0; i < nWordCount; i++ )
522 : {
523 : GByte byTemp;
524 :
525 10512648 : byTemp = pabyData[0];
526 10512648 : pabyData[0] = pabyData[1];
527 10512648 : pabyData[1] = byTemp;
528 :
529 10512648 : pabyData += nWordSkip;
530 : }
531 8559 : break;
532 :
533 : case 4:
534 37 : CPLAssert( nWordSkip >= 4 || nWordCount == 1 );
535 1160 : for( i = 0; i < nWordCount; i++ )
536 : {
537 : GByte byTemp;
538 :
539 1123 : byTemp = pabyData[0];
540 1123 : pabyData[0] = pabyData[3];
541 1123 : pabyData[3] = byTemp;
542 :
543 1123 : byTemp = pabyData[1];
544 1123 : pabyData[1] = pabyData[2];
545 1123 : pabyData[2] = byTemp;
546 :
547 1123 : pabyData += nWordSkip;
548 : }
549 37 : break;
550 :
551 : case 8:
552 45 : CPLAssert( nWordSkip >= 8 || nWordCount == 1 );
553 865 : for( i = 0; i < nWordCount; i++ )
554 : {
555 : GByte byTemp;
556 :
557 820 : byTemp = pabyData[0];
558 820 : pabyData[0] = pabyData[7];
559 820 : pabyData[7] = byTemp;
560 :
561 820 : byTemp = pabyData[1];
562 820 : pabyData[1] = pabyData[6];
563 820 : pabyData[6] = byTemp;
564 :
565 820 : byTemp = pabyData[2];
566 820 : pabyData[2] = pabyData[5];
567 820 : pabyData[5] = byTemp;
568 :
569 820 : byTemp = pabyData[3];
570 820 : pabyData[3] = pabyData[4];
571 820 : pabyData[4] = byTemp;
572 :
573 820 : pabyData += nWordSkip;
574 : }
575 45 : break;
576 :
577 : default:
578 0 : CPLAssert( FALSE );
579 : }
580 : }
581 :
582 : #ifdef USE_NEW_COPYWORDS
583 : // Place the new GDALCopyWords helpers in an anonymous namespace
584 : namespace {
585 : /************************************************************************/
586 : /* GetDataLimits() */
587 : /************************************************************************/
588 : /**
589 : * Compute the limits of values that can be placed in Tout in terms of
590 : * Tin. Usually used for output clamping, when the output data type's
591 : * limits are stable relative to the input type (i.e. no roundoff error).
592 : *
593 : * @param tMaxValue the returned maximum value
594 : * @param tMinValue the returned minimum value
595 : */
596 :
597 : template <class Tin, class Tout>
598 254972088 : inline void GetDataLimits(Tin &tMaxValue, Tin &tMinValue)
599 : {
600 254972088 : tMaxValue = std::numeric_limits<Tin>::max();
601 254972088 : tMinValue = std::numeric_limits<Tin>::min();
602 :
603 : // Compute the actual minimum value of Tout in terms of Tin.
604 : if (std::numeric_limits<Tout>::is_signed && std::numeric_limits<Tout>::is_integer)
605 : {
606 : // the minimum value is less than zero
607 : if (std::numeric_limits<Tout>::digits < std::numeric_limits<Tin>::digits ||
608 : !std::numeric_limits<Tin>::is_integer)
609 : {
610 : // Tout is smaller than Tin, so we need to clamp values in input
611 : // to the range of Tout's min/max values
612 : if (std::numeric_limits<Tin>::is_signed)
613 : {
614 36648 : tMinValue = static_cast<Tin>(std::numeric_limits<Tout>::min());
615 : }
616 59078 : tMaxValue = static_cast<Tin>(std::numeric_limits<Tout>::max());
617 : }
618 : }
619 : else if (std::numeric_limits<Tout>::is_integer)
620 : {
621 : // the output is unsigned, so we just need to determine the max
622 : if (std::numeric_limits<Tout>::digits <= std::numeric_limits<Tin>::digits)
623 : {
624 : // Tout is smaller than Tin, so we need to clamp the input values
625 : // to the range of Tout's max
626 14182538 : tMaxValue = static_cast<Tin>(std::numeric_limits<Tout>::max());
627 : }
628 254972088 : tMinValue = 0;
629 : }
630 :
631 : }
632 :
633 : /************************************************************************/
634 : /* ClampValue() */
635 : /************************************************************************/
636 : /**
637 : * Clamp values of type T to a specified range
638 : *
639 : * @param tValue the value
640 : * @param tMax the max value
641 : * @param tMin the min value
642 : */
643 : template <class T>
644 254970941 : inline T ClampValue(const T tValue, const T tMax, const T tMin)
645 : {
646 : return tValue > tMax ? tMax :
647 254970941 : tValue < tMin ? tMin : tValue;
648 : }
649 :
650 : /************************************************************************/
651 : /* CopyWord() */
652 : /************************************************************************/
653 : /**
654 : * Copy a single word, optionally rounding if appropriate (i.e. going
655 : * from the float to the integer case). Note that this is the function
656 : * you should specialize if you're adding a new data type.
657 : *
658 : * @param tValueIn value of type Tin; the input value to be converted
659 : * @param tValueOut value of type Tout; the output value
660 : */
661 :
662 : template <class Tin, class Tout>
663 250542989 : inline void CopyWord(const Tin tValueIn, Tout &tValueOut)
664 : {
665 : Tin tMaxVal, tMinVal;
666 250542989 : GetDataLimits<Tin, Tout>(tMaxVal, tMinVal);
667 250542989 : tValueOut = static_cast<Tout>(ClampValue(tValueIn, tMaxVal, tMinVal));
668 : }
669 :
670 : template <class Tin>
671 12739846 : inline void CopyWord(const Tin tValueIn, float &fValueOut)
672 : {
673 12739846 : fValueOut = tValueIn;
674 : }
675 :
676 : template <class Tin>
677 162787 : inline void CopyWord(const Tin tValueIn, double &dfValueOut)
678 : {
679 162787 : dfValueOut = tValueIn;
680 : }
681 :
682 421 : inline void CopyWord(const double dfValueIn, double &dfValueOut)
683 : {
684 421 : dfValueOut = dfValueIn;
685 421 : }
686 :
687 32364 : inline void CopyWord(const float fValueIn, float &fValueOut)
688 : {
689 32364 : fValueOut = fValueIn;
690 32364 : }
691 :
692 1301650 : inline void CopyWord(const float fValueIn, double &dfValueOut)
693 : {
694 1301650 : dfValueOut = fValueIn;
695 1301650 : }
696 :
697 32497 : inline void CopyWord(const double dfValueIn, float &fValueOut)
698 : {
699 32497 : fValueOut = static_cast<float>(dfValueIn);
700 32497 : }
701 :
702 : template <class Tout>
703 4207724 : inline void CopyWord(const float fValueIn, Tout &tValueOut)
704 : {
705 : float fMaxVal, fMinVal;
706 4207724 : GetDataLimits<float, Tout>(fMaxVal, fMinVal);
707 4207724 : tValueOut = static_cast<Tout>(
708 : ClampValue(fValueIn + 0.5f, fMaxVal, fMinVal));
709 : }
710 :
711 : template <class Tout>
712 183864 : inline void CopyWord(const double dfValueIn, Tout &tValueOut)
713 : {
714 : double dfMaxVal, dfMinVal;
715 183864 : GetDataLimits<double, Tout>(dfMaxVal, dfMinVal);
716 183864 : tValueOut = static_cast<Tout>(
717 : ClampValue(dfValueIn + 0.5, dfMaxVal, dfMinVal));
718 : }
719 :
720 1653 : inline void CopyWord(const double dfValueIn, int &nValueOut)
721 : {
722 : double dfMaxVal, dfMinVal;
723 1653 : GetDataLimits<double, int>(dfMaxVal, dfMinVal);
724 : double dfValue = dfValueIn >= 0.0 ? dfValueIn + 0.5 :
725 1653 : dfValueIn - 0.5;
726 : nValueOut = static_cast<int>(
727 1653 : ClampValue(dfValue, dfMaxVal, dfMinVal));
728 1653 : }
729 :
730 19753 : inline void CopyWord(const float fValueIn, short &nValueOut)
731 : {
732 : float fMaxVal, fMinVal;
733 19753 : GetDataLimits<float, short>(fMaxVal, fMinVal);
734 : float fValue = fValueIn >= 0.0f ? fValueIn + 0.5f :
735 19753 : fValueIn - 0.5f;
736 : nValueOut = static_cast<short>(
737 19753 : ClampValue(fValue, fMaxVal, fMinVal));
738 19753 : }
739 :
740 14958 : inline void CopyWord(const double dfValueIn, short &nValueOut)
741 : {
742 : double dfMaxVal, dfMinVal;
743 14958 : GetDataLimits<double, short>(dfMaxVal, dfMinVal);
744 : double dfValue = dfValueIn > 0.0 ? dfValueIn + 0.5 :
745 14958 : dfValueIn - 0.5;
746 : nValueOut = static_cast<short>(
747 14958 : ClampValue(dfValue, dfMaxVal, dfMinVal));
748 14958 : }
749 :
750 : // Roundoff occurs for Float32 -> int32 for max/min. Overload CopyWord
751 : // specifically for this case.
752 697656 : inline void CopyWord(const float fValueIn, int &nValueOut)
753 : {
754 697656 : if (fValueIn >= static_cast<float>(std::numeric_limits<int>::max()))
755 : {
756 0 : nValueOut = std::numeric_limits<int>::max();
757 : }
758 697656 : else if (fValueIn <= static_cast<float>(std::numeric_limits<int>::min()))
759 : {
760 0 : nValueOut = std::numeric_limits<int>::min();
761 : }
762 : else
763 : {
764 : nValueOut = static_cast<int>(fValueIn > 0.0f ?
765 697656 : fValueIn + 0.5f : fValueIn - 0.5f);
766 : }
767 697656 : }
768 :
769 : // Roundoff occurs for Float32 -> uint32 for max. Overload CopyWord
770 : // specifically for this case.
771 200 : inline void CopyWord(const float fValueIn, unsigned int &nValueOut)
772 : {
773 200 : if (fValueIn >= static_cast<float>(std::numeric_limits<unsigned int>::max()))
774 : {
775 0 : nValueOut = std::numeric_limits<unsigned int>::max();
776 : }
777 200 : else if (fValueIn <= static_cast<float>(std::numeric_limits<unsigned int>::min()))
778 : {
779 0 : nValueOut = std::numeric_limits<unsigned int>::min();
780 : }
781 : else
782 : {
783 200 : nValueOut = static_cast<unsigned int>(fValueIn + 0.5f);
784 : }
785 200 : }
786 :
787 : /************************************************************************/
788 : /* GDALCopyWordsT() */
789 : /************************************************************************/
790 : /**
791 : * Template function, used to copy data from pSrcData into buffer
792 : * pDstData, with stride nSrcPixelOffset in the source data and
793 : * stride nDstPixelOffset in the destination data. This template can
794 : * deal with the case where the input data type is real or complex and
795 : * the output is real.
796 : *
797 : * @param pSrcData the source data buffer
798 : * @param nSrcPixelOffset the stride, in the buffer pSrcData for pixels
799 : * of interest.
800 : * @param pDstData the destination buffer.
801 : * @param nDstPixelOffset the stride in the buffer pDstData for pixels of
802 : * interest.
803 : * @param nWordCount the total number of pixel words to copy
804 : *
805 : * @code
806 : * // Assume an input buffer of type GUInt16 named pBufferIn
807 : * GByte *pBufferOut = new GByte[numBytesOut];
808 : * GDALCopyWordsT<GUInt16, GByte>(pSrcData, 2, pDstData, 1, numBytesOut);
809 : * @code
810 : * @note
811 : * This is a private function, and should not be exposed outside of rasterio.cpp.
812 : * External users should call the GDALCopyWords driver function.
813 : * @note
814 : */
815 :
816 : template <class Tin, class Tout>
817 : static void GDALCopyWordsT(const Tin* const pSrcData, int nSrcPixelOffset,
818 : Tout* const pDstData, int nDstPixelOffset,
819 2920289 : int nWordCount)
820 : {
821 2920289 : std::ptrdiff_t nDstOffset = 0;
822 :
823 2920289 : const char* const pSrcDataPtr = reinterpret_cast<const char*>(pSrcData);
824 2920289 : char* const pDstDataPtr = reinterpret_cast<char*>(pDstData);
825 272823469 : for (std::ptrdiff_t n = 0; n < nWordCount; n++)
826 : {
827 269903180 : const Tin tValue = *reinterpret_cast<const Tin*>(pSrcDataPtr + (n * nSrcPixelOffset));
828 269903180 : Tout* const pOutPixel = reinterpret_cast<Tout*>(pDstDataPtr + nDstOffset);
829 :
830 269903180 : CopyWord(tValue, *pOutPixel);
831 :
832 272823469 : nDstOffset += nDstPixelOffset;
833 : }
834 : }
835 :
836 : /************************************************************************/
837 : /* GDALCopyWordsComplexT() */
838 : /************************************************************************/
839 : /**
840 : * Template function, used to copy data from pSrcData into buffer
841 : * pDstData, with stride nSrcPixelOffset in the source data and
842 : * stride nDstPixelOffset in the destination data. Deals with the
843 : * complex case, where input is complex and output is complex.
844 : *
845 : * @param pSrcData the source data buffer
846 : * @param nSrcPixelOffset the stride, in the buffer pSrcData for pixels
847 : * of interest.
848 : * @param pDstData the destination buffer.
849 : * @param nDstPixelOffset the stride in the buffer pDstData for pixels of
850 : * interest.
851 : * @param nWordCount the total number of pixel words to copy
852 : *
853 : */
854 : template <class Tin, class Tout>
855 : inline void GDALCopyWordsComplexT(const Tin* const pSrcData, int nSrcPixelOffset,
856 : Tout* const pDstData, int nDstPixelOffset,
857 1147 : int nWordCount)
858 : {
859 1147 : std::ptrdiff_t nDstOffset = 0;
860 1147 : const char* const pSrcDataPtr = reinterpret_cast<const char*>(pSrcData);
861 1147 : char* const pDstDataPtr = reinterpret_cast<char*>(pDstData);
862 :
863 : // Determine the minimum and maximum value we can have based
864 : // on the constraints of Tin and Tout.
865 : Tin tMaxValue, tMinValue;
866 1147 : GetDataLimits<Tin, Tout>(tMaxValue, tMinValue);
867 :
868 17138 : for (std::ptrdiff_t n = 0; n < nWordCount; n++)
869 : {
870 15991 : const Tin* const pPixelIn = reinterpret_cast<const Tin*>(pSrcDataPtr + n * nSrcPixelOffset);
871 15991 : Tout* const pPixelOut = reinterpret_cast<Tout*>(pDstDataPtr + nDstOffset);
872 :
873 15991 : CopyWord(pPixelIn[0], pPixelOut[0]);
874 15991 : CopyWord(pPixelIn[1], pPixelOut[1]);
875 :
876 17138 : nDstOffset += nDstPixelOffset;
877 : }
878 : }
879 :
880 : /************************************************************************/
881 : /* GDALCopyWordsComplexOutT() */
882 : /************************************************************************/
883 : /**
884 : * Template function, used to copy data from pSrcData into buffer
885 : * pDstData, with stride nSrcPixelOffset in the source data and
886 : * stride nDstPixelOffset in the destination data. Deals with the
887 : * case where the value is real coming in, but complex going out.
888 : *
889 : * @param pSrcData the source data buffer
890 : * @param nSrcPixelOffset the stride, in the buffer pSrcData for pixels
891 : * of interest, in bytes.
892 : * @param pDstData the destination buffer.
893 : * @param nDstPixelOffset the stride in the buffer pDstData for pixels of
894 : * interest, in bytes.
895 : * @param nWordCount the total number of pixel words to copy
896 : *
897 : */
898 : template <class Tin, class Tout>
899 : inline void GDALCopyWordsComplexOutT(const Tin* const pSrcData, int nSrcPixelOffset,
900 : Tout* const pDstData, int nDstPixelOffset,
901 160 : int nWordCount)
902 : {
903 160 : std::ptrdiff_t nDstOffset = 0;
904 :
905 160 : const Tout tOutZero = static_cast<Tout>(0);
906 :
907 160 : const char* const pSrcDataPtr = reinterpret_cast<const char*>(pSrcData);
908 160 : char* const pDstDataPtr = reinterpret_cast<char*>(pDstData);
909 :
910 3360 : for (std::ptrdiff_t n = 0; n < nWordCount; n++)
911 : {
912 3200 : const Tin tValue = *reinterpret_cast<const Tin* const>(pSrcDataPtr + n * nSrcPixelOffset);
913 3200 : Tout* const pPixelOut = reinterpret_cast<Tout*>(pDstDataPtr + nDstOffset);
914 3200 : CopyWord(tValue, *pPixelOut);
915 :
916 3200 : pPixelOut[1] = tOutZero;
917 :
918 3360 : nDstOffset += nDstPixelOffset;
919 : }
920 : }
921 :
922 : /************************************************************************/
923 : /* GDALCopyWordsFromT() */
924 : /************************************************************************/
925 : /**
926 : * Template driver function. Given the input type T, call the appropriate
927 : * GDALCopyWordsT function template for the desired output type. You should
928 : * never call this function directly (call GDALCopyWords instead).
929 : *
930 : * @param pSrcData source data buffer
931 : * @param nSrcPixelOffset pixel stride in input buffer, in pixel words
932 : * @param bInComplex input is complex
933 : * @param pDstData destination data buffer
934 : * @param eDstType destination data type
935 : * @param nDstPixelOffset pixel stride in output buffer, in pixel words
936 : * @param nWordCount number of pixel words to be copied
937 : */
938 : template <class T>
939 : inline void GDALCopyWordsFromT(const T* const pSrcData, int nSrcPixelOffset, bool bInComplex,
940 : void *pDstData, GDALDataType eDstType, int nDstPixelOffset,
941 2921596 : int nWordCount)
942 : {
943 2921596 : switch (eDstType)
944 : {
945 : case GDT_Byte:
946 293531 : GDALCopyWordsT(pSrcData, nSrcPixelOffset,
947 : static_cast<unsigned char*>(pDstData), nDstPixelOffset,
948 : nWordCount);
949 293531 : break;
950 : case GDT_UInt16:
951 1616 : GDALCopyWordsT(pSrcData, nSrcPixelOffset,
952 : static_cast<unsigned short*>(pDstData), nDstPixelOffset,
953 : nWordCount);
954 1616 : break;
955 : case GDT_Int16:
956 2148 : GDALCopyWordsT(pSrcData, nSrcPixelOffset,
957 : static_cast<short*>(pDstData), nDstPixelOffset,
958 : nWordCount);
959 2148 : break;
960 : case GDT_UInt32:
961 935 : GDALCopyWordsT(pSrcData, nSrcPixelOffset,
962 : static_cast<unsigned int*>(pDstData), nDstPixelOffset,
963 : nWordCount);
964 935 : break;
965 : case GDT_Int32:
966 2231523 : GDALCopyWordsT(pSrcData, nSrcPixelOffset,
967 : static_cast<int*>(pDstData), nDstPixelOffset,
968 : nWordCount);
969 2231523 : break;
970 : case GDT_Float32:
971 349148 : GDALCopyWordsT(pSrcData, nSrcPixelOffset,
972 : static_cast<float*>(pDstData), nDstPixelOffset,
973 : nWordCount);
974 349148 : break;
975 : case GDT_Float64:
976 41388 : GDALCopyWordsT(pSrcData, nSrcPixelOffset,
977 : static_cast<double*>(pDstData), nDstPixelOffset,
978 : nWordCount);
979 41388 : break;
980 : case GDT_CInt16:
981 82 : if (bInComplex)
982 : {
983 42 : GDALCopyWordsComplexT(pSrcData, nSrcPixelOffset,
984 : static_cast<short *>(pDstData), nDstPixelOffset,
985 : nWordCount);
986 : }
987 : else // input is not complex, so we need to promote to a complex buffer
988 : {
989 40 : GDALCopyWordsComplexOutT(pSrcData, nSrcPixelOffset,
990 : static_cast<short *>(pDstData), nDstPixelOffset,
991 : nWordCount);
992 : }
993 82 : break;
994 : case GDT_CInt32:
995 432 : if (bInComplex)
996 : {
997 392 : GDALCopyWordsComplexT(pSrcData, nSrcPixelOffset,
998 : static_cast<int *>(pDstData), nDstPixelOffset,
999 : nWordCount);
1000 : }
1001 : else // input is not complex, so we need to promote to a complex buffer
1002 : {
1003 40 : GDALCopyWordsComplexOutT(pSrcData, nSrcPixelOffset,
1004 : static_cast<int *>(pDstData), nDstPixelOffset,
1005 : nWordCount);
1006 : }
1007 432 : break;
1008 : case GDT_CFloat32:
1009 197 : if (bInComplex)
1010 : {
1011 157 : GDALCopyWordsComplexT(pSrcData, nSrcPixelOffset,
1012 : static_cast<float *>(pDstData), nDstPixelOffset,
1013 : nWordCount);
1014 : }
1015 : else // input is not complex, so we need to promote to a complex buffer
1016 : {
1017 40 : GDALCopyWordsComplexOutT(pSrcData, nSrcPixelOffset,
1018 : static_cast<float *>(pDstData), nDstPixelOffset,
1019 : nWordCount);
1020 : }
1021 197 : break;
1022 : case GDT_CFloat64:
1023 596 : if (bInComplex)
1024 : {
1025 556 : GDALCopyWordsComplexT(pSrcData, nSrcPixelOffset,
1026 : static_cast<double *>(pDstData), nDstPixelOffset,
1027 : nWordCount);
1028 : }
1029 : else // input is not complex, so we need to promote to a complex buffer
1030 : {
1031 40 : GDALCopyWordsComplexOutT(pSrcData, nSrcPixelOffset,
1032 : static_cast<double *>(pDstData), nDstPixelOffset,
1033 : nWordCount);
1034 : }
1035 596 : break;
1036 : case GDT_Unknown:
1037 : default:
1038 0 : CPLAssert(FALSE);
1039 : }
1040 : }
1041 :
1042 : } // end anonymous namespace
1043 : #endif
1044 :
1045 : /************************************************************************/
1046 : /* GDALReplicateWord() */
1047 : /************************************************************************/
1048 :
1049 : void GDALReplicateWord(void *pSrcData, GDALDataType eSrcType,
1050 : void *pDstData, GDALDataType eDstType, int nDstPixelOffset,
1051 3978 : int nWordCount)
1052 : {
1053 : /* ----------------------------------------------------------------------- */
1054 : /* Special case when the source data is always the same value */
1055 : /* (for VRTSourcedRasterBand::IRasterIO and VRTDerivedRasterBand::IRasterIO*/
1056 : /* for example) */
1057 : /* ----------------------------------------------------------------------- */
1058 : /* Let the general translation case do the necessary conversions */
1059 : /* on the first destination element */
1060 : GDALCopyWords(pSrcData, eSrcType, 0,
1061 : pDstData, eDstType, nDstPixelOffset,
1062 3978 : 1 );
1063 :
1064 : /* Now copy the first element to the nWordCount - 1 following destination */
1065 : /* elements */
1066 3978 : nWordCount--;
1067 3978 : GByte *pabyDstWord = ((GByte *)pDstData) + nDstPixelOffset;
1068 :
1069 3978 : switch (eDstType)
1070 : {
1071 : case GDT_Byte:
1072 : {
1073 1678 : if (nDstPixelOffset == 1)
1074 : {
1075 1678 : memset(pabyDstWord, *(GByte*)pDstData, nWordCount - 1);
1076 : }
1077 : else
1078 : {
1079 0 : GByte valSet = *(GByte*)pDstData;
1080 0 : while(nWordCount--)
1081 : {
1082 0 : *pabyDstWord = valSet;
1083 0 : pabyDstWord += nDstPixelOffset;
1084 : }
1085 : }
1086 1678 : break;
1087 : }
1088 :
1089 : #define CASE_DUPLICATE_SIMPLE(enum_type, c_type) \
1090 : case enum_type:\
1091 : { \
1092 : c_type valSet = *(c_type*)pDstData; \
1093 : while(nWordCount--) \
1094 : { \
1095 : *(c_type*)pabyDstWord = valSet; \
1096 : pabyDstWord += nDstPixelOffset; \
1097 : } \
1098 : break; \
1099 : }
1100 :
1101 246 : CASE_DUPLICATE_SIMPLE(GDT_UInt16, GUInt16)
1102 46 : CASE_DUPLICATE_SIMPLE(GDT_Int16, GInt16)
1103 240 : CASE_DUPLICATE_SIMPLE(GDT_UInt32, GUInt32)
1104 1586 : CASE_DUPLICATE_SIMPLE(GDT_Int32, GInt32)
1105 140 : CASE_DUPLICATE_SIMPLE(GDT_Float32,float)
1106 42 : CASE_DUPLICATE_SIMPLE(GDT_Float64,double)
1107 :
1108 : #define CASE_DUPLICATE_COMPLEX(enum_type, c_type) \
1109 : case enum_type:\
1110 : { \
1111 : c_type valSet1 = ((c_type*)pDstData)[0]; \
1112 : c_type valSet2 = ((c_type*)pDstData)[1]; \
1113 : while(nWordCount--) \
1114 : { \
1115 : ((c_type*)pabyDstWord)[0] = valSet1; \
1116 : ((c_type*)pabyDstWord)[1] = valSet2; \
1117 : pabyDstWord += nDstPixelOffset; \
1118 : } \
1119 : break; \
1120 : }
1121 :
1122 0 : CASE_DUPLICATE_COMPLEX(GDT_CInt16, GInt16)
1123 0 : CASE_DUPLICATE_COMPLEX(GDT_CInt32, GInt32)
1124 0 : CASE_DUPLICATE_COMPLEX(GDT_CFloat32, float)
1125 0 : CASE_DUPLICATE_COMPLEX(GDT_CFloat64, double)
1126 :
1127 : default:
1128 0 : CPLAssert( FALSE );
1129 : }
1130 3978 : }
1131 :
1132 : /************************************************************************/
1133 : /* GDALCopyWords() */
1134 : /************************************************************************/
1135 :
1136 : /**
1137 : * Copy pixel words from buffer to buffer.
1138 : *
1139 : * This function is used to copy pixel word values from one memory buffer
1140 : * to another, with support for conversion between data types, and differing
1141 : * step factors. The data type conversion is done using the normal GDAL
1142 : * rules. Values assigned to a lower range integer type are clipped. For
1143 : * instance assigning GDT_Int16 values to a GDT_Byte buffer will cause values
1144 : * less the 0 to be set to 0, and values larger than 255 to be set to 255.
1145 : * Assignment from floating point to integer uses default C type casting
1146 : * semantics. Assignment from non-complex to complex will result in the
1147 : * imaginary part being set to zero on output. Assigment from complex to
1148 : * non-complex will result in the complex portion being lost and the real
1149 : * component being preserved (<i>not magnitidue!</i>).
1150 : *
1151 : * No assumptions are made about the source or destination words occuring
1152 : * on word boundaries. It is assumed that all values are in native machine
1153 : * byte order.
1154 : *
1155 : * @param pSrcData Pointer to source data to be converted.
1156 : * @param eSrcType the source data type (see GDALDataType enum)
1157 : * @param nSrcPixelOffset Source pixel offset, in bytes
1158 : * @param pDstData Pointer to buffer where destination data should go
1159 : * @param eDstType the destination data type (see GDALDataType enum)
1160 : * @param nDstPixelOffset Destination pixel offset, in bytes
1161 : * @param nWordCount number of words to be copied
1162 : *
1163 : *
1164 : * @note
1165 : * When adding a new data type to GDAL, you must do the following to
1166 : * support it properly within the GDALCopyWords function:
1167 : * 1. Add the data type to the switch on eSrcType in GDALCopyWords.
1168 : * This should invoke the appropriate GDALCopyWordsFromT wrapper.
1169 : * 2. Add the data type to the switch on eDstType in GDALCopyWordsFromT.
1170 : * This should call the appropriate GDALCopyWordsT template.
1171 : * 3. If appropriate, overload the appropriate CopyWord template in the
1172 : * above namespace. This will ensure that any conversion issues are
1173 : * handled (cases like the float -> int32 case, where the min/max)
1174 : * values are subject to roundoff error.
1175 : */
1176 :
1177 : void CPL_STDCALL
1178 : GDALCopyWords( void * pSrcData, GDALDataType eSrcType, int nSrcPixelOffset,
1179 : void * pDstData, GDALDataType eDstType, int nDstPixelOffset,
1180 2938570 : int nWordCount )
1181 :
1182 : {
1183 : // Deal with the case where we're replicating a single word into the
1184 : // provided buffer
1185 2938570 : if (nSrcPixelOffset == 0 && nWordCount > 1)
1186 : {
1187 3978 : GDALReplicateWord(pSrcData, eSrcType, pDstData, eDstType, nDstPixelOffset, nWordCount);
1188 3978 : return;
1189 : }
1190 :
1191 : #ifdef USE_NEW_COPYWORDS
1192 :
1193 2934592 : int nSrcDataTypeSize = GDALGetDataTypeSize(eSrcType) / 8;
1194 : // Let memcpy() handle the case where we're copying a packed buffer
1195 : // of pixels.
1196 2934592 : if (eSrcType == eDstType && nSrcPixelOffset == nDstPixelOffset &&
1197 : nSrcPixelOffset == nSrcDataTypeSize)
1198 : {
1199 12996 : memcpy(pDstData, pSrcData, nWordCount * nSrcDataTypeSize);
1200 12996 : return;
1201 : }
1202 :
1203 : // Handle the more general case -- deals with conversion of data types
1204 : // directly.
1205 2921596 : switch (eSrcType)
1206 : {
1207 : case GDT_Byte:
1208 : GDALCopyWordsFromT<unsigned char>(static_cast<unsigned char *>(pSrcData), nSrcPixelOffset, false,
1209 : pDstData, eDstType, nDstPixelOffset,
1210 780661 : nWordCount);
1211 780661 : break;
1212 : case GDT_UInt16:
1213 : GDALCopyWordsFromT<unsigned short>(static_cast<unsigned short *>(pSrcData), nSrcPixelOffset, false,
1214 : pDstData, eDstType, nDstPixelOffset,
1215 13269 : nWordCount);
1216 13269 : break;
1217 : case GDT_Int16:
1218 : GDALCopyWordsFromT<short>(static_cast<short *>(pSrcData), nSrcPixelOffset, false,
1219 : pDstData, eDstType, nDstPixelOffset,
1220 1190064 : nWordCount);
1221 1190064 : break;
1222 : case GDT_UInt32:
1223 : GDALCopyWordsFromT<unsigned int>(static_cast<unsigned int *>(pSrcData), nSrcPixelOffset, false,
1224 : pDstData, eDstType, nDstPixelOffset,
1225 1551 : nWordCount);
1226 1551 : break;
1227 : case GDT_Int32:
1228 : GDALCopyWordsFromT<int>(static_cast<int *>(pSrcData), nSrcPixelOffset, false,
1229 : pDstData, eDstType, nDstPixelOffset,
1230 155 : nWordCount);
1231 155 : break;
1232 : case GDT_Float32:
1233 : GDALCopyWordsFromT<float>(static_cast<float *>(pSrcData), nSrcPixelOffset, false,
1234 : pDstData, eDstType, nDstPixelOffset,
1235 761586 : nWordCount);
1236 761586 : break;
1237 : case GDT_Float64:
1238 : GDALCopyWordsFromT<double>(static_cast<double *>(pSrcData), nSrcPixelOffset, false,
1239 : pDstData, eDstType, nDstPixelOffset,
1240 4891 : nWordCount);
1241 4891 : break;
1242 : case GDT_CInt16:
1243 : GDALCopyWordsFromT<short>(static_cast<short *>(pSrcData), nSrcPixelOffset, true,
1244 : pDstData, eDstType, nDstPixelOffset,
1245 489 : nWordCount);
1246 489 : break;
1247 : case GDT_CInt32:
1248 : GDALCopyWordsFromT<int>(static_cast<int *>(pSrcData), nSrcPixelOffset, true,
1249 : pDstData, eDstType, nDstPixelOffset,
1250 143 : nWordCount);
1251 143 : break;
1252 : case GDT_CFloat32:
1253 : GDALCopyWordsFromT<float>(static_cast<float *>(pSrcData), nSrcPixelOffset, true,
1254 : pDstData, eDstType, nDstPixelOffset,
1255 657 : nWordCount);
1256 657 : break;
1257 : case GDT_CFloat64:
1258 : GDALCopyWordsFromT<double>(static_cast<double *>(pSrcData), nSrcPixelOffset, true,
1259 : pDstData, eDstType, nDstPixelOffset,
1260 168130 : nWordCount);
1261 168130 : break;
1262 : case GDT_Unknown:
1263 : default:
1264 0 : CPLAssert(FALSE);
1265 : }
1266 :
1267 : #else // undefined USE_NEW_COPYWORDS
1268 : /* -------------------------------------------------------------------- */
1269 : /* Special case when no data type translation is required. */
1270 : /* -------------------------------------------------------------------- */
1271 : if( eSrcType == eDstType )
1272 : {
1273 : int nWordSize = GDALGetDataTypeSize(eSrcType)/8;
1274 : int i;
1275 :
1276 : // contiguous blocks.
1277 : if( nWordSize == nSrcPixelOffset && nWordSize == nDstPixelOffset )
1278 : {
1279 : memcpy( pDstData, pSrcData, nSrcPixelOffset * nWordCount );
1280 : return;
1281 : }
1282 :
1283 : GByte *pabySrc = (GByte *) pSrcData;
1284 : GByte *pabyDst = (GByte *) pDstData;
1285 :
1286 : // Moving single bytes.
1287 : if( nWordSize == 1 )
1288 : {
1289 : if (nWordCount > 100)
1290 : {
1291 : /* ==================================================================== */
1292 : /* Optimization for high number of words to transfer and some */
1293 : /* typical source and destination pixel spacing : we unroll the */
1294 : /* loop. */
1295 : /* ==================================================================== */
1296 : #define ASSIGN(_nSrcPixelOffset, _nDstPixelOffset, _k) \
1297 : pabyDst[_nDstPixelOffset * _k] = pabySrc[_nSrcPixelOffset * _k]
1298 : #define ASSIGN_LOOP(_nSrcPixelOffset, _nDstPixelOffset) \
1299 : for( i = nWordCount / 16 ; i != 0; i-- ) \
1300 : { \
1301 : ASSIGN(_nSrcPixelOffset, _nDstPixelOffset, 0); \
1302 : ASSIGN(_nSrcPixelOffset, _nDstPixelOffset, 1); \
1303 : ASSIGN(_nSrcPixelOffset, _nDstPixelOffset, 2); \
1304 : ASSIGN(_nSrcPixelOffset, _nDstPixelOffset, 3); \
1305 : ASSIGN(_nSrcPixelOffset, _nDstPixelOffset, 4); \
1306 : ASSIGN(_nSrcPixelOffset, _nDstPixelOffset, 5); \
1307 : ASSIGN(_nSrcPixelOffset, _nDstPixelOffset, 6); \
1308 : ASSIGN(_nSrcPixelOffset, _nDstPixelOffset, 7); \
1309 : ASSIGN(_nSrcPixelOffset, _nDstPixelOffset, 8); \
1310 : ASSIGN(_nSrcPixelOffset, _nDstPixelOffset, 9); \
1311 : ASSIGN(_nSrcPixelOffset, _nDstPixelOffset, 10); \
1312 : ASSIGN(_nSrcPixelOffset, _nDstPixelOffset, 11); \
1313 : ASSIGN(_nSrcPixelOffset, _nDstPixelOffset, 12); \
1314 : ASSIGN(_nSrcPixelOffset, _nDstPixelOffset, 13); \
1315 : ASSIGN(_nSrcPixelOffset, _nDstPixelOffset, 14); \
1316 : ASSIGN(_nSrcPixelOffset, _nDstPixelOffset, 15); \
1317 : pabyDst += _nDstPixelOffset * 16; \
1318 : pabySrc += _nSrcPixelOffset * 16; \
1319 : } \
1320 : nWordCount = nWordCount % 16;
1321 :
1322 : if (nSrcPixelOffset == 3 && nDstPixelOffset == 1)
1323 : {
1324 : ASSIGN_LOOP(3, 1)
1325 : }
1326 : else if (nSrcPixelOffset == 1 && nDstPixelOffset == 3)
1327 : {
1328 : ASSIGN_LOOP(1, 3)
1329 : }
1330 : else if (nSrcPixelOffset == 4 && nDstPixelOffset == 1)
1331 : {
1332 : ASSIGN_LOOP(4, 1)
1333 : }
1334 : else if (nSrcPixelOffset == 1 && nDstPixelOffset == 4)
1335 : {
1336 : ASSIGN_LOOP(1, 4)
1337 : }
1338 : else if (nSrcPixelOffset == 3 && nDstPixelOffset == 4)
1339 : {
1340 : ASSIGN_LOOP(3, 4)
1341 : }
1342 : else if (nSrcPixelOffset == 4 && nDstPixelOffset == 3)
1343 : {
1344 : ASSIGN_LOOP(4, 3)
1345 : }
1346 : }
1347 :
1348 : for( i = nWordCount; i != 0; i-- )
1349 : {
1350 : *pabyDst = *pabySrc;
1351 : pabyDst += nDstPixelOffset;
1352 : pabySrc += nSrcPixelOffset;
1353 : }
1354 : }
1355 : else if (nWordSize == 2)
1356 : {
1357 : for( i = nWordCount; i != 0; i-- )
1358 : {
1359 : *(short*)pabyDst = *(short*)pabySrc;
1360 : pabyDst += nDstPixelOffset;
1361 : pabySrc += nSrcPixelOffset;
1362 : }
1363 : }
1364 : else if (nWordSize == 4)
1365 : {
1366 : for( i = nWordCount; i != 0; i-- )
1367 : {
1368 : *(int*)pabyDst = *(int*)pabySrc;
1369 : pabyDst += nDstPixelOffset;
1370 : pabySrc += nSrcPixelOffset;
1371 : }
1372 : }
1373 : else if (nWordSize == 8)
1374 : {
1375 : for( i = nWordCount; i != 0; i-- )
1376 : {
1377 : ((int*)pabyDst)[0] = ((int*)pabySrc)[0];
1378 : ((int*)pabyDst)[1] = ((int*)pabySrc)[1];
1379 : pabyDst += nDstPixelOffset;
1380 : pabySrc += nSrcPixelOffset;
1381 : }
1382 : }
1383 : else if (nWordSize == 16)
1384 : {
1385 : for( i = nWordCount; i != 0; i-- )
1386 : {
1387 : ((int*)pabyDst)[0] = ((int*)pabySrc)[0];
1388 : ((int*)pabyDst)[1] = ((int*)pabySrc)[1];
1389 : ((int*)pabyDst)[2] = ((int*)pabySrc)[2];
1390 : ((int*)pabyDst)[3] = ((int*)pabySrc)[3];
1391 : pabyDst += nDstPixelOffset;
1392 : pabySrc += nSrcPixelOffset;
1393 : }
1394 : }
1395 : else
1396 : {
1397 : CPLAssert(FALSE);
1398 : }
1399 :
1400 : return;
1401 : }
1402 :
1403 : /* ==================================================================== */
1404 : /* General translation case */
1405 : /* ==================================================================== */
1406 : for( int iWord = 0; iWord < nWordCount; iWord++ )
1407 : {
1408 : void *pSrcWord, *pDstWord;
1409 : double dfPixelValue=0.0, dfPixelValueI=0.0;
1410 :
1411 : pSrcWord = static_cast<GByte *>(pSrcData) + iWord * nSrcPixelOffset;
1412 : pDstWord = static_cast<GByte *>(pDstData) + iWord * nDstPixelOffset;
1413 :
1414 : /* -------------------------------------------------------------------- */
1415 : /* Fetch source value based on data type. */
1416 : /* -------------------------------------------------------------------- */
1417 : switch( eSrcType )
1418 : {
1419 : case GDT_Byte:
1420 : {
1421 : GByte byVal = *static_cast<GByte *>(pSrcWord);
1422 : switch( eDstType )
1423 : {
1424 : case GDT_UInt16:
1425 : *static_cast<GUInt16 *>(pDstWord) = byVal;
1426 : continue;
1427 : case GDT_Int16:
1428 : *static_cast<GInt16 *>(pDstWord) = byVal;
1429 : continue;
1430 : case GDT_UInt32:
1431 : *static_cast<GUInt32 *>(pDstWord) = byVal;
1432 : continue;
1433 : case GDT_Int32:
1434 : *static_cast<GInt32 *>(pDstWord) = byVal;
1435 : continue;
1436 : case GDT_CInt16:
1437 : {
1438 : GInt16 *panDstWord = static_cast<GInt16 *>(pDstWord);
1439 : panDstWord[0] = byVal;
1440 : panDstWord[1] = 0;
1441 : continue;
1442 : }
1443 : case GDT_CInt32:
1444 : {
1445 : GInt32 *panDstWord = static_cast<GInt32 *>(pDstWord);
1446 : panDstWord[0] = byVal;
1447 : panDstWord[1] = 0;
1448 : continue;
1449 : }
1450 : default:
1451 : break;
1452 : }
1453 : dfPixelValue = byVal;
1454 : }
1455 : break;
1456 :
1457 : case GDT_UInt16:
1458 : {
1459 : GUInt16 nVal = *static_cast<GUInt16 *>(pSrcWord);
1460 : switch( eDstType )
1461 : {
1462 : case GDT_Byte:
1463 : {
1464 : GByte byVal;
1465 : if( nVal > 255 )
1466 : byVal = 255;
1467 : else
1468 : byVal = static_cast<GByte>(nVal);
1469 : *static_cast<GByte *>(pDstWord) = byVal;
1470 : continue;
1471 : }
1472 : case GDT_Int16:
1473 : if( nVal > 32767 )
1474 : nVal = 32767;
1475 : *static_cast<GInt16 *>(pDstWord) = nVal;
1476 : continue;
1477 : case GDT_UInt32:
1478 : *static_cast<GUInt32 *>(pDstWord) = nVal;
1479 : continue;
1480 : case GDT_Int32:
1481 : *static_cast<GInt32 *>(pDstWord) = nVal;
1482 : continue;
1483 : case GDT_CInt16:
1484 : {
1485 : GInt16 *panDstWord = static_cast<GInt16 *>(pDstWord);
1486 : if( nVal > 32767 )
1487 : nVal = 32767;
1488 : panDstWord[0] = nVal;
1489 : panDstWord[1] = 0;
1490 : continue;
1491 : }
1492 : case GDT_CInt32:
1493 : {
1494 : GInt32 *panDstWord = static_cast<GInt32 *>(pDstWord);
1495 : panDstWord[0] = nVal;
1496 : panDstWord[1] = 0;
1497 : continue;
1498 : }
1499 : default:
1500 : break;
1501 : }
1502 : dfPixelValue = nVal;
1503 : }
1504 : break;
1505 :
1506 : case GDT_Int16:
1507 : {
1508 : GInt16 nVal = *static_cast<GInt16 *>(pSrcWord);
1509 : switch( eDstType )
1510 : {
1511 : case GDT_Byte:
1512 : {
1513 : GByte byVal;
1514 : if( nVal > 255 )
1515 : byVal = 255;
1516 : else if (nVal < 0)
1517 : byVal = 0;
1518 : else
1519 : byVal = static_cast<GByte>(nVal);
1520 : *static_cast<GByte *>(pDstWord) = byVal;
1521 : continue;
1522 : }
1523 : case GDT_UInt16:
1524 : if( nVal < 0 )
1525 : nVal = 0;
1526 : *static_cast<GUInt16 *>(pDstWord) = nVal;
1527 : continue;
1528 : case GDT_UInt32:
1529 : if( nVal < 0 )
1530 : nVal = 0;
1531 : *static_cast<GUInt32 *>(pDstWord) = nVal;
1532 : continue;
1533 : case GDT_Int32:
1534 : *static_cast<GInt32 *>(pDstWord) = nVal;
1535 : continue;
1536 : case GDT_CInt16:
1537 : {
1538 : GInt16 *panDstWord = static_cast<GInt16 *>(pDstWord);
1539 : panDstWord[0] = nVal;
1540 : panDstWord[1] = 0;
1541 : continue;
1542 : }
1543 : case GDT_CInt32:
1544 : {
1545 : GInt32 *panDstWord = static_cast<GInt32 *>(pDstWord);
1546 : panDstWord[0] = nVal;
1547 : panDstWord[1] = 0;
1548 : continue;
1549 : }
1550 : default:
1551 : break;
1552 : }
1553 : dfPixelValue = nVal;
1554 : }
1555 : break;
1556 :
1557 : case GDT_Int32:
1558 : {
1559 : GInt32 nVal = *static_cast<GInt32 *>(pSrcWord);
1560 : switch( eDstType )
1561 : {
1562 : case GDT_Byte:
1563 : {
1564 : GByte byVal;
1565 : if( nVal > 255 )
1566 : byVal = 255;
1567 : else if (nVal < 0)
1568 : byVal = 0;
1569 : else
1570 : byVal = nVal;
1571 : *static_cast<GByte *>(pDstWord) = byVal;
1572 : continue;
1573 : }
1574 : case GDT_UInt16:
1575 : if( nVal > 65535 )
1576 : nVal = 65535;
1577 : else if( nVal < 0 )
1578 : nVal = 0;
1579 : *static_cast<GUInt16 *>(pDstWord) = nVal;
1580 : continue;
1581 : case GDT_Int16:
1582 : if( nVal > 32767 )
1583 : nVal = 32767;
1584 : else if( nVal < -32768)
1585 : nVal = -32768;
1586 : *static_cast<GInt16 *>(pDstWord) = nVal;
1587 : continue;
1588 : case GDT_UInt32:
1589 : if( nVal < 0 )
1590 : nVal = 0;
1591 : *static_cast<GUInt32 *>(pDstWord) = nVal;
1592 : continue;
1593 : case GDT_CInt16:
1594 : {
1595 : GInt16 *panDstWord = static_cast<GInt16 *>(pDstWord);
1596 : if( nVal > 32767 )
1597 : nVal = 32767;
1598 : else if( nVal < -32768)
1599 : nVal = -32768;
1600 : panDstWord[0] = nVal;
1601 : panDstWord[1] = 0;
1602 : continue;
1603 : }
1604 : case GDT_CInt32:
1605 : {
1606 : GInt32 *panDstWord = static_cast<GInt32 *>(pDstWord);
1607 : panDstWord[0] = nVal;
1608 : panDstWord[1] = 0;
1609 : continue;
1610 : }
1611 : default:
1612 : break;
1613 : }
1614 : dfPixelValue = nVal;
1615 : }
1616 : break;
1617 :
1618 : case GDT_UInt32:
1619 : {
1620 : GUInt32 nVal = *static_cast<GUInt32 *>(pSrcWord);
1621 : switch( eDstType )
1622 : {
1623 : case GDT_Byte:
1624 : {
1625 : GByte byVal;
1626 : if( nVal > 255 )
1627 : byVal = 255;
1628 : else
1629 : byVal = nVal;
1630 : *static_cast<GByte *>(pDstWord) = byVal;
1631 : continue;
1632 : }
1633 : case GDT_UInt16:
1634 : if( nVal > 65535 )
1635 : nVal = 65535;
1636 : *static_cast<GUInt16 *>(pDstWord) = nVal;
1637 : continue;
1638 : case GDT_Int16:
1639 : if( nVal > 32767 )
1640 : nVal = 32767;
1641 : *static_cast<GInt16 *>(pDstWord) = nVal;
1642 : continue;
1643 : case GDT_Int32:
1644 : if( nVal > 2147483647UL )
1645 : nVal = 2147483647UL;
1646 : *static_cast<GInt32 *>(pDstWord) = nVal;
1647 : continue;
1648 : case GDT_CInt16:
1649 : {
1650 : GInt16 *panDstWord = static_cast<GInt16 *>(pDstWord);
1651 : if( nVal > 32767 )
1652 : nVal = 32767;
1653 : panDstWord[0] = nVal;
1654 : panDstWord[1] = 0;
1655 : continue;
1656 : }
1657 : case GDT_CInt32:
1658 : {
1659 : GInt32 *panDstWord = static_cast<GInt32 *>(pDstWord);
1660 : if( nVal > 2147483647UL )
1661 : nVal = 2147483647UL;
1662 : panDstWord[0] = nVal;
1663 : panDstWord[1] = 0;
1664 : continue;
1665 : }
1666 : default:
1667 : break;
1668 : }
1669 : dfPixelValue = nVal;
1670 : }
1671 : break;
1672 :
1673 : case GDT_CInt16:
1674 : {
1675 : GInt16 *panSrcWord = static_cast<GInt16 *>(pSrcWord);
1676 : GInt16 nVal = panSrcWord[0];
1677 : switch( eDstType )
1678 : {
1679 : case GDT_Byte:
1680 : {
1681 : GByte byVal;
1682 : if( nVal > 255 )
1683 : byVal = 255;
1684 : else if (nVal < 0)
1685 : byVal = 0;
1686 : else
1687 : byVal = static_cast<GByte>(nVal);
1688 : *static_cast<GByte *>(pDstWord) = byVal;
1689 : continue;
1690 : }
1691 : case GDT_Int16:
1692 : *static_cast<GInt16 *>(pDstWord) = nVal;
1693 : continue;
1694 : case GDT_UInt16:
1695 : if( nVal < 0 )
1696 : nVal = 0;
1697 : *static_cast<GUInt16 *>(pDstWord) = nVal;
1698 : continue;
1699 : case GDT_UInt32:
1700 : if( nVal < 0 )
1701 : nVal = 0;
1702 : *static_cast<GUInt32 *>(pDstWord) = nVal;
1703 : continue;
1704 : case GDT_Int32:
1705 : *static_cast<GInt32 *>(pDstWord) = nVal;
1706 : continue;
1707 : case GDT_CInt32:
1708 : {
1709 : GInt32 *panDstWord = static_cast<GInt32 *>(pDstWord);
1710 : panDstWord[0] = panSrcWord[0];
1711 : panDstWord[1] = panSrcWord[1];
1712 : continue;
1713 : }
1714 : default:
1715 : break;
1716 : }
1717 : dfPixelValue = panSrcWord[0];
1718 : dfPixelValueI = panSrcWord[1];
1719 : }
1720 : break;
1721 :
1722 : case GDT_CInt32:
1723 : {
1724 : GInt32 *panSrcWord = static_cast<GInt32 *>(pSrcWord);
1725 : GInt32 nVal = panSrcWord[0];
1726 : switch( eDstType )
1727 : {
1728 : case GDT_Byte:
1729 : {
1730 : GByte byVal;
1731 : if( nVal > 255 )
1732 : byVal = 255;
1733 : else if (nVal < 0)
1734 : byVal = 0;
1735 : else
1736 : byVal = nVal;
1737 : *static_cast<GByte *>(pDstWord) = byVal;
1738 : continue;
1739 : }
1740 : case GDT_Int16:
1741 : if( nVal > 32767 )
1742 : nVal = 32767;
1743 : else if( nVal < -32768)
1744 : nVal = -32768;
1745 : *static_cast<GInt16 *>(pDstWord) = nVal;
1746 : continue;
1747 : case GDT_UInt16:
1748 : if( nVal > 65535 )
1749 : nVal = 65535;
1750 : else if( nVal < 0 )
1751 : nVal = 0;
1752 : *static_cast<GUInt16 *>(pDstWord) = nVal;
1753 : continue;
1754 : case GDT_UInt32:
1755 : if( nVal < 0 )
1756 : nVal = 0;
1757 : *static_cast<GUInt32 *>(pDstWord) = nVal;
1758 : continue;
1759 : case GDT_Int32:
1760 : *static_cast<GInt32 *>(pDstWord) = nVal;
1761 : continue;
1762 : case GDT_CInt16:
1763 : {
1764 : GInt16 *panDstWord = static_cast<GInt16 *>(pDstWord);
1765 : if( nVal > 32767 )
1766 : nVal = 32767;
1767 : else if( nVal < -32768)
1768 : nVal = -32768;
1769 : panDstWord[0] = nVal;
1770 : nVal = panSrcWord[1];
1771 : if( nVal > 32767 )
1772 : nVal = 32767;
1773 : else if( nVal < -32768)
1774 : nVal = -32768;
1775 : panDstWord[1] = nVal;
1776 : continue;
1777 : }
1778 : default:
1779 : break;
1780 : }
1781 : dfPixelValue = panSrcWord[0];
1782 : dfPixelValueI = panSrcWord[1];
1783 : }
1784 : break;
1785 :
1786 : case GDT_Float32:
1787 : {
1788 : float fVal = *static_cast<float *>(pSrcWord);
1789 : dfPixelValue = fVal;
1790 : }
1791 : break;
1792 :
1793 : case GDT_Float64:
1794 : {
1795 : dfPixelValue = *static_cast<double *>(pSrcWord);
1796 : }
1797 : break;
1798 :
1799 : case GDT_CFloat32:
1800 : {
1801 : float *pafSrcWord = static_cast<float *>(pSrcWord);
1802 : dfPixelValue = pafSrcWord[0];
1803 : dfPixelValueI = pafSrcWord[1];
1804 : }
1805 : break;
1806 :
1807 : case GDT_CFloat64:
1808 : {
1809 : double *padfSrcWord = static_cast<double *>(pSrcWord);
1810 : dfPixelValue = padfSrcWord[0];
1811 : dfPixelValueI = padfSrcWord[1];
1812 : }
1813 : break;
1814 :
1815 : default:
1816 : CPLAssert( FALSE );
1817 : }
1818 :
1819 : /* -------------------------------------------------------------------- */
1820 : /* Set the destination pixel, doing range clipping as needed. */
1821 : /* -------------------------------------------------------------------- */
1822 : switch( eDstType )
1823 : {
1824 : case GDT_Byte:
1825 : {
1826 : GByte *pabyDstWord = static_cast<GByte *>(pDstWord);
1827 :
1828 : dfPixelValue += (float) 0.5;
1829 :
1830 : if( dfPixelValue < 0.0 )
1831 : *pabyDstWord = 0;
1832 : else if( dfPixelValue > 255.0 )
1833 : *pabyDstWord = 255;
1834 : else
1835 : *pabyDstWord = (GByte) dfPixelValue;
1836 : }
1837 : break;
1838 :
1839 : case GDT_UInt16:
1840 : {
1841 : GUInt16 nVal;
1842 :
1843 : dfPixelValue += 0.5;
1844 :
1845 : if( dfPixelValue < 0.0 )
1846 : nVal = 0;
1847 : else if( dfPixelValue > 65535.0 )
1848 : nVal = 65535;
1849 : else
1850 : nVal = (GUInt16) dfPixelValue;
1851 :
1852 : *static_cast<GUInt16 *>(pDstWord) = nVal;
1853 : }
1854 : break;
1855 :
1856 : case GDT_Int16:
1857 : {
1858 : GInt16 nVal;
1859 :
1860 : dfPixelValue += 0.5;
1861 :
1862 : if( dfPixelValue < -32768 )
1863 : nVal = -32768;
1864 : else if( dfPixelValue > 32767 )
1865 : nVal = 32767;
1866 : else
1867 : nVal = (GInt16) floor(dfPixelValue);
1868 :
1869 : *static_cast<GInt16 *>(pDstWord) = nVal;
1870 : }
1871 : break;
1872 :
1873 : case GDT_UInt32:
1874 : {
1875 : GUInt32 nVal;
1876 :
1877 : dfPixelValue += 0.5;
1878 :
1879 : if( dfPixelValue < 0 )
1880 : nVal = 0;
1881 : else if( dfPixelValue > 4294967295U )
1882 : nVal = 4294967295U;
1883 : else
1884 : nVal = (GInt32) dfPixelValue;
1885 :
1886 : *static_cast<GUInt32 *>(pDstWord) = nVal;
1887 : }
1888 : break;
1889 :
1890 : case GDT_Int32:
1891 : {
1892 : GInt32 nVal;
1893 :
1894 : dfPixelValue += 0.5;
1895 :
1896 : if( dfPixelValue < -2147483648.0 )
1897 : nVal = INT_MIN;
1898 : else if( dfPixelValue > 2147483647 )
1899 : nVal = 2147483647;
1900 : else
1901 : nVal = (GInt32) floor(dfPixelValue);
1902 :
1903 : *static_cast<GInt32 *>(pDstWord) = nVal;
1904 : }
1905 : break;
1906 :
1907 : case GDT_Float32:
1908 : {
1909 : *static_cast<float *>(pDstWord) = static_cast<float>(dfPixelValue);
1910 : }
1911 : break;
1912 :
1913 : case GDT_Float64:
1914 : *static_cast<double *>(pDstWord) = dfPixelValue;
1915 : break;
1916 :
1917 : case GDT_CInt16:
1918 : {
1919 : GInt16 nVal;
1920 : GInt16 *panDstWord = static_cast<GInt16 *>(pDstWord);
1921 :
1922 : dfPixelValue += 0.5;
1923 : dfPixelValueI += 0.5;
1924 :
1925 : if( dfPixelValue < -32768 )
1926 : nVal = -32768;
1927 : else if( dfPixelValue > 32767 )
1928 : nVal = 32767;
1929 : else
1930 : nVal = (GInt16) floor(dfPixelValue);
1931 : panDstWord[0] = nVal;
1932 :
1933 : if( dfPixelValueI < -32768 )
1934 : nVal = -32768;
1935 : else if( dfPixelValueI > 32767 )
1936 : nVal = 32767;
1937 : else
1938 : nVal = (GInt16) floor(dfPixelValueI);
1939 : panDstWord[1] = nVal;
1940 : }
1941 : break;
1942 :
1943 : case GDT_CInt32:
1944 : {
1945 : GInt32 nVal;
1946 : GInt32 *panDstWord = static_cast<GInt32 *>(pDstWord);
1947 :
1948 : dfPixelValue += 0.5;
1949 : dfPixelValueI += 0.5;
1950 :
1951 : if( dfPixelValue < -2147483648.0 )
1952 : nVal = INT_MIN;
1953 : else if( dfPixelValue > 2147483647 )
1954 : nVal = 2147483647;
1955 : else
1956 : nVal = (GInt32) floor(dfPixelValue);
1957 :
1958 : panDstWord[0] = nVal;
1959 :
1960 : if( dfPixelValueI < -2147483648.0 )
1961 : nVal = INT_MIN;
1962 : else if( dfPixelValueI > 2147483647 )
1963 : nVal = 2147483647;
1964 : else
1965 : nVal = (GInt32) floor(dfPixelValueI);
1966 :
1967 : panDstWord[1] = nVal;
1968 : }
1969 : break;
1970 :
1971 : case GDT_CFloat32:
1972 : {
1973 : float *pafDstWord = static_cast<float *>(pDstWord);
1974 : pafDstWord[0] = static_cast<float>(dfPixelValue);
1975 : pafDstWord[1] = static_cast<float>(dfPixelValueI);
1976 : }
1977 : break;
1978 :
1979 : case GDT_CFloat64:
1980 : {
1981 : double *padfDstWord = static_cast<double *>(pDstWord);
1982 : padfDstWord[0] = dfPixelValue;
1983 : padfDstWord[1] = dfPixelValueI;
1984 : }
1985 : break;
1986 :
1987 : default:
1988 : CPLAssert( FALSE );
1989 : }
1990 : } /* next iWord */
1991 : #endif // defined USE_NEW_COPYWORDS
1992 : }
1993 :
1994 : /************************************************************************/
1995 : /* GDALCopyBits() */
1996 : /************************************************************************/
1997 :
1998 : /**
1999 : * Bitwise word copying.
2000 : *
2001 : * A function for moving sets of partial bytes around. Loosely
2002 : * speaking this is a bitswise analog to GDALCopyWords().
2003 : *
2004 : * It copies nStepCount "words" where each word is nBitCount bits long.
2005 : * The nSrcStep and nDstStep are the number of bits from the start of one
2006 : * word to the next (same as nBitCount if they are packed). The nSrcOffset
2007 : * and nDstOffset are the offset into the source and destination buffers
2008 : * to start at, also measured in bits.
2009 : *
2010 : * All bit offsets are assumed to start from the high order bit in a byte
2011 : * (ie. most significant bit first). Currently this function is not very
2012 : * optimized, but it may be improved for some common cases in the future
2013 : * as needed.
2014 : *
2015 : * @param pabySrcData the source data buffer.
2016 : * @param nSrcOffset the offset (in bits) in pabySrcData to the start of the
2017 : * first word to copy.
2018 : * @param nSrcStep the offset in bits from the start one source word to the
2019 : * start of the next.
2020 : * @param pabyDstData the destination data buffer.
2021 : * @param nDstOffset the offset (in bits) in pabyDstData to the start of the
2022 : * first word to copy over.
2023 : * @param nDstStep the offset in bits from the start one word to the
2024 : * start of the next.
2025 : * @param nBitCount the number of bits in a word to be copied.
2026 : * @param nStepCount the number of words to copy.
2027 : */
2028 :
2029 : void GDALCopyBits( const GByte *pabySrcData, int nSrcOffset, int nSrcStep,
2030 : GByte *pabyDstData, int nDstOffset, int nDstStep,
2031 0 : int nBitCount, int nStepCount )
2032 :
2033 : {
2034 0 : VALIDATE_POINTER0( pabySrcData, "GDALCopyBits" );
2035 :
2036 : int iStep;
2037 : int iBit;
2038 :
2039 0 : for( iStep = 0; iStep < nStepCount; iStep++ )
2040 : {
2041 0 : for( iBit = 0; iBit < nBitCount; iBit++ )
2042 : {
2043 0 : if( pabySrcData[nSrcOffset>>3]
2044 : & (0x80 >>(nSrcOffset & 7)) )
2045 0 : pabyDstData[nDstOffset>>3] |= (0x80 >> (nDstOffset & 7));
2046 : else
2047 0 : pabyDstData[nDstOffset>>3] &= ~(0x80 >> (nDstOffset & 7));
2048 :
2049 :
2050 0 : nSrcOffset++;
2051 0 : nDstOffset++;
2052 : }
2053 :
2054 0 : nSrcOffset += (nSrcStep - nBitCount);
2055 0 : nDstOffset += (nDstStep - nBitCount);
2056 : }
2057 : }
2058 :
2059 : /************************************************************************/
2060 : /* GDALGetBestOverviewLevel() */
2061 : /* */
2062 : /* Returns the best overview level to satisfy the query or -1 if none */
2063 : /* Also updates nXOff, nYOff, nXSize, nYSize when returning a valid */
2064 : /* overview level */
2065 : /************************************************************************/
2066 :
2067 : int GDALBandGetBestOverviewLevel(GDALRasterBand* poBand,
2068 : int &nXOff, int &nYOff,
2069 : int &nXSize, int &nYSize,
2070 11 : int nBufXSize, int nBufYSize)
2071 : {
2072 : double dfDesiredResolution;
2073 : /* -------------------------------------------------------------------- */
2074 : /* Compute the desired resolution. The resolution is */
2075 : /* based on the least reduced axis, and represents the number */
2076 : /* of source pixels to one destination pixel. */
2077 : /* -------------------------------------------------------------------- */
2078 11 : if( (nXSize / (double) nBufXSize) < (nYSize / (double) nBufYSize )
2079 : || nBufYSize == 1 )
2080 0 : dfDesiredResolution = nXSize / (double) nBufXSize;
2081 : else
2082 11 : dfDesiredResolution = nYSize / (double) nBufYSize;
2083 :
2084 : /* -------------------------------------------------------------------- */
2085 : /* Find the overview level that largest resolution value (most */
2086 : /* downsampled) that is still less than (or only a little more) */
2087 : /* downsampled than the request. */
2088 : /* -------------------------------------------------------------------- */
2089 11 : int nOverviewCount = poBand->GetOverviewCount();
2090 11 : GDALRasterBand* poBestOverview = NULL;
2091 11 : double dfBestResolution = 0;
2092 11 : int nBestOverviewLevel = -1;
2093 :
2094 26 : for( int iOverview = 0; iOverview < nOverviewCount; iOverview++ )
2095 : {
2096 15 : GDALRasterBand *poOverview = poBand->GetOverview( iOverview );
2097 15 : if (poOverview == NULL)
2098 0 : continue;
2099 :
2100 : double dfResolution;
2101 :
2102 : // What resolution is this?
2103 15 : if( (poBand->GetXSize() / (double) poOverview->GetXSize())
2104 : < (poBand->GetYSize() / (double) poOverview->GetYSize()) )
2105 : dfResolution =
2106 0 : poBand->GetXSize() / (double) poOverview->GetXSize();
2107 : else
2108 : dfResolution =
2109 15 : poBand->GetYSize() / (double) poOverview->GetYSize();
2110 :
2111 : // Is it nearly the requested resolution and better (lower) than
2112 : // the current best resolution?
2113 15 : if( dfResolution >= dfDesiredResolution * 1.2
2114 : || dfResolution <= dfBestResolution )
2115 0 : continue;
2116 :
2117 : // Ignore AVERAGE_BIT2GRAYSCALE overviews for RasterIO purposes.
2118 : const char *pszResampling =
2119 15 : poOverview->GetMetadataItem( "RESAMPLING" );
2120 :
2121 15 : if( pszResampling != NULL && EQUALN(pszResampling,"AVERAGE_BIT2",12))
2122 8 : continue;
2123 :
2124 : // OK, this is our new best overview.
2125 7 : poBestOverview = poOverview;
2126 7 : nBestOverviewLevel = iOverview;
2127 7 : dfBestResolution = dfResolution;
2128 : }
2129 :
2130 : /* -------------------------------------------------------------------- */
2131 : /* If we didn't find an overview that helps us, just return */
2132 : /* indicating failure and the full resolution image will be used. */
2133 : /* -------------------------------------------------------------------- */
2134 11 : if( nBestOverviewLevel < 0 )
2135 4 : return -1;
2136 :
2137 : /* -------------------------------------------------------------------- */
2138 : /* Recompute the source window in terms of the selected */
2139 : /* overview. */
2140 : /* -------------------------------------------------------------------- */
2141 : int nOXOff, nOYOff, nOXSize, nOYSize;
2142 : double dfXRes, dfYRes;
2143 :
2144 7 : dfXRes = poBand->GetXSize() / (double) poBestOverview->GetXSize();
2145 7 : dfYRes = poBand->GetYSize() / (double) poBestOverview->GetYSize();
2146 :
2147 7 : nOXOff = MIN(poBestOverview->GetXSize()-1,(int) (nXOff/dfXRes+0.5));
2148 7 : nOYOff = MIN(poBestOverview->GetYSize()-1,(int) (nYOff/dfYRes+0.5));
2149 7 : nOXSize = MAX(1,(int) (nXSize/dfXRes + 0.5));
2150 7 : nOYSize = MAX(1,(int) (nYSize/dfYRes + 0.5));
2151 7 : if( nOXOff + nOXSize > poBestOverview->GetXSize() )
2152 0 : nOXSize = poBestOverview->GetXSize() - nOXOff;
2153 7 : if( nOYOff + nOYSize > poBestOverview->GetYSize() )
2154 0 : nOYSize = poBestOverview->GetYSize() - nOYOff;
2155 :
2156 7 : nXOff = nOXOff;
2157 7 : nYOff = nOYOff;
2158 7 : nXSize = nOXSize;
2159 7 : nYSize = nOYSize;
2160 :
2161 7 : return nBestOverviewLevel;
2162 : }
2163 :
2164 :
2165 : /************************************************************************/
2166 : /* OverviewRasterIO() */
2167 : /* */
2168 : /* Special work function to utilize available overviews to */
2169 : /* more efficiently satisfy downsampled requests. It will */
2170 : /* return CE_Failure if there are no appropriate overviews */
2171 : /* available but it doesn't emit any error messages. */
2172 : /************************************************************************/
2173 :
2174 : CPLErr GDALRasterBand::OverviewRasterIO( GDALRWFlag eRWFlag,
2175 : int nXOff, int nYOff, int nXSize, int nYSize,
2176 : void * pData, int nBufXSize, int nBufYSize,
2177 : GDALDataType eBufType,
2178 9 : int nPixelSpace, int nLineSpace )
2179 :
2180 :
2181 : {
2182 : int nOverview;
2183 :
2184 : nOverview =
2185 : GDALBandGetBestOverviewLevel(this, nXOff, nYOff, nXSize, nYSize,
2186 9 : nBufXSize, nBufYSize);
2187 9 : if (nOverview < 0)
2188 4 : return CE_Failure;
2189 :
2190 : /* -------------------------------------------------------------------- */
2191 : /* Recast the call in terms of the new raster layer. */
2192 : /* -------------------------------------------------------------------- */
2193 5 : GDALRasterBand* poOverviewBand = GetOverview(nOverview);
2194 5 : if (poOverviewBand == NULL)
2195 0 : return CE_Failure;
2196 :
2197 : return poOverviewBand->RasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
2198 : pData, nBufXSize, nBufYSize, eBufType,
2199 5 : nPixelSpace, nLineSpace );
2200 : }
2201 :
2202 : /************************************************************************/
2203 : /* GetBestOverviewLevel() */
2204 : /* */
2205 : /* Returns the best overview level to satisfy the query or -1 if none */
2206 : /* Also updates nXOff, nYOff, nXSize, nYSize when returning a valid */
2207 : /* overview level */
2208 : /************************************************************************/
2209 :
2210 : static
2211 : int GDALDatasetGetBestOverviewLevel(GDALDataset* poDS,
2212 : int &nXOff, int &nYOff,
2213 : int &nXSize, int &nYSize,
2214 : int nBufXSize, int nBufYSize,
2215 2 : int nBandCount, int *panBandMap)
2216 : {
2217 : int iBand, iOverview;
2218 2 : int nOverviewCount = 0;
2219 2 : GDALRasterBand *poFirstBand = NULL;
2220 :
2221 2 : if (nBandCount == 0)
2222 0 : return -1;
2223 :
2224 : /* -------------------------------------------------------------------- */
2225 : /* Check that all bands have the same number of overviews and */
2226 : /* that they have all the same size and block dimensions */
2227 : /* -------------------------------------------------------------------- */
2228 4 : for( iBand = 0; iBand < nBandCount; iBand++ )
2229 : {
2230 2 : GDALRasterBand *poBand = poDS->GetRasterBand( panBandMap[iBand] );
2231 2 : if (iBand == 0)
2232 : {
2233 2 : poFirstBand = poBand;
2234 2 : nOverviewCount = poBand->GetOverviewCount();
2235 : }
2236 0 : else if (nOverviewCount != poBand->GetOverviewCount())
2237 : {
2238 : CPLDebug( "GDAL",
2239 : "GDALDataset::GetBestOverviewLevel() ... "
2240 0 : "mismatched overview count, use std method." );
2241 0 : return -1;
2242 : }
2243 : else
2244 : {
2245 0 : for(iOverview = 0; iOverview < nOverviewCount; iOverview++)
2246 : {
2247 : GDALRasterBand* poOvrBand =
2248 0 : poBand->GetOverview(iOverview);
2249 : GDALRasterBand* poOvrFirstBand =
2250 0 : poFirstBand->GetOverview(iOverview);
2251 0 : if ( poOvrBand == NULL || poOvrFirstBand == NULL)
2252 0 : continue;
2253 :
2254 0 : if ( poOvrFirstBand->GetXSize() != poOvrBand->GetXSize() ||
2255 : poOvrFirstBand->GetYSize() != poOvrBand->GetYSize() )
2256 : {
2257 : CPLDebug( "GDAL",
2258 : "GDALDataset::GetBestOverviewLevel() ... "
2259 0 : "mismatched overview sizes, use std method." );
2260 0 : return -1;
2261 : }
2262 0 : int nBlockXSizeFirst=0, nBlockYSizeFirst=0;
2263 0 : int nBlockXSizeCurrent=0, nBlockYSizeCurrent=0;
2264 0 : poOvrFirstBand->GetBlockSize(&nBlockXSizeFirst, &nBlockYSizeFirst);
2265 0 : poOvrBand->GetBlockSize(&nBlockXSizeCurrent, &nBlockYSizeCurrent);
2266 0 : if (nBlockXSizeFirst != nBlockXSizeCurrent ||
2267 : nBlockYSizeFirst != nBlockYSizeCurrent)
2268 : {
2269 : CPLDebug( "GDAL",
2270 : "GDALDataset::GetBestOverviewLevel() ... "
2271 0 : "mismatched block sizes, use std method." );
2272 0 : return -1;
2273 : }
2274 : }
2275 : }
2276 : }
2277 :
2278 : return GDALBandGetBestOverviewLevel(poFirstBand,
2279 : nXOff, nYOff, nXSize, nYSize,
2280 2 : nBufXSize, nBufYSize);
2281 : }
2282 :
2283 : /************************************************************************/
2284 : /* BlockBasedRasterIO() */
2285 : /* */
2286 : /* This convenience function implements a dataset level */
2287 : /* RasterIO() interface based on calling down to fetch blocks, */
2288 : /* much like the GDALRasterBand::IRasterIO(), but it handles */
2289 : /* all bands at once, so that a format driver that handles a */
2290 : /* request for different bands of the same block efficiently */
2291 : /* (ie. without re-reading interleaved data) will efficiently. */
2292 : /* */
2293 : /* This method is intended to be called by an overridden */
2294 : /* IRasterIO() method in the driver specific GDALDataset */
2295 : /* derived class. */
2296 : /* */
2297 : /* Default internal implementation of RasterIO() ... utilizes */
2298 : /* the Block access methods to satisfy the request. This would */
2299 : /* normally only be overridden by formats with overviews. */
2300 : /* */
2301 : /* To keep things relatively simple, this method does not */
2302 : /* currently take advantage of some special cases addressed in */
2303 : /* GDALRasterBand::IRasterIO(), so it is likely best to only */
2304 : /* call it when you know it will help. That is in cases where */
2305 : /* data is at 1:1 to the buffer, and you know the driver is */
2306 : /* implementing interleaved IO efficiently on a block by block */
2307 : /* basis. Overviews will be used when possible. */
2308 : /************************************************************************/
2309 :
2310 : CPLErr
2311 : GDALDataset::BlockBasedRasterIO( GDALRWFlag eRWFlag,
2312 : int nXOff, int nYOff, int nXSize, int nYSize,
2313 : void * pData, int nBufXSize, int nBufYSize,
2314 : GDALDataType eBufType,
2315 : int nBandCount, int *panBandMap,
2316 949 : int nPixelSpace, int nLineSpace,int nBandSpace)
2317 :
2318 : {
2319 949 : GByte **papabySrcBlock = NULL;
2320 949 : GDALRasterBlock *poBlock = NULL;
2321 949 : GDALRasterBlock **papoBlocks = NULL;
2322 949 : int nLBlockX=-1, nLBlockY=-1, iBufYOff, iBufXOff, iSrcY, iBand;
2323 949 : int nBlockXSize=1, nBlockYSize=1;
2324 949 : CPLErr eErr = CE_None;
2325 949 : GDALDataType eDataType = GDT_Byte;
2326 :
2327 949 : CPLAssert( NULL != pData );
2328 :
2329 : /* -------------------------------------------------------------------- */
2330 : /* Ensure that all bands share a common block size and data type. */
2331 : /* -------------------------------------------------------------------- */
2332 :
2333 3944 : for( iBand = 0; iBand < nBandCount; iBand++ )
2334 : {
2335 2995 : GDALRasterBand *poBand = GetRasterBand( panBandMap[iBand] );
2336 : int nThisBlockXSize, nThisBlockYSize;
2337 :
2338 2995 : if( iBand == 0 )
2339 : {
2340 949 : poBand->GetBlockSize( &nBlockXSize, &nBlockYSize );
2341 949 : eDataType = poBand->GetRasterDataType();
2342 : }
2343 : else
2344 : {
2345 2046 : poBand->GetBlockSize( &nThisBlockXSize, &nThisBlockYSize );
2346 2046 : if( nThisBlockXSize != nBlockXSize
2347 : || nThisBlockYSize != nBlockYSize )
2348 : {
2349 : CPLDebug( "GDAL",
2350 : "GDALDataset::BlockBasedRasterIO() ... "
2351 0 : "mismatched block sizes, use std method." );
2352 : return GDALDataset::IRasterIO( eRWFlag,
2353 : nXOff, nYOff, nXSize, nYSize,
2354 : pData, nBufXSize, nBufYSize,
2355 : eBufType,
2356 : nBandCount, panBandMap,
2357 : nPixelSpace, nLineSpace,
2358 0 : nBandSpace );
2359 : }
2360 :
2361 2046 : if( eDataType != poBand->GetRasterDataType()
2362 : && (nXSize != nBufXSize || nYSize != nBufYSize) )
2363 : {
2364 : CPLDebug( "GDAL",
2365 : "GDALDataset::BlockBasedRasterIO() ... "
2366 0 : "mismatched band data types, use std method." );
2367 : return GDALDataset::IRasterIO( eRWFlag,
2368 : nXOff, nYOff, nXSize, nYSize,
2369 : pData, nBufXSize, nBufYSize,
2370 : eBufType,
2371 : nBandCount, panBandMap,
2372 : nPixelSpace, nLineSpace,
2373 0 : nBandSpace );
2374 : }
2375 : }
2376 : }
2377 :
2378 : /* ==================================================================== */
2379 : /* In this special case at full resolution we step through in */
2380 : /* blocks, turning the request over to the per-band */
2381 : /* IRasterIO(), but ensuring that all bands of one block are */
2382 : /* called before proceeding to the next. */
2383 : /* ==================================================================== */
2384 949 : if( nXSize == nBufXSize && nYSize == nBufYSize )
2385 : {
2386 : int nChunkYSize, nChunkXSize, nChunkXOff, nChunkYOff;
2387 :
2388 9080 : for( iBufYOff = 0; iBufYOff < nBufYSize; iBufYOff += nChunkYSize )
2389 : {
2390 8133 : nChunkYSize = nBlockYSize;
2391 8133 : nChunkYOff = iBufYOff + nYOff;
2392 8133 : nChunkYSize = nBlockYSize - (nChunkYOff % nBlockYSize);
2393 8133 : if( nChunkYSize == 0 )
2394 0 : nChunkYSize = nBlockYSize;
2395 8133 : if( nChunkYOff + nChunkYSize > nYOff + nYSize )
2396 285 : nChunkYSize = (nYOff + nYSize) - nChunkYOff;
2397 :
2398 16274 : for( iBufXOff = 0; iBufXOff < nBufXSize; iBufXOff += nChunkXSize )
2399 : {
2400 8141 : nChunkXSize = nBlockXSize;
2401 8141 : nChunkXOff = iBufXOff + nXOff;
2402 8141 : nChunkXSize = nBlockXSize - (nChunkXOff % nBlockXSize);
2403 8141 : if( nChunkXSize == 0 )
2404 0 : nChunkXSize = nBlockXSize;
2405 8141 : if( nChunkXOff + nChunkXSize > nXOff + nXSize )
2406 253 : nChunkXSize = (nXOff + nXSize) - nChunkXOff;
2407 :
2408 : GByte *pabyChunkData;
2409 :
2410 : pabyChunkData = ((GByte *) pData)
2411 : + iBufXOff * nPixelSpace
2412 8141 : + iBufYOff * nLineSpace;
2413 :
2414 20488 : for( iBand = 0; iBand < nBandCount; iBand++ )
2415 : {
2416 12347 : GDALRasterBand *poBand = GetRasterBand(panBandMap[iBand]);
2417 :
2418 : eErr =
2419 : poBand->GDALRasterBand::IRasterIO(
2420 : eRWFlag, nChunkXOff, nChunkYOff,
2421 : nChunkXSize, nChunkYSize,
2422 : pabyChunkData + iBand * nBandSpace,
2423 : nChunkXSize, nChunkYSize, eBufType,
2424 12347 : nPixelSpace, nLineSpace );
2425 12347 : if( eErr != CE_None )
2426 0 : return eErr;
2427 : }
2428 : }
2429 : }
2430 :
2431 947 : return CE_None;
2432 : }
2433 :
2434 : /* Below code is not compatible with that case. It would need a complete */
2435 : /* separate code like done in GDALRasterBand::IRasterIO. */
2436 2 : if (eRWFlag == GF_Write && (nBufXSize < nXSize || nBufYSize < nYSize))
2437 : {
2438 : return GDALDataset::IRasterIO( eRWFlag,
2439 : nXOff, nYOff, nXSize, nYSize,
2440 : pData, nBufXSize, nBufYSize,
2441 : eBufType,
2442 : nBandCount, panBandMap,
2443 : nPixelSpace, nLineSpace,
2444 0 : nBandSpace );
2445 : }
2446 :
2447 : /* ==================================================================== */
2448 : /* Loop reading required source blocks to satisfy output */
2449 : /* request. This is the most general implementation. */
2450 : /* ==================================================================== */
2451 :
2452 2 : int nBandDataSize = GDALGetDataTypeSize( eDataType ) / 8;
2453 :
2454 2 : papabySrcBlock = (GByte **) CPLCalloc(sizeof(GByte*),nBandCount);
2455 2 : papoBlocks = (GDALRasterBlock **) CPLCalloc(sizeof(void*),nBandCount);
2456 :
2457 : /* -------------------------------------------------------------------- */
2458 : /* Select an overview level if appropriate. */
2459 : /* -------------------------------------------------------------------- */
2460 : int nOverviewLevel = GDALDatasetGetBestOverviewLevel (this,
2461 : nXOff, nYOff, nXSize, nYSize,
2462 : nBufXSize, nBufYSize,
2463 2 : nBandCount, panBandMap);
2464 2 : if (nOverviewLevel >= 0)
2465 : {
2466 : GetRasterBand(panBandMap[0])->GetOverview(nOverviewLevel)->
2467 2 : GetBlockSize( &nBlockXSize, &nBlockYSize );
2468 : }
2469 :
2470 : /* -------------------------------------------------------------------- */
2471 : /* Compute stepping increment. */
2472 : /* -------------------------------------------------------------------- */
2473 : double dfSrcX, dfSrcY, dfSrcXInc, dfSrcYInc;
2474 :
2475 2 : dfSrcXInc = nXSize / (double) nBufXSize;
2476 2 : dfSrcYInc = nYSize / (double) nBufYSize;
2477 :
2478 : /* -------------------------------------------------------------------- */
2479 : /* Loop over buffer computing source locations. */
2480 : /* -------------------------------------------------------------------- */
2481 12 : for( iBufYOff = 0; iBufYOff < nBufYSize; iBufYOff++ )
2482 : {
2483 : int iBufOffset, iSrcOffset;
2484 :
2485 10 : dfSrcY = (iBufYOff+0.5) * dfSrcYInc + nYOff;
2486 10 : iSrcY = (int) dfSrcY;
2487 :
2488 10 : iBufOffset = iBufYOff * nLineSpace;
2489 :
2490 60 : for( iBufXOff = 0; iBufXOff < nBufXSize; iBufXOff++ )
2491 : {
2492 : int iSrcX;
2493 :
2494 50 : dfSrcX = (iBufXOff+0.5) * dfSrcXInc + nXOff;
2495 :
2496 50 : iSrcX = (int) dfSrcX;
2497 :
2498 : /* -------------------------------------------------------------------- */
2499 : /* Ensure we have the appropriate block loaded. */
2500 : /* -------------------------------------------------------------------- */
2501 50 : if( iSrcX < nLBlockX * nBlockXSize
2502 : || iSrcX >= (nLBlockX+1) * nBlockXSize
2503 : || iSrcY < nLBlockY * nBlockYSize
2504 : || iSrcY >= (nLBlockY+1) * nBlockYSize )
2505 : {
2506 2 : nLBlockX = iSrcX / nBlockXSize;
2507 2 : nLBlockY = iSrcY / nBlockYSize;
2508 :
2509 : int bJustInitialize =
2510 : eRWFlag == GF_Write
2511 : && nYOff <= nLBlockY * nBlockYSize
2512 : && nYOff + nYSize >= (nLBlockY+1) * nBlockYSize
2513 : && nXOff <= nLBlockX * nBlockXSize
2514 2 : && nXOff + nXSize >= (nLBlockX+1) * nBlockXSize;
2515 :
2516 4 : for( iBand = 0; iBand < nBandCount; iBand++ )
2517 : {
2518 2 : GDALRasterBand *poBand = GetRasterBand( panBandMap[iBand]);
2519 2 : if (nOverviewLevel >= 0)
2520 2 : poBand = poBand->GetOverview(nOverviewLevel);
2521 : poBlock = poBand->GetLockedBlockRef( nLBlockX, nLBlockY,
2522 2 : bJustInitialize );
2523 2 : if( poBlock == NULL )
2524 : {
2525 0 : eErr = CE_Failure;
2526 0 : goto CleanupAndReturn;
2527 : }
2528 :
2529 2 : if( eRWFlag == GF_Write )
2530 0 : poBlock->MarkDirty();
2531 :
2532 2 : if( papoBlocks[iBand] != NULL )
2533 0 : papoBlocks[iBand]->DropLock();
2534 :
2535 2 : papoBlocks[iBand] = poBlock;
2536 :
2537 2 : papabySrcBlock[iBand] = (GByte *) poBlock->GetDataRef();
2538 2 : if( papabySrcBlock[iBand] == NULL )
2539 : {
2540 0 : eErr = CE_Failure;
2541 0 : goto CleanupAndReturn;
2542 : }
2543 : }
2544 : }
2545 :
2546 : /* -------------------------------------------------------------------- */
2547 : /* Copy over this pixel of data. */
2548 : /* -------------------------------------------------------------------- */
2549 : iSrcOffset = (iSrcX - nLBlockX*nBlockXSize
2550 50 : + (iSrcY - nLBlockY*nBlockYSize) * nBlockXSize)*nBandDataSize;
2551 :
2552 100 : for( iBand = 0; iBand < nBandCount; iBand++ )
2553 : {
2554 50 : GByte *pabySrcBlock = papabySrcBlock[iBand];
2555 50 : int iBandBufOffset = iBufOffset + iBand * nBandSpace;
2556 :
2557 50 : if( eDataType == eBufType )
2558 : {
2559 50 : if( eRWFlag == GF_Read )
2560 : memcpy( ((GByte *) pData) + iBandBufOffset,
2561 50 : pabySrcBlock + iSrcOffset, nBandDataSize );
2562 : else
2563 : memcpy( pabySrcBlock + iSrcOffset,
2564 0 : ((GByte *)pData) + iBandBufOffset, nBandDataSize );
2565 : }
2566 : else
2567 : {
2568 : /* type to type conversion ... ouch, this is expensive way
2569 : of handling single words */
2570 :
2571 0 : if( eRWFlag == GF_Read )
2572 : GDALCopyWords( pabySrcBlock + iSrcOffset, eDataType, 0,
2573 : ((GByte *) pData) + iBandBufOffset,
2574 0 : eBufType, 0, 1 );
2575 : else
2576 : GDALCopyWords( ((GByte *) pData) + iBandBufOffset,
2577 : eBufType, 0,
2578 : pabySrcBlock + iSrcOffset, eDataType, 0,
2579 0 : 1 );
2580 : }
2581 : }
2582 :
2583 50 : iBufOffset += nPixelSpace;
2584 : }
2585 : }
2586 :
2587 : /* -------------------------------------------------------------------- */
2588 : /* CleanupAndReturn. */
2589 : /* -------------------------------------------------------------------- */
2590 2 : CleanupAndReturn:
2591 2 : CPLFree( papabySrcBlock );
2592 2 : if( papoBlocks != NULL )
2593 : {
2594 4 : for( iBand = 0; iBand < nBandCount; iBand++ )
2595 : {
2596 2 : if( papoBlocks[iBand] != NULL )
2597 2 : papoBlocks[iBand]->DropLock();
2598 : }
2599 2 : CPLFree( papoBlocks );
2600 : }
2601 :
2602 2 : return( CE_None );
2603 : }
2604 :
2605 : /************************************************************************/
2606 : /* GDALDatasetCopyWholeRaster() */
2607 : /************************************************************************/
2608 :
2609 : /**
2610 : * \brief Copy all dataset raster data.
2611 : *
2612 : * This function copies the complete raster contents of one dataset to
2613 : * another similarly configured dataset. The source and destination
2614 : * dataset must have the same number of bands, and the same width
2615 : * and height. The bands do not have to have the same data type.
2616 : *
2617 : * This function is primarily intended to support implementation of
2618 : * driver specific CreateCopy() functions. It implements efficient copying,
2619 : * in particular "chunking" the copy in substantial blocks and, if appropriate,
2620 : * performing the transfer in a pixel interleaved fashion.
2621 : *
2622 : * Currently the only papszOptions value supported is "INTERLEAVE=PIXEL"
2623 : * to force pixel interleaved operation. More options may be supported in
2624 : * the future.
2625 : *
2626 : * @param hSrcDS the source dataset
2627 : * @param hDstDS the destination dataset
2628 : * @param papszOptions transfer hints in "StringList" Name=Value format.
2629 : * @param pfnProgress progress reporting function.
2630 : * @param pProgressData callback data for progress function.
2631 : *
2632 : * @return CE_None on success, or CE_Failure on failure.
2633 : */
2634 :
2635 : CPLErr CPL_STDCALL GDALDatasetCopyWholeRaster(
2636 : GDALDatasetH hSrcDS, GDALDatasetH hDstDS, char **papszOptions,
2637 370 : GDALProgressFunc pfnProgress, void *pProgressData )
2638 :
2639 : {
2640 370 : VALIDATE_POINTER1( hSrcDS, "GDALDatasetCopyWholeRaster", CE_Failure );
2641 370 : VALIDATE_POINTER1( hDstDS, "GDALDatasetCopyWholeRaster", CE_Failure );
2642 :
2643 370 : GDALDataset *poSrcDS = (GDALDataset *) hSrcDS;
2644 370 : GDALDataset *poDstDS = (GDALDataset *) hDstDS;
2645 370 : CPLErr eErr = CE_None;
2646 :
2647 370 : if( pfnProgress == NULL )
2648 0 : pfnProgress = GDALDummyProgress;
2649 :
2650 : /* -------------------------------------------------------------------- */
2651 : /* Confirm the datasets match in size and band counts. */
2652 : /* -------------------------------------------------------------------- */
2653 370 : int nXSize = poDstDS->GetRasterXSize(),
2654 370 : nYSize = poDstDS->GetRasterYSize(),
2655 370 : nBandCount = poDstDS->GetRasterCount();
2656 :
2657 370 : if( poSrcDS->GetRasterXSize() != nXSize
2658 : || poSrcDS->GetRasterYSize() != nYSize
2659 : || poSrcDS->GetRasterCount() != nBandCount )
2660 : {
2661 : CPLError( CE_Failure, CPLE_AppDefined,
2662 : "Input and output dataset sizes or band counts do not\n"
2663 0 : "match in GDALDatasetCopyWholeRaster()" );
2664 0 : return CE_Failure;
2665 : }
2666 :
2667 : /* -------------------------------------------------------------------- */
2668 : /* Report preliminary (0) progress. */
2669 : /* -------------------------------------------------------------------- */
2670 370 : if( !pfnProgress( 0.0, NULL, pProgressData ) )
2671 : {
2672 : CPLError( CE_Failure, CPLE_UserInterrupt,
2673 0 : "User terminated CreateCopy()" );
2674 0 : return CE_Failure;
2675 : }
2676 :
2677 : /* -------------------------------------------------------------------- */
2678 : /* Get our prototype band, and assume the others are similarly */
2679 : /* configured. */
2680 : /* -------------------------------------------------------------------- */
2681 370 : if( nBandCount == 0 )
2682 0 : return CE_None;
2683 :
2684 370 : GDALRasterBand *poPrototypeBand = poDstDS->GetRasterBand(1);
2685 370 : GDALDataType eDT = poPrototypeBand->GetRasterDataType();
2686 : int nBlockXSize, nBlockYSize;
2687 :
2688 370 : poPrototypeBand->GetBlockSize( &nBlockXSize, &nBlockYSize );
2689 :
2690 : /* -------------------------------------------------------------------- */
2691 : /* Do we want to try and do the operation in a pixel */
2692 : /* interleaved fashion? */
2693 : /* -------------------------------------------------------------------- */
2694 370 : int bInterleave = FALSE;
2695 370 : const char *pszInterleave = NULL;
2696 :
2697 370 : pszInterleave = poSrcDS->GetMetadataItem( "INTERLEAVE", "IMAGE_STRUCTURE");
2698 370 : if( pszInterleave != NULL
2699 : && (EQUAL(pszInterleave,"PIXEL") || EQUAL(pszInterleave,"LINE")) )
2700 67 : bInterleave = TRUE;
2701 :
2702 370 : pszInterleave = poDstDS->GetMetadataItem( "INTERLEAVE", "IMAGE_STRUCTURE");
2703 370 : if( pszInterleave != NULL
2704 : && (EQUAL(pszInterleave,"PIXEL") || EQUAL(pszInterleave,"LINE")) )
2705 38 : bInterleave = TRUE;
2706 :
2707 370 : pszInterleave = CSLFetchNameValue( papszOptions, "INTERLEAVE" );
2708 370 : if( pszInterleave != NULL
2709 : && (EQUAL(pszInterleave,"PIXEL") || EQUAL(pszInterleave,"LINE")) )
2710 0 : bInterleave = TRUE;
2711 :
2712 : /* If the destination is compressed, we must try to write blocks just once, to save */
2713 : /* disk space (GTiff case for example), and to avoid data loss (JPEG compression for example) */
2714 370 : int bDstIsCompressed = FALSE;
2715 370 : const char* pszDstCompressed= CSLFetchNameValue( papszOptions, "COMPRESSED" );
2716 370 : if (pszDstCompressed != NULL && CSLTestBoolean(pszDstCompressed))
2717 13 : bDstIsCompressed = TRUE;
2718 :
2719 : /* -------------------------------------------------------------------- */
2720 : /* What will our swath size be? */
2721 : /* -------------------------------------------------------------------- */
2722 : /* When writing interleaved data in a compressed format, we want to be sure */
2723 : /* that each block will only be written once, so the swath size must not be */
2724 : /* greater than the block cache. */
2725 : /* So as the default cache size is 40 MB, 10 MB is a safe value */
2726 370 : int nTargetSwathSize = atoi(CPLGetConfigOption("GDAL_SWATH_SIZE", "10000000"));
2727 370 : if (nTargetSwathSize < 1000000)
2728 0 : nTargetSwathSize = 1000000;
2729 :
2730 : /* But let's check that */
2731 370 : if (bDstIsCompressed && bInterleave && nTargetSwathSize > GDALGetCacheMax())
2732 : {
2733 : CPLError(CE_Warning, CPLE_AppDefined,
2734 : "When translating into a compressed interleave format, the block cache size (%d) "
2735 0 : "should be at least the size of the swath (%d)", GDALGetCacheMax(), nTargetSwathSize);
2736 : }
2737 :
2738 : void *pSwathBuf;
2739 :
2740 370 : int nPixelSize = (GDALGetDataTypeSize(eDT) / 8);
2741 370 : if( bInterleave)
2742 86 : nPixelSize *= nBandCount;
2743 :
2744 : // aim for one row of blocks. Do not settle for less.
2745 370 : int nSwathCols = nXSize;
2746 370 : int nSwathLines = nBlockYSize;
2747 :
2748 370 : int nMemoryPerLine = nXSize * nPixelSize;
2749 :
2750 : /* Do the computation on a big int since for example when translating */
2751 : /* the JPL WMS layer, we overflow 32 bits*/
2752 370 : GIntBig nSwathBufSize = (GIntBig)nMemoryPerLine * nSwathLines;
2753 370 : if (nSwathBufSize > (GIntBig)nTargetSwathSize)
2754 : {
2755 0 : nSwathLines = nTargetSwathSize / nMemoryPerLine;
2756 0 : if (nSwathLines == 0)
2757 0 : nSwathLines = 1;
2758 : CPLDebug( "GDAL",
2759 : "GDALDatasetCopyWholeRaster(): adjusting to %d line swath "
2760 : "since requirement (%d * %d bytes) exceed target swath size (%d bytes) ",
2761 0 : nSwathLines, nBlockYSize, nMemoryPerLine, nTargetSwathSize);
2762 : }
2763 : // If we are processing single scans, try to handle several at once.
2764 : // If we are handling swaths already, only grow the swath if a row
2765 : // of blocks is substantially less than our target buffer size.
2766 370 : else if( nSwathLines == 1
2767 : || nMemoryPerLine * nSwathLines < nTargetSwathSize / 10 )
2768 369 : nSwathLines = MIN(nYSize,MAX(1,nTargetSwathSize/nMemoryPerLine));
2769 :
2770 :
2771 370 : if (bDstIsCompressed)
2772 : {
2773 13 : if (nSwathLines < nBlockYSize)
2774 : {
2775 0 : nSwathLines = nBlockYSize;
2776 :
2777 : /* Number of pixels that can be read/write simultaneously */
2778 0 : nSwathCols = nTargetSwathSize / (nSwathLines * nPixelSize);
2779 0 : nSwathCols = (nSwathCols / nBlockXSize) * nBlockXSize;
2780 0 : if (nSwathCols == 0)
2781 0 : nSwathCols = nBlockXSize;
2782 0 : if (nSwathCols > nXSize)
2783 0 : nSwathCols = nXSize;
2784 :
2785 : CPLDebug( "GDAL",
2786 : "GDALDatasetCopyWholeRaster(): because of compression and too high block,\n"
2787 0 : "use partial width at one time");
2788 : }
2789 : else
2790 : {
2791 : /* Round on a multiple of nBlockYSize */
2792 13 : nSwathLines = (nSwathLines / nBlockYSize) * nBlockYSize;
2793 : CPLDebug( "GDAL",
2794 : "GDALDatasetCopyWholeRaster(): because of compression, \n"
2795 13 : "round nSwathLines to block height : %d", nSwathLines);
2796 : }
2797 : }
2798 :
2799 370 : pSwathBuf = VSIMalloc3(nSwathCols, nSwathLines, nPixelSize );
2800 370 : if( pSwathBuf == NULL )
2801 : {
2802 : CPLError( CE_Failure, CPLE_OutOfMemory,
2803 : "Failed to allocate %d*%d*%d byte swath buffer in\n"
2804 : "GDALDatasetCopyWholeRaster()",
2805 0 : nSwathCols, nSwathLines, nPixelSize );
2806 0 : return CE_Failure;
2807 : }
2808 :
2809 : CPLDebug( "GDAL",
2810 : "GDALDatasetCopyWholeRaster(): %d*%d swaths, bInterleave=%d",
2811 370 : nSwathCols, nSwathLines, bInterleave );
2812 :
2813 : /* ==================================================================== */
2814 : /* Band oriented (uninterleaved) case. */
2815 : /* ==================================================================== */
2816 370 : if( !bInterleave )
2817 : {
2818 : int iBand, iX, iY;
2819 :
2820 590 : for( iBand = 0; iBand < nBandCount && eErr == CE_None; iBand++ )
2821 : {
2822 306 : int nBand = iBand+1;
2823 :
2824 614 : for( iY = 0; iY < nYSize && eErr == CE_None; iY += nSwathLines )
2825 : {
2826 308 : int nThisLines = nSwathLines;
2827 :
2828 308 : if( iY + nThisLines > nYSize )
2829 2 : nThisLines = nYSize - iY;
2830 :
2831 616 : for( iX = 0; iX < nXSize && eErr == CE_None; iX += nSwathCols )
2832 : {
2833 308 : int nThisCols = nSwathCols;
2834 :
2835 308 : if( iX + nThisCols > nXSize )
2836 0 : nThisCols = nXSize - iX;
2837 :
2838 : eErr = poSrcDS->RasterIO( GF_Read,
2839 : iX, iY, nThisCols, nThisLines,
2840 : pSwathBuf, nThisCols, nThisLines,
2841 : eDT, 1, &nBand,
2842 308 : 0, 0, 0 );
2843 :
2844 308 : if( eErr == CE_None )
2845 : eErr = poDstDS->RasterIO( GF_Write,
2846 : iX, iY, nThisCols, nThisLines,
2847 : pSwathBuf, nThisCols, nThisLines,
2848 : eDT, 1, &nBand,
2849 308 : 0, 0, 0 );
2850 :
2851 308 : if( eErr == CE_None
2852 : && !pfnProgress(
2853 : iBand / (float)nBandCount
2854 : + (iY+nThisLines) / (float) (nYSize*nBandCount),
2855 : NULL, pProgressData ) )
2856 : {
2857 0 : eErr = CE_Failure;
2858 : CPLError( CE_Failure, CPLE_UserInterrupt,
2859 0 : "User terminated CreateCopy()" );
2860 : }
2861 : }
2862 : }
2863 : }
2864 : }
2865 :
2866 : /* ==================================================================== */
2867 : /* Pixel interleaved case. */
2868 : /* ==================================================================== */
2869 : else /* if( bInterleave ) */
2870 : {
2871 : int iY, iX;
2872 :
2873 173 : for( iY = 0; iY < nYSize && eErr == CE_None; iY += nSwathLines )
2874 : {
2875 87 : int nThisLines = nSwathLines;
2876 :
2877 87 : if( iY + nThisLines > nYSize )
2878 1 : nThisLines = nYSize - iY;
2879 :
2880 174 : for( iX = 0; iX < nXSize && eErr == CE_None; iX += nSwathCols )
2881 : {
2882 87 : int nThisCols = nSwathCols;
2883 :
2884 87 : if( iX + nThisCols > nXSize )
2885 0 : nThisCols = nXSize - iX;
2886 :
2887 : eErr = poSrcDS->RasterIO( GF_Read,
2888 : iX, iY, nThisCols, nThisLines,
2889 : pSwathBuf, nThisCols, nThisLines,
2890 : eDT, nBandCount, NULL,
2891 87 : 0, 0, 0 );
2892 :
2893 87 : if( eErr == CE_None )
2894 : eErr = poDstDS->RasterIO( GF_Write,
2895 : iX, iY, nThisCols, nThisLines,
2896 : pSwathBuf, nThisCols, nThisLines,
2897 : eDT, nBandCount, NULL,
2898 87 : 0, 0, 0 );
2899 :
2900 87 : if( eErr == CE_None
2901 : && !pfnProgress( (iY+nThisLines) / (float) nYSize,
2902 : NULL, pProgressData ) )
2903 : {
2904 0 : eErr = CE_Failure;
2905 : CPLError( CE_Failure, CPLE_UserInterrupt,
2906 0 : "User terminated CreateCopy()" );
2907 : }
2908 : }
2909 : }
2910 : }
2911 :
2912 : /* -------------------------------------------------------------------- */
2913 : /* Cleanup */
2914 : /* -------------------------------------------------------------------- */
2915 370 : CPLFree( pSwathBuf );
2916 :
2917 370 : return eErr;
2918 : }
|