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