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