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