LCOV - code coverage report
Current view: directory - gcore - overview.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 656 450 68.6 %
Date: 2010-01-09 Functions: 7 5 71.4 %

       1                 : /******************************************************************************
       2                 :  * $Id: overview.cpp 18349 2009-12-19 14:45:41Z rouault $
       3                 :  *
       4                 :  * Project:  GDAL Core
       5                 :  * Purpose:  Helper code to implement overview support in different drivers.
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2000, Frank Warmerdam
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include "gdal_priv.h"
      31                 : 
      32                 : CPL_CVSID("$Id: overview.cpp 18349 2009-12-19 14:45:41Z rouault $");
      33                 : 
      34                 : typedef enum
      35                 : {
      36                 :     GRM_Near = 0,
      37                 :     GRM_Average = 1,
      38                 :     GRM_Gauss = 2,
      39                 :     GRM_Mode = 3,
      40                 :     GRM_Cubic = 4,
      41                 : } GDALResamplingMethod;
      42                 : 
      43                 : /************************************************************************/
      44                 : /*                       GDALDownsampleChunk32R()                       */
      45                 : /************************************************************************/
      46                 : 
      47                 : static CPLErr
      48             538 : GDALDownsampleChunk32R( int nSrcWidth, int nSrcHeight, 
      49                 :                         float * pafChunk,
      50                 :                         GByte * pabyChunkNodataMask,
      51                 :                         int nChunkXOff, int nChunkXSize,
      52                 :                         int nChunkYOff, int nChunkYSize,
      53                 :                         GDALRasterBand * poOverview,
      54                 :                         const char * pszResampling,
      55                 :                         int bHasNoData, float fNoDataValue,
      56                 :                         GDALColorTable* poColorTable,
      57                 :                         GDALDataType eSrcDataType)
      58                 : 
      59                 : {
      60                 : /* -------------------------------------------------------------------- */
      61                 : /*      Check the input parameters.                                     */
      62                 : /*      TODO: I think that instead of passing the pszResampling string  */
      63                 : /*            and endless string comparisons this function should take  */
      64                 : /*            GDALResamplingMethod flag. The string to flag conversion  */
      65                 : /*            should be done on upper level.                            */
      66                 : /* -------------------------------------------------------------------- */
      67             538 :     CPLErr eErr = CE_None;
      68                 :     GDALResamplingMethod eResampling;
      69                 : 
      70             538 :     if ( EQUALN(pszResampling, "NEAR", 4) )
      71             341 :         eResampling = GRM_Near;
      72             197 :     else if ( EQUALN(pszResampling, "AVER", 4) )
      73             111 :         eResampling = GRM_Average;
      74              86 :     else if ( EQUALN(pszResampling, "GAUSS", 5) )
      75              20 :         eResampling = GRM_Gauss;
      76              66 :     else if ( EQUALN(pszResampling, "MODE", 4) )
      77              18 :         eResampling = GRM_Mode;
      78              48 :     else if ( EQUALN(pszResampling, "CUBIC", 6) )
      79              48 :         eResampling = GRM_Cubic;
      80                 :     else
      81                 :     {
      82                 :         CPLError( CE_Failure, CPLE_AppDefined,
      83                 :                   "GDALDownsampleChunk32R: Unsupported resampling method \"%s\".",
      84               0 :                   pszResampling );
      85               0 :         return CE_Failure;
      86                 :     }
      87                 : 
      88                 : /* -------------------------------------------------------------------- */
      89                 : /*      Create the filter kernel and allocate scanline buffer.          */
      90                 : /* -------------------------------------------------------------------- */
      91                 :     int      nDstXOff, nDstXOff2, nDstYOff, nDstYOff2, nOXSize, nOYSize;
      92                 :     float    *pafDstScanline;
      93             538 :     int nGaussMatrixDim = 3;
      94                 :     const int *panGaussMatrix;
      95                 :     static const int anGaussMatrix3x3[] ={
      96                 :         1,2,1,
      97                 :         2,4,2,
      98                 :         1,2,1
      99                 :     };
     100                 :     static const int anGaussMatrix5x5[] = {
     101                 :         1,4,6,4,1,
     102                 :         4,16,24,16,4,
     103                 :         6,24,36,24,6,
     104                 :         4,16,24,16,4,
     105                 :         1,4,6,4,1};
     106                 :     static const int anGaussMatrix7x7[] = {
     107                 :         1,6,15,20,15,6,1,
     108                 :         6,36,90,120,90,36,6,
     109                 :         15,90,225,300,225,90,15,
     110                 :         20,120,300,400,300,120,20,
     111                 :         15,90,225,300,225,90,15,
     112                 :         6,36,90,120,90,36,6,
     113                 :         1,6,15,20,15,6,1};
     114                 : 
     115             538 :     nOXSize = poOverview->GetXSize();
     116             538 :     nOYSize = poOverview->GetYSize();
     117             538 :     int nResYFactor = (int) (0.5 + (double)nSrcHeight/(double)nOYSize);
     118                 : 
     119                 :     // matrix for gauss filter
     120             538 :     if(nResYFactor <= 2 )
     121                 :     {
     122             326 :         panGaussMatrix = anGaussMatrix3x3;
     123             326 :         nGaussMatrixDim=3;
     124                 :     }
     125             212 :     else if (nResYFactor <= 4)
     126                 :     {
     127             186 :         panGaussMatrix = anGaussMatrix5x5;
     128             186 :         nGaussMatrixDim=5;
     129                 :     }
     130                 :     else
     131                 :     {
     132              26 :         panGaussMatrix = anGaussMatrix7x7;
     133              26 :         nGaussMatrixDim=7;
     134                 :     }
     135                 : 
     136                 : /* -------------------------------------------------------------------- */
     137                 : /*      Figure out the column to start writing to, and the first column */
     138                 : /*      to not write to.                                                */
     139                 : /* -------------------------------------------------------------------- */
     140             538 :     nDstXOff = (int) (0.5 + (nChunkXOff/(double)nSrcWidth) * nOXSize);
     141                 :     nDstXOff2 = (int) 
     142             538 :         (0.5 + ((nChunkXOff+nChunkXSize)/(double)nSrcWidth) * nOXSize);
     143                 : 
     144             538 :     if( nChunkXOff + nChunkXSize == nSrcWidth )
     145             538 :         nDstXOff2 = nOXSize;
     146                 : 
     147                 : 
     148             538 :     pafDstScanline = (float *) VSIMalloc((nDstXOff2 - nDstXOff) * sizeof(float));
     149             538 :     if( pafDstScanline == NULL )
     150                 :     {
     151                 :         CPLError( CE_Failure, CPLE_OutOfMemory,
     152               0 :                   "GDALDownsampleChunk32R: Out of memory for line buffer." );
     153               0 :         return CE_Failure;
     154                 :     }
     155                 : 
     156                 : /* -------------------------------------------------------------------- */
     157                 : /*      Figure out the line to start writing to, and the first line     */
     158                 : /*      to not write to.  In theory this approach should ensure that    */
     159                 : /*      every output line will be written if all input chunks are       */
     160                 : /*      processed.                                                      */
     161                 : /* -------------------------------------------------------------------- */
     162             538 :     nDstYOff = (int) (0.5 + (nChunkYOff/(double)nSrcHeight) * nOYSize);
     163                 :     nDstYOff2 = (int) 
     164             538 :         (0.5 + ((nChunkYOff+nChunkYSize)/(double)nSrcHeight) * nOYSize);
     165                 : 
     166             538 :     if( nChunkYOff + nChunkYSize == nSrcHeight )
     167             232 :         nDstYOff2 = nOYSize;
     168                 : 
     169                 : 
     170             538 :     int nEntryCount = 0;
     171             538 :     GDALColorEntry* aEntries = NULL;
     172             538 :     if (poColorTable)
     173                 :     {
     174                 :         int i;
     175               6 :         nEntryCount = poColorTable->GetColorEntryCount();
     176               6 :         aEntries = (GDALColorEntry* )CPLMalloc(sizeof(GDALColorEntry) * nEntryCount);
     177            1542 :         for(i=0;i<nEntryCount;i++)
     178                 :         {
     179            1536 :             poColorTable->GetColorEntryAsRGB(i, &aEntries[i]);
     180                 :         }
     181                 :     }
     182                 : 
     183             538 :     int      nMaxNumPx = 0;
     184             538 :     float*   pafVals = NULL;
     185             538 :     int*     panSums = NULL;
     186                 : 
     187                 : /* ==================================================================== */
     188                 : /*      Loop over destination scanlines.                                */
     189                 : /* ==================================================================== */
     190           11178 :     for( int iDstLine = nDstYOff; iDstLine < nDstYOff2 && eErr == CE_None; iDstLine++ )
     191                 :     {
     192                 :         float *pafSrcScanline;
     193                 :         GByte *pabySrcScanlineNodataMask;
     194           10640 :         int   nSrcYOff, nSrcYOff2 = 0, iDstPixel;
     195                 : 
     196           10640 :         if (eResampling == GRM_Gauss)
     197                 :         {
     198             260 :             nSrcYOff = (int) (0.5 + (iDstLine/(double)nOYSize) * nSrcHeight);
     199             260 :             nSrcYOff2 = (int) (0.5 + ((iDstLine+1)/(double)nOYSize) * nSrcHeight) + 1;
     200                 : 
     201             260 :             if( nSrcYOff < nChunkYOff )
     202                 :             {
     203               0 :                 nSrcYOff = nChunkYOff;
     204               0 :                 nSrcYOff2++;
     205                 :             }
     206                 : 
     207             260 :             int iSizeY = nSrcYOff2 - nSrcYOff;
     208             260 :             nSrcYOff = nSrcYOff + iSizeY/2 - nGaussMatrixDim/2;
     209             260 :             nSrcYOff2 = nSrcYOff + nGaussMatrixDim;
     210             260 :             if(nSrcYOff < 0)
     211               0 :                 nSrcYOff = 0;
     212                 :         }
     213           10380 :         else if( eResampling == GRM_Cubic )
     214                 :         {
     215             840 :             nSrcYOff = (int) floor(((iDstLine+0.5)/(double)nOYSize) * nSrcHeight - 0.5)-1;
     216             840 :             nSrcYOff2 = nSrcYOff + 4;
     217             840 :             if(nSrcYOff < 0)
     218               8 :                 nSrcYOff = 0;
     219             840 :             if(nSrcYOff < nChunkYOff)
     220              16 :                 nSrcYOff = nChunkYOff;
     221                 :         }
     222                 :         else 
     223                 :         {
     224            9540 :             nSrcYOff = (int) (0.5 + (iDstLine/(double)nOYSize) * nSrcHeight);
     225            9540 :             if ( nSrcYOff < nChunkYOff )
     226              10 :                 nSrcYOff = nChunkYOff;
     227                 :             
     228                 :             nSrcYOff2 = 
     229            9540 :                 (int) (0.5 + ((iDstLine+1)/(double)nOYSize) * nSrcHeight);
     230                 :         }
     231                 : 
     232           10640 :         if( nSrcYOff2 > nSrcHeight || iDstLine == nOYSize-1 )
     233             232 :             nSrcYOff2 = nSrcHeight;
     234           10640 :         if( nSrcYOff2 > nChunkYOff + nChunkYSize)
     235              48 :             nSrcYOff2 = nChunkYOff + nChunkYSize;
     236                 : 
     237           10640 :         pafSrcScanline = pafChunk + ((nSrcYOff-nChunkYOff) * nChunkXSize);
     238           10640 :         if (pabyChunkNodataMask != NULL)
     239             950 :             pabySrcScanlineNodataMask = pabyChunkNodataMask + ((nSrcYOff-nChunkYOff) * nChunkXSize);
     240                 :         else
     241            9690 :             pabySrcScanlineNodataMask = NULL;
     242                 : 
     243                 : /* -------------------------------------------------------------------- */
     244                 : /*      Loop over destination pixels                                    */
     245                 : /* -------------------------------------------------------------------- */
     246         3458484 :         for( iDstPixel = nDstXOff; iDstPixel < nDstXOff2; iDstPixel++ )
     247                 :         {
     248                 :             int   nSrcXOff, nSrcXOff2;
     249                 : 
     250         3447844 :             if (eResampling == GRM_Gauss) 
     251                 :             {
     252            4700 :                 nSrcXOff = (int) (0.5 + (iDstPixel/(double)nOXSize) * nSrcWidth);
     253            4700 :                 nSrcXOff2 = (int)(0.5 + ((iDstPixel+1)/(double)nOXSize) * nSrcWidth) + 1;
     254                 : 
     255            4700 :                 int iSizeX = nSrcXOff2 - nSrcXOff;
     256            4700 :                 nSrcXOff = nSrcXOff + iSizeX/2 - nGaussMatrixDim/2;
     257            4700 :                 nSrcXOff2 = nSrcXOff + nGaussMatrixDim;
     258            4700 :                 if(nSrcXOff < 0)
     259               0 :                     nSrcXOff = 0;
     260                 :             }
     261         3443144 :             else if( eResampling == GRM_Cubic )
     262                 :             {
     263           56520 :                 nSrcXOff = (int) floor(((iDstPixel+0.5)/(double)nOXSize) * nSrcWidth - 0.5)-1;
     264           56520 :                 nSrcXOff2 = nSrcXOff + 4;
     265                 : 
     266           56520 :                 if(nSrcXOff < 0)
     267             600 :                     nSrcXOff = 0;
     268                 :             }
     269                 :             else
     270                 :             {
     271                 :                 nSrcXOff =
     272         3386624 :                     (int) (0.5 + (iDstPixel/(double)nOXSize) * nSrcWidth);
     273         3386624 :                 if ( nSrcXOff < nChunkXOff )
     274               0 :                     nSrcXOff = nChunkXOff;
     275                 :                 nSrcXOff2 = (int) 
     276         3386624 :                     (0.5 + ((iDstPixel+1)/(double)nOXSize) * nSrcWidth);
     277                 :             }
     278                 : 
     279         3447844 :             if( nSrcXOff2 > nSrcWidth || iDstPixel == nOXSize-1 )
     280           10640 :                 nSrcXOff2 = nSrcWidth;
     281         3447844 :             if( nSrcXOff2 > nChunkXOff + nChunkXSize )
     282               0 :                 nSrcXOff2 = nChunkXOff + nChunkXSize;
     283                 : 
     284         3447844 :             if ( eResampling == GRM_Near )
     285                 :             { 
     286         3332224 :                 pafDstScanline[iDstPixel - nDstXOff] = pafSrcScanline[nSrcXOff - nChunkXOff];
     287                 :             }
     288          115620 :             else if( eResampling == GRM_Cubic )
     289                 :             {
     290                 :                 // If we do not seem to have our full 4x4 window just 
     291                 :                 // do nearest resampling. 
     292           62040 :                 if( nSrcXOff2 - nSrcXOff != 4 || nSrcYOff2 - nSrcYOff != 4 )
     293                 :                 {
     294            5520 :                     int nLSrcYOff = (int) (0.5+(iDstLine/(double)nOYSize) * nSrcHeight);
     295            5520 :                     int nLSrcXOff = (int) (0.5+(iDstPixel/(double)nOXSize) * nSrcWidth);
     296                 :                     
     297            5520 :                     if( nLSrcYOff < nChunkYOff )
     298               0 :                         nLSrcYOff = nChunkYOff;
     299            5520 :                     if( nLSrcYOff > nChunkYOff + nChunkYSize - 1 )
     300               0 :                         nLSrcYOff = nChunkYOff + nChunkYSize - 1;
     301                 : 
     302            5520 :                     pafDstScanline[iDstPixel - nDstXOff] = 
     303                 :                         pafChunk[(nLSrcYOff-nChunkYOff) * nChunkXSize 
     304            5520 :                                  + (nLSrcXOff - nChunkXOff)];
     305                 :                 }
     306                 :                 else
     307                 :                 {
     308                 : #define CubicConvolution(distance1,distance2,distance3,f0,f1,f2,f3) \
     309                 :    (  (   -f0 +     f1 - f2 + f3) * distance3                       \
     310                 :     + (2.0*(f0 - f1) + f2 - f3) * distance2                         \
     311                 :     + (   -f0          + f2     ) * distance1                       \
     312                 :     +               f1                         )
     313                 : 
     314                 :                     int ic;
     315                 :                     double adfRowResults[4];
     316           51000 :                     double dfSrcX = (((iDstPixel+0.5)/(double)nOXSize) * nSrcWidth);
     317           51000 :                     double dfDeltaX = dfSrcX - 0.5 - (nSrcXOff+1);
     318           51000 :                     double dfDeltaX2 = dfDeltaX * dfDeltaX;
     319           51000 :                     double dfDeltaX3 = dfDeltaX2 * dfDeltaX;
     320                 : 
     321          255000 :                     for ( ic = 0; ic < 4; ic++ )
     322                 :                     {
     323                 :                         float *pafSrcRow = pafSrcScanline +
     324          204000 :                             nSrcXOff-nChunkXOff+(nSrcYOff+ic-nSrcYOff)*nChunkXSize;
     325                 : 
     326          204000 :                         adfRowResults[ic] = 
     327         1632000 :                             CubicConvolution(dfDeltaX, dfDeltaX2, dfDeltaX3,
     328                 :                                              pafSrcRow[0], 
     329                 :                                              pafSrcRow[1], 
     330                 :                                              pafSrcRow[2], 
     331         1632000 :                                              pafSrcRow[3] );
     332                 :                     }
     333                 : 
     334           51000 :                     double dfSrcY = (((iDstLine+0.5)/(double)nOYSize) * nSrcHeight);
     335           51000 :                     double dfDeltaY = dfSrcY - 0.5 - (nSrcYOff+1);
     336           51000 :                     double dfDeltaY2 = dfDeltaY * dfDeltaY;
     337           51000 :                     double dfDeltaY3 = dfDeltaY2 * dfDeltaY;
     338                 : 
     339           51000 :                     pafDstScanline[iDstPixel - nDstXOff] = (float) 
     340          408000 :                         CubicConvolution(dfDeltaY, dfDeltaY2, dfDeltaY3,
     341                 :                                          adfRowResults[0],
     342                 :                                          adfRowResults[1],
     343                 :                                          adfRowResults[2],
     344          408000 :                                          adfRowResults[3] );
     345                 :                 }
     346                 :             }
     347           59100 :             else if ( eResampling == GRM_Average )
     348                 :             {
     349          106200 :                 if (poColorTable == NULL
     350                 :                     || EQUALN(pszResampling,"AVERAGE_BIT2GRAYSCALE",13))
     351                 :                 {
     352                 :                     double val;
     353           53000 :                     double dfTotal = 0.0;
     354           53000 :                     int    nCount = 0, iX, iY;
     355                 : 
     356          166300 :                     for( iY = nSrcYOff; iY < nSrcYOff2; iY++ )
     357                 :                     {
     358          369504 :                         for( iX = nSrcXOff; iX < nSrcXOff2; iX++ )
     359                 :                         {
     360          256204 :                             val = pafSrcScanline[iX-nChunkXOff+(iY-nSrcYOff)*nChunkXSize];
     361          408204 :                             if (pabySrcScanlineNodataMask == NULL ||
     362          152000 :                                 pabySrcScanlineNodataMask[iX-nChunkXOff+(iY-nSrcYOff)*nChunkXSize])
     363                 :                             {
     364          236904 :                                 dfTotal += val;
     365          236904 :                                 nCount++;
     366                 :                             }
     367                 :                         }
     368                 :                     }
     369                 : 
     370           57800 :                     if (bHasNoData && nCount == 0)
     371                 :                     {
     372            4800 :                         pafDstScanline[iDstPixel - nDstXOff] = fNoDataValue;
     373                 :                     }
     374                 :                     else
     375                 :                     {
     376           48200 :                         if( nCount == 0 )
     377               0 :                             pafDstScanline[iDstPixel - nDstXOff] = 0.0;
     378                 :                         else
     379           48200 :                             pafDstScanline[iDstPixel - nDstXOff] = (float) (dfTotal / nCount);
     380                 :                     }
     381                 :                 }
     382                 :                 else
     383                 :                 {
     384                 :                     double val;
     385             200 :                     int    nTotalR = 0, nTotalG = 0, nTotalB = 0;
     386             200 :                     int    nCount = 0, iX, iY;
     387                 : 
     388             600 :                     for( iY = nSrcYOff; iY < nSrcYOff2; iY++ )
     389                 :                     {
     390            1200 :                         for( iX = nSrcXOff; iX < nSrcXOff2; iX++ )
     391                 :                         {
     392             800 :                             val = pafSrcScanline[iX-nChunkXOff+(iY-nSrcYOff)*nChunkXSize];
     393             800 :                             if (bHasNoData == FALSE || val != fNoDataValue)
     394                 :                             {
     395             800 :                                 int nVal = (int)val;
     396             800 :                                 if (nVal >= 0 && nVal < nEntryCount)
     397                 :                                 {
     398             800 :                                     nTotalR += aEntries[nVal].c1;
     399             800 :                                     nTotalG += aEntries[nVal].c2;
     400             800 :                                     nTotalB += aEntries[nVal].c3;
     401             800 :                                     nCount++;
     402                 :                                 }
     403                 :                             }
     404                 :                         }
     405                 :                     }
     406                 : 
     407             200 :                     if (bHasNoData && nCount == 0)
     408                 :                     {
     409               0 :                         pafDstScanline[iDstPixel - nDstXOff] = fNoDataValue;
     410                 :                     }
     411                 :                     else
     412                 :                     {
     413                 :                         CPLAssert( nCount > 0 );
     414             200 :                         if( nCount == 0 )
     415               0 :                             pafDstScanline[iDstPixel - nDstXOff] = 0.0;
     416                 :                         else
     417                 :                         {
     418             200 :                             int nR = nTotalR / nCount, nG = nTotalG / nCount, nB = nTotalB / nCount;
     419                 :                             int i;
     420             200 :                             double dfMinDist = 0;
     421             200 :                             int iBestEntry = 0;
     422           51400 :                             for(i=0;i<nEntryCount;i++)
     423                 :                             {
     424          102400 :                                 double dfDist = (nR - aEntries[i].c1) *  (nR - aEntries[i].c1) +
     425          102400 :                                     (nG - aEntries[i].c2) *  (nG - aEntries[i].c2) +
     426          204800 :                                     (nB - aEntries[i].c3) *  (nB - aEntries[i].c3);
     427           51200 :                                 if (i == 0 || dfDist < dfMinDist)
     428                 :                                 {
     429             400 :                                     dfMinDist = dfDist;
     430             400 :                                     iBestEntry = i;
     431                 :                                 }
     432                 :                             }
     433             200 :                             pafDstScanline[iDstPixel - nDstXOff] = iBestEntry;
     434                 :                         }
     435                 :                     }
     436                 :                 }
     437                 :             }
     438            5900 :             else if ( eResampling == GRM_Mode )
     439                 :             {
     440            1950 :                 if (eSrcDataType != GDT_Byte || nEntryCount > 256)
     441                 :                 {
     442                 :                     /* I'm not sure how much sense it makes to run a majority
     443                 :                        filter on floating point data, but here it is for the sake
     444                 :                        of compatability. It won't look right on RGB images by the
     445                 :                        nature of the filter. */
     446             750 :                     int     nNumPx = (nSrcYOff2-nSrcYOff)*(nSrcXOff2-nSrcXOff);
     447             750 :                     int     iMaxInd = 0, iMaxVal = -1, iY, iX;
     448                 : 
     449             750 :                     if (nNumPx > nMaxNumPx)
     450                 :                     {
     451              12 :                         pafVals = (float*) CPLRealloc(pafVals, nNumPx * sizeof(float));
     452              12 :                         panSums = (int*) CPLRealloc(panSums, nNumPx * sizeof(int));
     453              12 :                         nMaxNumPx = nNumPx;
     454                 :                     }
     455                 : 
     456            2550 :                     for( iY = nSrcYOff; iY < nSrcYOff2; ++iY )
     457                 :                     {
     458            1800 :                         int     iTotYOff = (iY-nSrcYOff)*nChunkXSize-nChunkXOff;
     459            6600 :                         for( iX = nSrcXOff; iX < nSrcXOff2; ++iX )
     460                 :                         {
     461            4800 :                             if (pabySrcScanlineNodataMask == NULL ||
     462               0 :                                 pabySrcScanlineNodataMask[iX+iTotYOff])
     463                 :                             {
     464            4800 :                                 float fVal = pafSrcScanline[iX+iTotYOff];
     465                 :                                 int i;
     466                 : 
     467                 :                                 //Check array for existing entry
     468           23148 :                                 for( i = 0; i < iMaxInd; ++i )
     469           23436 :                                     if( pafVals[i] == fVal
     470            4668 :                                         && ++panSums[i] > panSums[iMaxVal] )
     471                 :                                     {
     472             420 :                                         iMaxVal = i;
     473             420 :                                         break;
     474                 :                                     }
     475                 : 
     476                 :                                 //Add to arr if entry not already there
     477            4800 :                                 if( i == iMaxInd )
     478                 :                                 {
     479            4380 :                                     pafVals[iMaxInd] = fVal;
     480            4380 :                                     panSums[iMaxInd] = 1;
     481                 : 
     482            4380 :                                     if( iMaxVal < 0 )
     483             750 :                                         iMaxVal = iMaxInd;
     484                 : 
     485            4380 :                                     ++iMaxInd;
     486                 :                                 }
     487                 :                             }
     488                 :                         }
     489                 :                     }
     490                 : 
     491             750 :                     if( iMaxVal == -1 )
     492               0 :                         pafDstScanline[iDstPixel - nDstXOff] = fNoDataValue;
     493                 :                     else
     494             750 :                         pafDstScanline[iDstPixel - nDstXOff] = pafVals[iMaxVal];
     495                 :                 }
     496                 :                 else /* if (eSrcDataType == GDT_Byte && nEntryCount < 256) */
     497                 :                 {
     498                 :                     /* So we go here for a paletted or non-paletted byte band */
     499                 :                     /* The input values are then between 0 and 255 */
     500             450 :                     int     anVals[256], nMaxVal = 0, iMaxInd = -1, iY, iX;
     501                 : 
     502             450 :                     memset(anVals, 0, 256*sizeof(int));
     503                 : 
     504            1450 :                     for( iY = nSrcYOff; iY < nSrcYOff2; ++iY )
     505                 :                     {
     506            1000 :                         int     iTotYOff = (iY-nSrcYOff)*nChunkXSize-nChunkXOff;
     507            3400 :                         for( iX = nSrcXOff; iX < nSrcXOff2; ++iX )
     508                 :                         {
     509            2400 :                             float  val = pafSrcScanline[iX+iTotYOff];
     510            2400 :                             if (bHasNoData == FALSE || val != fNoDataValue)
     511                 :                             {
     512            2400 :                                 int nVal = (int) val;
     513            2400 :                                 if ( ++anVals[nVal] > nMaxVal)
     514                 :                                 {
     515                 :                                     //Sum the density
     516                 :                                     //Is it the most common value so far?
     517             948 :                                     iMaxInd = nVal;
     518             948 :                                     nMaxVal = anVals[nVal];
     519                 :                                 }
     520                 :                             }
     521                 :                         }
     522                 :                     }
     523                 : 
     524             450 :                     if( iMaxInd == -1 )
     525               0 :                         pafDstScanline[iDstPixel - nDstXOff] = fNoDataValue;
     526                 :                     else
     527             450 :                         pafDstScanline[iDstPixel - nDstXOff] = iMaxInd;
     528                 :                 }
     529                 :             }
     530            4700 :             else if ( eResampling == GRM_Gauss )
     531                 :             {
     532            4700 :                 if (poColorTable == NULL)
     533                 :                 {
     534            4500 :                     double dfTotal = 0.0, val;
     535            4500 :                     int  nCount = 0, iX, iY;
     536            4500 :                     int  i = 0,j = 0;
     537            4500 :                     const int *panLineWeight = panGaussMatrix;
     538                 : 
     539           17760 :                     for( j=0, iY = nSrcYOff; iY < nSrcYOff2;
     540                 :                          iY++, j++, panLineWeight += nGaussMatrixDim )
     541                 :                     {
     542           52338 :                         for( i=0, iX = nSrcXOff; iX < nSrcXOff2; iX++,++i )
     543                 :                         {
     544           39078 :                             val = pafSrcScanline[iX-nChunkXOff+(iY-nSrcYOff)*nChunkXSize];
     545           71934 :                             if (pabySrcScanlineNodataMask == NULL ||
     546           32856 :                                 pabySrcScanlineNodataMask[iX-nChunkXOff+(iY-nSrcYOff)*nChunkXSize])
     547                 :                             {
     548           18372 :                                 int nWeight = panLineWeight[i];
     549           18372 :                                 dfTotal += val * nWeight;
     550           18372 :                                 nCount += nWeight;
     551                 :                             }
     552                 :                         }
     553                 :                     }
     554                 : 
     555            6714 :                     if (bHasNoData && nCount == 0)
     556                 :                     {
     557            2214 :                         pafDstScanline[iDstPixel - nDstXOff] = fNoDataValue;
     558                 :                     }
     559                 :                     else
     560                 :                     {
     561            2286 :                         if( nCount == 0 )
     562               0 :                             pafDstScanline[iDstPixel - nDstXOff] = 0.0;
     563                 :                         else
     564            2286 :                             pafDstScanline[iDstPixel - nDstXOff] = (float) (dfTotal / nCount);
     565                 :                     }
     566                 :                 }
     567                 :                 else 
     568                 :                 {
     569                 :                     double val;
     570             200 :                     int  nTotalR = 0, nTotalG = 0, nTotalB = 0;
     571             200 :                     int  nTotalWeight = 0, iX, iY;
     572             200 :                     int  i = 0,j = 0;
     573             200 :                     const int *panLineWeight = panGaussMatrix;
     574                 : 
     575             780 :                     for( j=0, iY = nSrcYOff; iY < nSrcYOff2; 
     576                 :                          iY++, j++, panLineWeight += nGaussMatrixDim )
     577                 :                     {
     578            2262 :                         for( i=0, iX = nSrcXOff; iX < nSrcXOff2; iX++,++i )
     579                 :                         {
     580            1682 :                             val = pafSrcScanline[iX-nChunkXOff+(iY-nSrcYOff)*nChunkXSize];
     581            1682 :                             if (bHasNoData == FALSE || val != fNoDataValue)
     582                 :                             {
     583            1682 :                                 int nVal = (int)val;
     584            1682 :                                 if (nVal >= 0 && nVal < nEntryCount)
     585                 :                                 {
     586            1682 :                                     int nWeight = panLineWeight[i];
     587            1682 :                                     nTotalR += aEntries[nVal].c1 * nWeight;
     588            1682 :                                     nTotalG += aEntries[nVal].c2 * nWeight;
     589            1682 :                                     nTotalB += aEntries[nVal].c3 * nWeight;
     590            1682 :                                     nTotalWeight += nWeight;
     591                 :                                 }
     592                 :                             }
     593                 :                         }
     594                 :                     }
     595                 : 
     596             200 :                     if (bHasNoData && nTotalWeight == 0)
     597                 :                     {
     598               0 :                         pafDstScanline[iDstPixel - nDstXOff] = fNoDataValue;
     599                 :                     }
     600                 :                     else
     601                 :                     {
     602                 :                         CPLAssert( nTotalWeight > 0 );
     603             200 :                         if( nTotalWeight == 0 )
     604               0 :                             pafDstScanline[iDstPixel - nDstXOff] = 0.0;
     605                 :                         else
     606                 :                         {
     607             200 :                             int nR = nTotalR / nTotalWeight, nG = nTotalG / nTotalWeight, nB = nTotalB / nTotalWeight;
     608                 :                             int i;
     609             200 :                             double dfMinDist = 0;
     610             200 :                             int iBestEntry = 0;
     611           51400 :                             for(i=0;i<nEntryCount;i++)
     612                 :                             {
     613          102400 :                                 double dfDist = (nR - aEntries[i].c1) *  (nR - aEntries[i].c1) +
     614          102400 :                                     (nG - aEntries[i].c2) *  (nG - aEntries[i].c2) +
     615          204800 :                                     (nB - aEntries[i].c3) *  (nB - aEntries[i].c3);
     616           51200 :                                 if (i == 0 || dfDist < dfMinDist)
     617                 :                                 {
     618             400 :                                     dfMinDist = dfDist;
     619             400 :                                     iBestEntry = i;
     620                 :                                 }
     621                 :                             }
     622             200 :                             pafDstScanline[iDstPixel - nDstXOff] = iBestEntry;
     623                 :                         }
     624                 :                     }
     625                 :                 }
     626                 :             } // end of gauss
     627                 :         }
     628                 : 
     629                 :         eErr = poOverview->RasterIO( GF_Write, nDstXOff, iDstLine, nDstXOff2 - nDstXOff, 1, 
     630                 :                                      pafDstScanline, nDstXOff2 - nDstXOff, 1, GDT_Float32, 
     631           10640 :                                      0, 0 );
     632                 :     }
     633                 : 
     634             538 :     CPLFree( pafDstScanline );
     635             538 :     CPLFree( aEntries );
     636             538 :     CPLFree( pafVals );
     637             538 :     CPLFree( panSums );
     638                 : 
     639             538 :     return eErr;
     640                 : }
     641                 : 
     642                 : /************************************************************************/
     643                 : /*                       GDALDownsampleChunkC32R()                      */
     644                 : /************************************************************************/
     645                 : 
     646                 : static CPLErr
     647               0 : GDALDownsampleChunkC32R( int nSrcWidth, int nSrcHeight, 
     648                 :                          float * pafChunk, int nChunkYOff, int nChunkYSize,
     649                 :                          GDALRasterBand * poOverview,
     650                 :                          const char * pszResampling )
     651                 :     
     652                 : {
     653                 :     int      nDstYOff, nDstYOff2, nOXSize, nOYSize;
     654                 :     float    *pafDstScanline;
     655               0 :     CPLErr   eErr = CE_None;
     656                 : 
     657               0 :     nOXSize = poOverview->GetXSize();
     658               0 :     nOYSize = poOverview->GetYSize();
     659                 : 
     660               0 :     pafDstScanline = (float *) VSIMalloc(nOXSize * sizeof(float) * 2);
     661               0 :     if( pafDstScanline == NULL )
     662                 :     {
     663                 :         CPLError( CE_Failure, CPLE_OutOfMemory,
     664               0 :                   "GDALDownsampleChunkC32R: Out of memory for line buffer." );
     665               0 :         return CE_Failure;
     666                 :     }
     667                 : 
     668                 : /* -------------------------------------------------------------------- */
     669                 : /*      Figure out the line to start writing to, and the first line     */
     670                 : /*      to not write to.  In theory this approach should ensure that    */
     671                 : /*      every output line will be written if all input chunks are       */
     672                 : /*      processed.                                                      */
     673                 : /* -------------------------------------------------------------------- */
     674               0 :     nDstYOff = (int) (0.5 + (nChunkYOff/(double)nSrcHeight) * nOYSize);
     675                 :     nDstYOff2 = (int) 
     676               0 :         (0.5 + ((nChunkYOff+nChunkYSize)/(double)nSrcHeight) * nOYSize);
     677                 : 
     678               0 :     if( nChunkYOff + nChunkYSize == nSrcHeight )
     679               0 :         nDstYOff2 = nOYSize;
     680                 :     
     681                 : /* ==================================================================== */
     682                 : /*      Loop over destination scanlines.                                */
     683                 : /* ==================================================================== */
     684               0 :     for( int iDstLine = nDstYOff; iDstLine < nDstYOff2 && eErr == CE_None; iDstLine++ )
     685                 :     {
     686                 :         float *pafSrcScanline;
     687                 :         int   nSrcYOff, nSrcYOff2, iDstPixel;
     688                 : 
     689               0 :         nSrcYOff = (int) (0.5 + (iDstLine/(double)nOYSize) * nSrcHeight);
     690               0 :         if( nSrcYOff < nChunkYOff )
     691               0 :             nSrcYOff = nChunkYOff;
     692                 :         
     693               0 :         nSrcYOff2 = (int) (0.5 + ((iDstLine+1)/(double)nOYSize) * nSrcHeight);
     694               0 :         if( nSrcYOff2 > nSrcHeight || iDstLine == nOYSize-1 )
     695               0 :             nSrcYOff2 = nSrcHeight;
     696               0 :         if( nSrcYOff2 > nChunkYOff + nChunkYSize )
     697               0 :             nSrcYOff2 = nChunkYOff + nChunkYSize;
     698                 : 
     699               0 :         pafSrcScanline = pafChunk + ((nSrcYOff-nChunkYOff) * nSrcWidth) * 2;
     700                 : 
     701                 : /* -------------------------------------------------------------------- */
     702                 : /*      Loop over destination pixels                                    */
     703                 : /* -------------------------------------------------------------------- */
     704               0 :         for( iDstPixel = 0; iDstPixel < nOXSize; iDstPixel++ )
     705                 :         {
     706                 :             int   nSrcXOff, nSrcXOff2;
     707                 : 
     708               0 :             nSrcXOff = (int) (0.5 + (iDstPixel/(double)nOXSize) * nSrcWidth);
     709                 :             nSrcXOff2 = (int) 
     710               0 :                 (0.5 + ((iDstPixel+1)/(double)nOXSize) * nSrcWidth);
     711               0 :             if( nSrcXOff2 > nSrcWidth )
     712               0 :                 nSrcXOff2 = nSrcWidth;
     713                 :             
     714               0 :             if( EQUALN(pszResampling,"NEAR",4) )
     715                 :             {
     716               0 :                 pafDstScanline[iDstPixel*2] = pafSrcScanline[nSrcXOff*2];
     717               0 :                 pafDstScanline[iDstPixel*2+1] = pafSrcScanline[nSrcXOff*2+1];
     718                 :             }
     719               0 :             else if( EQUAL(pszResampling,"AVERAGE_MAGPHASE") )
     720                 :             {
     721               0 :                 double dfTotalR = 0.0, dfTotalI = 0.0, dfTotalM = 0.0;
     722               0 :                 int    nCount = 0, iX, iY;
     723                 : 
     724               0 :                 for( iY = nSrcYOff; iY < nSrcYOff2; iY++ )
     725                 :                 {
     726               0 :                     for( iX = nSrcXOff; iX < nSrcXOff2; iX++ )
     727                 :                     {
     728                 :                         double  dfR, dfI;
     729                 : 
     730               0 :                         dfR = pafSrcScanline[iX*2+(iY-nSrcYOff)*nSrcWidth*2];
     731               0 :                         dfI = pafSrcScanline[iX*2+(iY-nSrcYOff)*nSrcWidth*2+1];
     732               0 :                         dfTotalR += dfR;
     733               0 :                         dfTotalI += dfI;
     734               0 :                         dfTotalM += sqrt( dfR*dfR + dfI*dfI );
     735               0 :                         nCount++;
     736                 :                     }
     737                 :                 }
     738                 :                 
     739                 :                 CPLAssert( nCount > 0 );
     740               0 :                 if( nCount == 0 )
     741                 :                 {
     742               0 :                     pafDstScanline[iDstPixel*2] = 0.0;
     743               0 :                     pafDstScanline[iDstPixel*2+1] = 0.0;
     744                 :                 }
     745                 :                 else
     746                 :                 {
     747               0 :                     double      dfM, dfDesiredM, dfRatio=1.0;
     748                 : 
     749               0 :                     pafDstScanline[iDstPixel*2  ] = (float) (dfTotalR/nCount);
     750               0 :                     pafDstScanline[iDstPixel*2+1] = (float) (dfTotalI/nCount);
     751                 :                     
     752               0 :                     dfM = sqrt(pafDstScanline[iDstPixel*2  ]*pafDstScanline[iDstPixel*2  ]
     753               0 :                              + pafDstScanline[iDstPixel*2+1]*pafDstScanline[iDstPixel*2+1]);
     754               0 :                     dfDesiredM = dfTotalM / nCount;
     755               0 :                     if( dfM != 0.0 )
     756               0 :                         dfRatio = dfDesiredM / dfM;
     757                 : 
     758               0 :                     pafDstScanline[iDstPixel*2  ] *= (float) dfRatio;
     759               0 :                     pafDstScanline[iDstPixel*2+1] *= (float) dfRatio;
     760                 :                 }
     761                 :             }
     762               0 :             else if( EQUALN(pszResampling,"AVER",4) )
     763                 :             {
     764               0 :                 double dfTotalR = 0.0, dfTotalI = 0.0;
     765               0 :                 int    nCount = 0, iX, iY;
     766                 : 
     767               0 :                 for( iY = nSrcYOff; iY < nSrcYOff2; iY++ )
     768                 :                 {
     769               0 :                     for( iX = nSrcXOff; iX < nSrcXOff2; iX++ )
     770                 :                     {
     771               0 :                         dfTotalR += pafSrcScanline[iX*2+(iY-nSrcYOff)*nSrcWidth*2];
     772               0 :                         dfTotalI += pafSrcScanline[iX*2+(iY-nSrcYOff)*nSrcWidth*2+1];
     773               0 :                         nCount++;
     774                 :                     }
     775                 :                 }
     776                 :                 
     777                 :                 CPLAssert( nCount > 0 );
     778               0 :                 if( nCount == 0 )
     779                 :                 {
     780               0 :                     pafDstScanline[iDstPixel*2] = 0.0;
     781               0 :                     pafDstScanline[iDstPixel*2+1] = 0.0;
     782                 :                 }
     783                 :                 else
     784                 :                 {
     785               0 :                     pafDstScanline[iDstPixel*2  ] = (float) (dfTotalR/nCount);
     786               0 :                     pafDstScanline[iDstPixel*2+1] = (float) (dfTotalI/nCount);
     787                 :                 }
     788                 :             }
     789                 :         }
     790                 : 
     791                 :         eErr = poOverview->RasterIO( GF_Write, 0, iDstLine, nOXSize, 1, 
     792                 :                                      pafDstScanline, nOXSize, 1, GDT_CFloat32, 
     793               0 :                                      0, 0 );
     794                 :     }
     795                 : 
     796               0 :     CPLFree( pafDstScanline );
     797                 : 
     798               0 :     return eErr;
     799                 : }
     800                 : 
     801                 : /************************************************************************/
     802                 : /*                  GDALRegenerateCascadingOverviews()                  */
     803                 : /*                                                                      */
     804                 : /*      Generate a list of overviews in order from largest to           */
     805                 : /*      smallest, computing each from the next larger.                  */
     806                 : /************************************************************************/
     807                 : 
     808                 : static CPLErr
     809              12 : GDALRegenerateCascadingOverviews( 
     810                 :     GDALRasterBand *poSrcBand, int nOverviews, GDALRasterBand **papoOvrBands, 
     811                 :     const char * pszResampling, 
     812                 :     GDALProgressFunc pfnProgress, void * pProgressData )
     813                 : 
     814                 : {
     815                 : /* -------------------------------------------------------------------- */
     816                 : /*      First, we must put the overviews in order from largest to       */
     817                 : /*      smallest.                                                       */
     818                 : /* -------------------------------------------------------------------- */
     819                 :     int   i, j;
     820                 : 
     821              24 :     for( i = 0; i < nOverviews-1; i++ )
     822                 :     {
     823              24 :         for( j = 0; j < nOverviews - i - 1; j++ )
     824                 :         {
     825                 : 
     826              48 :             if( papoOvrBands[j]->GetXSize() 
     827              12 :                 * (float) papoOvrBands[j]->GetYSize() <
     828              12 :                 papoOvrBands[j+1]->GetXSize()
     829              12 :                 * (float) papoOvrBands[j+1]->GetYSize() )
     830                 :             {
     831                 :                 GDALRasterBand * poTempBand;
     832                 : 
     833               0 :                 poTempBand = papoOvrBands[j];
     834               0 :                 papoOvrBands[j] = papoOvrBands[j+1];
     835               0 :                 papoOvrBands[j+1] = poTempBand;
     836                 :             }
     837                 :         }
     838                 :     }
     839                 : 
     840                 : /* -------------------------------------------------------------------- */
     841                 : /*      Count total pixels so we can prepare appropriate scaled         */
     842                 : /*      progress functions.                                             */
     843                 : /* -------------------------------------------------------------------- */
     844              12 :     double       dfTotalPixels = 0.0;
     845                 : 
     846              36 :     for( i = 0; i < nOverviews; i++ )
     847                 :     {
     848              24 :         dfTotalPixels += papoOvrBands[i]->GetXSize()
     849              48 :             * (double) papoOvrBands[i]->GetYSize();
     850                 :     }
     851                 : 
     852                 : /* -------------------------------------------------------------------- */
     853                 : /*      Generate all the bands.                                         */
     854                 : /* -------------------------------------------------------------------- */
     855              12 :     double      dfPixelsProcessed = 0.0;
     856                 : 
     857              36 :     for( i = 0; i < nOverviews; i++ )
     858                 :     {
     859                 :         void    *pScaledProgressData;
     860                 :         double  dfPixels;
     861                 :         GDALRasterBand *poBaseBand;
     862                 :         CPLErr  eErr;
     863                 : 
     864              24 :         if( i == 0 )
     865              12 :             poBaseBand = poSrcBand;
     866                 :         else
     867              12 :             poBaseBand = papoOvrBands[i-1];
     868                 : 
     869              24 :         dfPixels = papoOvrBands[i]->GetXSize() 
     870              48 :             * (double) papoOvrBands[i]->GetYSize();
     871                 : 
     872                 :         pScaledProgressData = GDALCreateScaledProgress( 
     873                 :             dfPixelsProcessed / dfTotalPixels,
     874                 :             (dfPixelsProcessed + dfPixels) / dfTotalPixels, 
     875              24 :             pfnProgress, pProgressData );
     876                 : 
     877                 :         eErr = GDALRegenerateOverviews( (GDALRasterBandH) poBaseBand, 
     878                 :                                         1, (GDALRasterBandH *) papoOvrBands+i, 
     879                 :                                         pszResampling, 
     880                 :                                         GDALScaledProgress, 
     881              24 :                                         pScaledProgressData );
     882              24 :         GDALDestroyScaledProgress( pScaledProgressData );
     883                 : 
     884              24 :         if( eErr != CE_None )
     885               0 :             return eErr;
     886                 : 
     887              24 :         dfPixelsProcessed += dfPixels;
     888                 : 
     889                 :         /* we only do the bit2grayscale promotion on the base band */
     890              24 :         if( EQUALN(pszResampling,"AVERAGE_BIT2GRAYSCALE",13) )
     891               4 :             pszResampling = "AVERAGE";
     892                 :     }
     893                 : 
     894              12 :     return CE_None;
     895                 : }
     896                 : 
     897                 : /************************************************************************/
     898                 : /*                      GDALRegenerateOverviews()                       */
     899                 : /************************************************************************/
     900                 : 
     901                 : /**
     902                 :  * \brief Generate downsampled overviews.
     903                 :  *
     904                 :  * This function will generate one or more overview images from a base
     905                 :  * image using the requested downsampling algorithm.  It's primary use
     906                 :  * is for generating overviews via GDALDataset::BuildOverviews(), but it
     907                 :  * can also be used to generate downsampled images in one file from another
     908                 :  * outside the overview architecture.
     909                 :  *
     910                 :  * The output bands need to exist in advance. 
     911                 :  *
     912                 :  * The full set of resampling algorithms is documented in 
     913                 :  * GDALDataset::BuildOverviews().
     914                 :  *
     915                 :  * This function will honour properly NODATA_VALUES tuples (special dataset metadata) so
     916                 :  * that only a given RGB triplet (in case of a RGB image) will be considered as the
     917                 :  * nodata value and not each value of the triplet independantly per band.
     918                 :  *
     919                 :  * @param hSrcBand the source (base level) band. 
     920                 :  * @param nOverviewCount the number of downsampled bands being generated.
     921                 :  * @param pahOvrBands the list of downsampled bands to be generated.
     922                 :  * @param pszResampling Resampling algorithm (eg. "AVERAGE"). 
     923                 :  * @param pfnProgress progress report function.
     924                 :  * @param pProgressData progress function callback data.
     925                 :  * @return CE_None on success or CE_Failure on failure.
     926                 :  */
     927                 : CPLErr 
     928             160 : GDALRegenerateOverviews( GDALRasterBandH hSrcBand,
     929                 :                          int nOverviewCount, GDALRasterBandH *pahOvrBands, 
     930                 :                          const char * pszResampling, 
     931                 :                          GDALProgressFunc pfnProgress, void * pProgressData )
     932                 : 
     933                 : {
     934             160 :     GDALRasterBand *poSrcBand = (GDALRasterBand *) hSrcBand;
     935             160 :     GDALRasterBand **papoOvrBands = (GDALRasterBand **) pahOvrBands;
     936                 :     int    nFullResYChunk, nWidth;
     937                 :     int    nFRXBlockSize, nFRYBlockSize;
     938                 :     GDALDataType eType;
     939                 :     int    bHasNoData;
     940                 :     float  fNoDataValue;
     941             160 :     GDALColorTable* poColorTable = NULL;
     942                 : 
     943             160 :     if( pfnProgress == NULL )
     944               4 :         pfnProgress = GDALDummyProgress;
     945                 : 
     946             160 :     if( EQUAL(pszResampling,"NONE") )
     947               8 :         return CE_None;
     948                 : 
     949                 : /* -------------------------------------------------------------------- */
     950                 : /*      Check color tables...                                           */
     951                 : /* -------------------------------------------------------------------- */
     952             219 :     if ((EQUALN(pszResampling,"AVER",4)
     953                 :          || EQUALN(pszResampling,"MODE",4)
     954                 :          || EQUALN(pszResampling,"GAUSS",5)) &&
     955              67 :         poSrcBand->GetColorInterpretation() == GCI_PaletteIndex)
     956                 :     {
     957               6 :         poColorTable = poSrcBand->GetColorTable();
     958               6 :         if (poColorTable != NULL)
     959                 :         {
     960               6 :             if (poColorTable->GetPaletteInterpretation() != GPI_RGB)
     961                 :             {
     962                 :                 CPLError(CE_Warning, CPLE_AppDefined,
     963                 :                         "Computing overviews on palette index raster bands "
     964                 :                         "with a palette whose color interpreation is not RGB "
     965               0 :                         "will probably lead to unexpected results.");
     966               0 :                 poColorTable = NULL;
     967                 :             }
     968                 :         }
     969                 :         else
     970                 :         {
     971                 :             CPLError(CE_Warning, CPLE_AppDefined,
     972                 :                     "Computing overviews on palette index raster bands "
     973               0 :                     "without a palette will probably lead to unexpected results.");
     974                 :         }
     975                 :     }
     976                 : 
     977                 : 
     978                 :     /* If we have a nodata mask and we are doing something more complicated */
     979                 :     /* than nearest neighbouring, we have to fetch to nodata mask */ 
     980                 :     int bUseNoDataMask = (!EQUALN(pszResampling,"NEAR",4) &&
     981             152 :                           (poSrcBand->GetMaskFlags() & GMF_ALL_VALID) == 0);
     982                 : 
     983                 : /* -------------------------------------------------------------------- */
     984                 : /*      If we are operating on multiple overviews, and using            */
     985                 : /*      averaging, lets do them in cascading order to reduce the        */
     986                 : /*      amount of computation.                                          */
     987                 : /* -------------------------------------------------------------------- */
     988                 : 
     989                 :     /* In case the mask made be computed from another band of the dataset, */
     990                 :     /* we can't use cascaded generation, as the computation of the overviews */
     991                 :     /* of the band used for the mask band may not have yet occured (#3033) */
     992             158 :     if( (EQUALN(pszResampling,"AVER",4) || EQUALN(pszResampling,"GAUSS",5)) && nOverviewCount > 1
     993               6 :          && !(bUseNoDataMask && poSrcBand->GetMaskFlags() != GMF_NODATA))
     994                 :         return GDALRegenerateCascadingOverviews( poSrcBand, 
     995                 :                                                  nOverviewCount, papoOvrBands,
     996                 :                                                  pszResampling, 
     997                 :                                                  pfnProgress,
     998              12 :                                                  pProgressData );
     999                 : 
    1000                 : /* -------------------------------------------------------------------- */
    1001                 : /*      Setup one horizontal swath to read from the raw buffer.         */
    1002                 : /* -------------------------------------------------------------------- */
    1003                 :     float *pafChunk;
    1004             140 :     GByte *pabyChunkNodataMask = NULL;
    1005                 : 
    1006             140 :     poSrcBand->GetBlockSize( &nFRXBlockSize, &nFRYBlockSize );
    1007                 :     
    1008             160 :     if( nFRYBlockSize < 16 || nFRYBlockSize > 256 )
    1009              20 :         nFullResYChunk = 64;
    1010                 :     else
    1011             120 :         nFullResYChunk = nFRYBlockSize;
    1012                 : 
    1013             140 :     if( GDALDataTypeIsComplex( poSrcBand->GetRasterDataType() ) )
    1014               0 :         eType = GDT_CFloat32;
    1015                 :     else
    1016             140 :         eType = GDT_Float32;
    1017                 : 
    1018             140 :     nWidth = poSrcBand->GetXSize();
    1019                 :     pafChunk = (float *) 
    1020             140 :         VSIMalloc3((GDALGetDataTypeSize(eType)/8), nFullResYChunk, nWidth );
    1021             140 :     if (bUseNoDataMask)
    1022                 :     {
    1023                 :         pabyChunkNodataMask = (GByte *) 
    1024              17 :             (GByte*) VSIMalloc2( nFullResYChunk, nWidth );
    1025                 :     }
    1026                 : 
    1027             140 :     if( pafChunk == NULL || (bUseNoDataMask && pabyChunkNodataMask == NULL))
    1028                 :     {
    1029               0 :         CPLFree(pafChunk);
    1030               0 :         CPLFree(pabyChunkNodataMask);
    1031                 :         CPLError( CE_Failure, CPLE_OutOfMemory, 
    1032               0 :                   "Out of memory in GDALRegenerateOverviews()." );
    1033                 : 
    1034               0 :         return CE_Failure;
    1035                 :     }
    1036                 : 
    1037             140 :     fNoDataValue = (float) poSrcBand->GetNoDataValue(&bHasNoData);
    1038                 : 
    1039                 : /* -------------------------------------------------------------------- */
    1040                 : /*      Loop over image operating on chunks.                            */
    1041                 : /* -------------------------------------------------------------------- */
    1042             140 :     int  nChunkYOff = 0;
    1043             140 :     CPLErr eErr = CE_None;
    1044                 : 
    1045             441 :     for( nChunkYOff = 0; 
    1046                 :          nChunkYOff < poSrcBand->GetYSize() && eErr == CE_None; 
    1047                 :          nChunkYOff += nFullResYChunk )
    1048                 :     {
    1049             301 :         if( !pfnProgress( nChunkYOff / (double) poSrcBand->GetYSize(), 
    1050                 :                           NULL, pProgressData ) )
    1051                 :         {
    1052               0 :             CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
    1053               0 :             eErr = CE_Failure;
    1054                 :         }
    1055                 : 
    1056             301 :         if( nFullResYChunk + nChunkYOff > poSrcBand->GetYSize() )
    1057              46 :             nFullResYChunk = poSrcBand->GetYSize() - nChunkYOff;
    1058                 :         
    1059                 :         /* read chunk */
    1060             301 :         if (eErr == CE_None)
    1061                 :             eErr = poSrcBand->RasterIO( GF_Read, 0, nChunkYOff, nWidth, nFullResYChunk, 
    1062                 :                                 pafChunk, nWidth, nFullResYChunk, eType,
    1063             301 :                                 0, 0 );
    1064             301 :         if (eErr == CE_None && bUseNoDataMask)
    1065              41 :             eErr = poSrcBand->GetMaskBand()->RasterIO( GF_Read, 0, nChunkYOff, nWidth, nFullResYChunk, 
    1066                 :                                 pabyChunkNodataMask, nWidth, nFullResYChunk, GDT_Byte,
    1067              41 :                                 0, 0 );
    1068                 : 
    1069                 :         /* special case to promote 1bit data to 8bit 0/255 values */
    1070             301 :         if( EQUAL(pszResampling,"AVERAGE_BIT2GRAYSCALE") )
    1071                 :         {
    1072                 :             int i;
    1073                 : 
    1074           39208 :             for( i = nFullResYChunk*nWidth - 1; i >= 0; i-- )
    1075                 :             {
    1076           39204 :                 if( pafChunk[i] == 1.0 )
    1077           23672 :                     pafChunk[i] = 255.0;
    1078                 :             }
    1079                 :         }
    1080             297 :         else if( EQUAL(pszResampling,"AVERAGE_BIT2GRAYSCALE_MINISWHITE") )
    1081                 :         {
    1082                 :             int i;
    1083                 : 
    1084               0 :             for( i = nFullResYChunk*nWidth - 1; i >= 0; i-- )
    1085                 :             {
    1086               0 :                 if( pafChunk[i] == 1.0 )
    1087               0 :                     pafChunk[i] = 0.0;
    1088               0 :                 else if( pafChunk[i] == 0.0 )
    1089               0 :                     pafChunk[i] = 255.0;
    1090                 :             }
    1091                 :         }
    1092                 :         
    1093             815 :         for( int iOverview = 0; iOverview < nOverviewCount && eErr == CE_None; iOverview++ )
    1094                 :         {
    1095             514 :             if( eType == GDT_Float32 )
    1096                 :                 eErr = GDALDownsampleChunk32R(nWidth, poSrcBand->GetYSize(), 
    1097                 :                                               pafChunk,
    1098                 :                                               pabyChunkNodataMask,
    1099                 :                                               0, nWidth,
    1100                 :                                               nChunkYOff, nFullResYChunk,
    1101                 :                                               papoOvrBands[iOverview], pszResampling,
    1102                 :                                               bHasNoData, fNoDataValue, poColorTable,
    1103             514 :                                               poSrcBand->GetRasterDataType());
    1104                 :             else
    1105                 :                 eErr = GDALDownsampleChunkC32R(nWidth, poSrcBand->GetYSize(), 
    1106                 :                                                pafChunk, nChunkYOff, nFullResYChunk,
    1107               0 :                                                papoOvrBands[iOverview], pszResampling);
    1108                 :         }
    1109                 :     }
    1110                 : 
    1111             140 :     VSIFree( pafChunk );
    1112             140 :     VSIFree( pabyChunkNodataMask );
    1113                 :     
    1114                 : /* -------------------------------------------------------------------- */
    1115                 : /*      Renormalized overview mean / stddev if needed.                  */
    1116                 : /* -------------------------------------------------------------------- */
    1117             140 :     if( eErr == CE_None && EQUAL(pszResampling,"AVERAGE_MP") )
    1118                 :     {
    1119                 :         GDALOverviewMagnitudeCorrection( (GDALRasterBandH) poSrcBand, 
    1120                 :                                          nOverviewCount, 
    1121                 :                                          (GDALRasterBandH *) papoOvrBands,
    1122               0 :                                          GDALDummyProgress, NULL );
    1123                 :     }
    1124                 : 
    1125                 : /* -------------------------------------------------------------------- */
    1126                 : /*      It can be important to flush out data to overviews.             */
    1127                 : /* -------------------------------------------------------------------- */
    1128             348 :     for( int iOverview = 0; 
    1129                 :          eErr == CE_None && iOverview < nOverviewCount; 
    1130                 :          iOverview++ )
    1131                 :     {
    1132             208 :         eErr = papoOvrBands[iOverview]->FlushCache();
    1133                 :     }
    1134                 : 
    1135             140 :     if (eErr == CE_None)
    1136             140 :         pfnProgress( 1.0, NULL, pProgressData );
    1137                 : 
    1138             140 :     return eErr;
    1139                 : }
    1140                 : 
    1141                 : 
    1142                 : 
    1143                 : /************************************************************************/
    1144                 : /*            GDALRegenerateOverviewsMultiBand()                        */
    1145                 : /************************************************************************/
    1146                 : 
    1147                 : /**
    1148                 :  * \brief Variant of GDALRegenerateOverviews, specialy dedicated for generating
    1149                 :  * compressed pixel-interleaved overviews (JPEG-IN-TIFF for example)
    1150                 :  *
    1151                 :  * This function will generate one or more overview images from a base
    1152                 :  * image using the requested downsampling algorithm.  It's primary use
    1153                 :  * is for generating overviews via GDALDataset::BuildOverviews(), but it
    1154                 :  * can also be used to generate downsampled images in one file from another
    1155                 :  * outside the overview architecture.
    1156                 :  *
    1157                 :  * The output bands need to exist in advance and share the same characteristics
    1158                 :  * (type, dimensions)
    1159                 :  *
    1160                 :  * The resampling algorithms supported for the moment are "NEAREST", "AVERAGE"
    1161                 :  * and "GAUSS"
    1162                 :  *
    1163                 :  * The pseudo-algorithm used by the function is :
    1164                 :  *    for each overview
    1165                 :  *       iterate on lines of the source by a step of deltay
    1166                 :  *           iterate on columns of the source  by a step of deltax
    1167                 :  *               read the source data of size deltax * deltay for all the bands
    1168                 :  *               generate the corresponding overview block for all the bands
    1169                 :  *
    1170                 :  * This function will honour properly NODATA_VALUES tuples (special dataset metadata) so
    1171                 :  * that only a given RGB triplet (in case of a RGB image) will be considered as the
    1172                 :  * nodata value and not each value of the triplet independantly per band.
    1173                 :  *
    1174                 :  * @param nBands the number of bands, size of papoSrcBands and size of
    1175                 :  *               first dimension of papapoOverviewBands
    1176                 :  * @param papoSrcBands the list of source bands to downsample
    1177                 :  * @param nOverviews the number of downsampled overview levels being generated.
    1178                 :  * @param papapoOverviewBands bidimension array of bands. First dimension is indexed
    1179                 :  *                            by nBands. Second dimension is indexed by nOverviews.
    1180                 :  * @param pszResampling Resampling algorithm ("NEAREST", "AVERAGE" or "GAUSS"). 
    1181                 :  * @param pfnProgress progress report function.
    1182                 :  * @param pProgressData progress function callback data.
    1183                 :  * @return CE_None on success or CE_Failure on failure.
    1184                 :  */
    1185                 : 
    1186                 : CPLErr 
    1187               8 : GDALRegenerateOverviewsMultiBand(int nBands, GDALRasterBand** papoSrcBands,
    1188                 :                                  int nOverviews,
    1189                 :                                  GDALRasterBand*** papapoOverviewBands,
    1190                 :                                  const char * pszResampling, 
    1191                 :                                  GDALProgressFunc pfnProgress, void * pProgressData )
    1192                 : {
    1193               8 :     CPLErr eErr = CE_None;
    1194                 :     int iOverview, iBand;
    1195                 : 
    1196               8 :     if( pfnProgress == NULL )
    1197               0 :         pfnProgress = GDALDummyProgress;
    1198                 : 
    1199               8 :     if( EQUAL(pszResampling,"NONE") )
    1200               0 :         return CE_None;
    1201                 : 
    1202                 :     /* Sanity checks */
    1203               8 :     if (!EQUALN(pszResampling, "NEAR", 4) && !EQUAL(pszResampling, "AVERAGE") && !EQUAL(pszResampling, "GAUSS"))
    1204                 :     {
    1205                 :         CPLError(CE_Failure, CPLE_NotSupported,
    1206               0 :                  "GDALRegenerateOverviewsMultiBand: pszResampling='%s' not supported", pszResampling);
    1207               0 :         return CE_Failure;
    1208                 :     }
    1209                 : 
    1210               8 :     int nSrcWidth = papoSrcBands[0]->GetXSize();
    1211               8 :     int nSrcHeight = papoSrcBands[0]->GetYSize();
    1212               8 :     GDALDataType eDataType = papoSrcBands[0]->GetRasterDataType();
    1213              24 :     for(iBand=1;iBand<nBands;iBand++)
    1214                 :     {
    1215              32 :         if (papoSrcBands[iBand]->GetXSize() != nSrcWidth ||
    1216              16 :             papoSrcBands[iBand]->GetYSize() != nSrcHeight)
    1217                 :         {
    1218                 :             CPLError(CE_Failure, CPLE_NotSupported,
    1219               0 :                     "GDALRegenerateOverviewsMultiBand: all the source bands must have the same dimensions");
    1220               0 :             return CE_Failure;
    1221                 :         }
    1222              16 :         if (papoSrcBands[iBand]->GetRasterDataType() != eDataType)
    1223                 :         {
    1224                 :             CPLError(CE_Failure, CPLE_NotSupported,
    1225               0 :                     "GDALRegenerateOverviewsMultiBand: all the source bands must have the same data type");
    1226               0 :             return CE_Failure;
    1227                 :         }
    1228                 :     }
    1229                 : 
    1230              16 :     for(iOverview=0;iOverview<nOverviews;iOverview++)
    1231                 :     {
    1232               8 :         int nDstWidth = papapoOverviewBands[0][iOverview]->GetXSize();
    1233               8 :         int nDstHeight = papapoOverviewBands[0][iOverview]->GetYSize();
    1234              24 :         for(iBand=1;iBand<nBands;iBand++)
    1235                 :         {
    1236              48 :             if (papapoOverviewBands[iBand][iOverview]->GetXSize() != nDstWidth ||
    1237              32 :                 papapoOverviewBands[iBand][iOverview]->GetYSize() != nDstHeight)
    1238                 :             {
    1239                 :                 CPLError(CE_Failure, CPLE_NotSupported,
    1240               0 :                         "GDALRegenerateOverviewsMultiBand: all the overviews bands of the same level must have the same dimensions");
    1241               0 :                 return CE_Failure;
    1242                 :             }
    1243              16 :             if (papapoOverviewBands[iBand][iOverview]->GetRasterDataType() != eDataType)
    1244                 :             {
    1245                 :                 CPLError(CE_Failure, CPLE_NotSupported,
    1246               0 :                         "GDALRegenerateOverviewsMultiBand: all the overviews bands must have the same data type as the source bands");
    1247               0 :                 return CE_Failure;
    1248                 :             }
    1249                 :         }
    1250                 :     }
    1251                 : 
    1252                 :     /* First pass to compute the total number of pixels to read */
    1253               8 :     double dfTotalPixelCount = 0;
    1254              16 :     for(iOverview=0;iOverview<nOverviews;iOverview++)
    1255                 :     {
    1256               8 :         nSrcWidth = papoSrcBands[0]->GetXSize();
    1257               8 :         nSrcHeight = papoSrcBands[0]->GetYSize();
    1258                 : 
    1259               8 :         int nDstWidth = papapoOverviewBands[0][iOverview]->GetXSize();
    1260                 :         /* Try to use previous level of overview as the source to compute */
    1261                 :         /* the next level */
    1262               8 :         if (iOverview > 0 && papapoOverviewBands[0][iOverview - 1]->GetXSize() > nDstWidth)
    1263                 :         {
    1264               0 :             nSrcWidth = papapoOverviewBands[0][iOverview - 1]->GetXSize();
    1265               0 :             nSrcHeight = papapoOverviewBands[0][iOverview - 1]->GetYSize();
    1266                 :         }
    1267                 : 
    1268               8 :         dfTotalPixelCount += (double)nSrcWidth * nSrcHeight;
    1269                 :     }
    1270                 : 
    1271               8 :     nSrcWidth = papoSrcBands[0]->GetXSize();
    1272               8 :     nSrcHeight = papoSrcBands[0]->GetYSize();
    1273                 : 
    1274                 :     /* If we have a nodata mask and we are doing something more complicated */
    1275                 :     /* than nearest neighbouring, we have to fetch to nodata mask */ 
    1276                 :     int bUseNoDataMask = (!EQUALN(pszResampling,"NEAR",4) &&
    1277               8 :                           (papoSrcBands[0]->GetMaskFlags() & GMF_ALL_VALID) == 0);
    1278                 : 
    1279               8 :     int* pabHasNoData = (int*)CPLMalloc(nBands * sizeof(int));
    1280               8 :     float* pafNoDataValue = (float*)CPLMalloc(nBands * sizeof(float));
    1281                 : 
    1282              32 :     for(iBand=0;iBand<nBands;iBand++)
    1283                 :     {
    1284              24 :         pabHasNoData[iBand] = FALSE;
    1285              24 :         pafNoDataValue[iBand] = (float) papoSrcBands[iBand]->GetNoDataValue(&pabHasNoData[iBand]);
    1286                 :     }
    1287                 : 
    1288                 :     /* Second pass to do the real job ! */
    1289               8 :     double dfCurPixelCount = 0;
    1290              16 :     for(iOverview=0;iOverview<nOverviews && eErr == CE_None;iOverview++)
    1291                 :     {
    1292               8 :         int iSrcOverview = -1; /* -1 means the source bands */
    1293                 : 
    1294                 :         int nDstBlockXSize, nDstBlockYSize;
    1295                 :         int nDstWidth, nDstHeight;
    1296               8 :         papapoOverviewBands[0][iOverview]->GetBlockSize(&nDstBlockXSize, &nDstBlockYSize);
    1297               8 :         nDstWidth = papapoOverviewBands[0][iOverview]->GetXSize();
    1298               8 :         nDstHeight = papapoOverviewBands[0][iOverview]->GetYSize();
    1299                 : 
    1300                 :         /* Try to use previous level of overview as the source to compute */
    1301                 :         /* the next level */
    1302               8 :         if (iOverview > 0 && papapoOverviewBands[0][iOverview - 1]->GetXSize() > nDstWidth)
    1303                 :         {
    1304               0 :             nSrcWidth = papapoOverviewBands[0][iOverview - 1]->GetXSize();
    1305               0 :             nSrcHeight = papapoOverviewBands[0][iOverview - 1]->GetYSize();
    1306               0 :             iSrcOverview = iOverview - 1;
    1307                 :         }
    1308                 : 
    1309                 :         /* Compute the chunck size of the source such as it will match the size of */
    1310                 :         /* a block of the overview */
    1311               8 :         int nFullResXChunk = (nDstBlockXSize * nSrcWidth) / nDstWidth;
    1312               8 :         int nFullResYChunk = (nDstBlockYSize * nSrcHeight) / nDstHeight;
    1313                 : 
    1314               8 :         float** papafChunk = (float**) CPLMalloc(nBands * sizeof(void*));
    1315               8 :         GByte* pabyChunkNoDataMask = NULL;
    1316              32 :         for(iBand=0;iBand<nBands;iBand++)
    1317                 :         {
    1318              24 :             papafChunk[iBand] = (float*) VSIMalloc3(nFullResXChunk, nFullResYChunk, sizeof(float));
    1319              24 :             if( papafChunk[iBand] == NULL )
    1320                 :             {
    1321               0 :                 while ( --iBand >= 0)
    1322               0 :                     CPLFree(papafChunk[iBand]);
    1323               0 :                 CPLFree(papafChunk);
    1324               0 :                 CPLFree(pabHasNoData);
    1325               0 :                 CPLFree(pafNoDataValue);
    1326                 : 
    1327                 :                 CPLError( CE_Failure, CPLE_OutOfMemory,
    1328               0 :                         "GDALRegenerateOverviewsMultiBand: Out of memory." );
    1329               0 :                 return CE_Failure;
    1330                 :             }
    1331                 :         }
    1332               8 :         if (bUseNoDataMask)
    1333                 :         {
    1334               4 :             pabyChunkNoDataMask = (GByte*) VSIMalloc2(nFullResXChunk, nFullResYChunk);
    1335               4 :             if( pabyChunkNoDataMask == NULL )
    1336                 :             {
    1337               0 :                 for(iBand=0;iBand<nBands;iBand++)
    1338                 :                 {
    1339               0 :                     CPLFree(papafChunk[iBand]);
    1340                 :                 }
    1341               0 :                 CPLFree(papafChunk);
    1342               0 :                 CPLFree(pabHasNoData);
    1343               0 :                 CPLFree(pafNoDataValue);
    1344                 : 
    1345                 :                 CPLError( CE_Failure, CPLE_OutOfMemory,
    1346               0 :                         "GDALRegenerateOverviewsMultiBand: Out of memory." );
    1347               0 :                 return CE_Failure;
    1348                 :             }
    1349                 :         }
    1350                 : 
    1351                 :         int nChunkYOff;
    1352                 :         /* Iterate on destination overview, block by block */
    1353              16 :         for( nChunkYOff = 0; nChunkYOff < nSrcHeight && eErr == CE_None; nChunkYOff += nFullResYChunk )
    1354                 :         {
    1355                 :             int nYCount;
    1356               8 :             if  (nChunkYOff + nFullResYChunk <= nSrcHeight)
    1357               0 :                 nYCount = nFullResYChunk;
    1358                 :             else
    1359               8 :                 nYCount = nSrcHeight - nChunkYOff;
    1360                 : 
    1361               8 :             if( !pfnProgress( dfCurPixelCount / dfTotalPixelCount, 
    1362                 :                               NULL, pProgressData ) )
    1363                 :             {
    1364               0 :                 CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
    1365               0 :                 eErr = CE_Failure;
    1366                 :             }
    1367                 : 
    1368                 :             int nChunkXOff;
    1369              16 :             for( nChunkXOff = 0; nChunkXOff < nSrcWidth && eErr == CE_None; nChunkXOff += nFullResXChunk )
    1370                 :             {
    1371                 :                 int nXCount;
    1372               8 :                 if  (nChunkXOff + nFullResXChunk <= nSrcWidth)
    1373               0 :                     nXCount = nFullResXChunk;
    1374                 :                 else
    1375               8 :                     nXCount = nSrcWidth - nChunkXOff;
    1376                 : 
    1377                 :                 /* Read the source buffers for all the bands */
    1378              32 :                 for(iBand=0;iBand<nBands && eErr == CE_None;iBand++)
    1379                 :                 {
    1380                 :                     GDALRasterBand* poSrcBand;
    1381              24 :                     if (iSrcOverview == -1)
    1382              24 :                         poSrcBand = papoSrcBands[iBand];
    1383                 :                     else
    1384               0 :                         poSrcBand = papapoOverviewBands[iBand][iSrcOverview];
    1385                 :                     eErr = poSrcBand->RasterIO( GF_Read,
    1386                 :                                                 nChunkXOff, nChunkYOff,
    1387                 :                                                 nXCount, nYCount, 
    1388              24 :                                                 papafChunk[iBand],
    1389                 :                                                 nXCount, nYCount,
    1390              48 :                                                 GDT_Float32, 0, 0 );
    1391                 :                 }
    1392                 : 
    1393               8 :                 if (bUseNoDataMask && eErr == CE_None)
    1394                 :                 {
    1395                 :                     GDALRasterBand* poSrcBand;
    1396               4 :                     if (iSrcOverview == -1)
    1397               4 :                         poSrcBand = papoSrcBands[0];
    1398                 :                     else
    1399               0 :                         poSrcBand = papapoOverviewBands[0][iSrcOverview];
    1400               4 :                     eErr = poSrcBand->GetMaskBand()->RasterIO( GF_Read,
    1401                 :                                                                nChunkXOff, nChunkYOff,
    1402                 :                                                                nXCount, nYCount, 
    1403                 :                                                                pabyChunkNoDataMask,
    1404                 :                                                                nXCount, nYCount,
    1405               4 :                                                                GDT_Byte, 0, 0 );
    1406                 :                 }
    1407                 : 
    1408                 :                 /* Compute the resulting overview block */
    1409              32 :                 for(iBand=0;iBand<nBands && eErr == CE_None;iBand++)
    1410                 :                 {
    1411                 :                     eErr = GDALDownsampleChunk32R(nSrcWidth, nSrcHeight,
    1412                 :                                                   papafChunk[iBand],
    1413                 :                                                   pabyChunkNoDataMask,
    1414                 :                                                   nChunkXOff, nXCount,
    1415                 :                                                   nChunkYOff, nYCount,
    1416              24 :                                                   papapoOverviewBands[iBand][iOverview],
    1417                 :                                                   pszResampling,
    1418                 :                                                   pabHasNoData[iBand],
    1419                 :                                                   pafNoDataValue[iBand],
    1420                 :                                                   /*poColorTable*/ NULL,
    1421              48 :                                                   eDataType);
    1422                 :                 }
    1423                 :             }
    1424                 : 
    1425               8 :             dfCurPixelCount += (double)nYCount * nSrcWidth;
    1426                 :         }
    1427                 : 
    1428                 :         /* Flush the data to overviews */
    1429              32 :         for(iBand=0;iBand<nBands;iBand++)
    1430                 :         {
    1431              24 :             CPLFree(papafChunk[iBand]);
    1432              24 :             papapoOverviewBands[iBand][iOverview]->FlushCache();
    1433                 :         }
    1434               8 :         CPLFree(papafChunk);
    1435               8 :         CPLFree(pabyChunkNoDataMask);
    1436                 : 
    1437                 :     }
    1438                 : 
    1439               8 :     CPLFree(pabHasNoData);
    1440               8 :     CPLFree(pafNoDataValue);
    1441                 : 
    1442               8 :     if (eErr == CE_None)
    1443               8 :         pfnProgress( 1.0, NULL, pProgressData );
    1444                 : 
    1445               8 :     return eErr;
    1446                 : }
    1447                 : 
    1448                 : 
    1449                 : /************************************************************************/
    1450                 : /*                        GDALComputeBandStats()                        */
    1451                 : /************************************************************************/
    1452                 : 
    1453                 : CPLErr CPL_STDCALL 
    1454              11 : GDALComputeBandStats( GDALRasterBandH hSrcBand,
    1455                 :                       int nSampleStep,
    1456                 :                       double *pdfMean, double *pdfStdDev, 
    1457                 :                       GDALProgressFunc pfnProgress, 
    1458                 :                       void *pProgressData )
    1459                 : 
    1460                 : {
    1461              11 :     VALIDATE_POINTER1( hSrcBand, "GDALComputeBandStats", CE_Failure );
    1462                 : 
    1463              11 :     GDALRasterBand *poSrcBand = (GDALRasterBand *) hSrcBand;
    1464                 :     int         iLine, nWidth, nHeight;
    1465              11 :     GDALDataType eType = poSrcBand->GetRasterDataType();
    1466                 :     GDALDataType eWrkType;
    1467                 :     int         bComplex;
    1468                 :     float       *pafData;
    1469              11 :     double      dfSum=0.0, dfSum2=0.0;
    1470              11 :     int         nSamples = 0;
    1471                 : 
    1472              11 :     if( pfnProgress == NULL )
    1473              11 :         pfnProgress = GDALDummyProgress;
    1474                 : 
    1475              11 :     nWidth = poSrcBand->GetXSize();
    1476              11 :     nHeight = poSrcBand->GetYSize();
    1477                 : 
    1478              11 :     if( nSampleStep >= nHeight || nSampleStep < 1 )
    1479               0 :         nSampleStep = 1;
    1480                 : 
    1481              11 :     bComplex = GDALDataTypeIsComplex(eType);
    1482              11 :     if( bComplex )
    1483                 :     {
    1484               0 :         pafData = (float *) VSIMalloc(nWidth * 2 * sizeof(float));
    1485               0 :         eWrkType = GDT_CFloat32;
    1486                 :     }
    1487                 :     else
    1488                 :     {
    1489              11 :         pafData = (float *) VSIMalloc(nWidth * sizeof(float));
    1490              11 :         eWrkType = GDT_Float32;
    1491                 :     }
    1492                 : 
    1493              11 :     if( pafData == NULL )
    1494                 :     {
    1495                 :         CPLError( CE_Failure, CPLE_OutOfMemory,
    1496               0 :                   "GDALComputeBandStats: Out of memory for buffer." );
    1497               0 :         return CE_Failure;
    1498                 :     }
    1499                 : 
    1500                 : /* -------------------------------------------------------------------- */
    1501                 : /*      Loop over all sample lines.                                     */
    1502                 : /* -------------------------------------------------------------------- */
    1503            1201 :     for( iLine = 0; iLine < nHeight; iLine += nSampleStep )
    1504                 :     {
    1505                 :         int     iPixel;
    1506                 : 
    1507            1191 :         if( !pfnProgress( iLine / (double) nHeight,
    1508                 :                           NULL, pProgressData ) )
    1509                 :         {
    1510               0 :             CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
    1511               0 :             CPLFree( pafData );
    1512               0 :             return CE_Failure;
    1513                 :         }
    1514                 : 
    1515                 :         CPLErr eErr = poSrcBand->RasterIO( GF_Read, 0, iLine, nWidth, 1,
    1516                 :                              pafData, nWidth, 1, eWrkType,
    1517            1191 :                              0, 0 );
    1518            1191 :         if ( eErr != CE_None )
    1519                 :         {
    1520               1 :             CPLFree( pafData );
    1521               1 :             return eErr;
    1522                 :         }
    1523                 : 
    1524          353030 :         for( iPixel = 0; iPixel < nWidth; iPixel++ )
    1525                 :         {
    1526                 :             float       fValue;
    1527                 : 
    1528          351840 :             if( bComplex )
    1529                 :             {
    1530                 :                 // Compute the magnitude of the complex value.
    1531                 : 
    1532                 :                 fValue = (float) 
    1533               0 :                     sqrt(pafData[iPixel*2  ] * pafData[iPixel*2  ]
    1534               0 :                          + pafData[iPixel*2+1] * pafData[iPixel*2+1]);
    1535                 :             }
    1536                 :             else
    1537                 :             {
    1538          351840 :                 fValue = pafData[iPixel];
    1539                 :             }
    1540                 : 
    1541          351840 :             dfSum  += fValue;
    1542          351840 :             dfSum2 += fValue * fValue;
    1543                 :         }
    1544                 : 
    1545            1190 :         nSamples += nWidth;
    1546                 :     }
    1547                 : 
    1548              10 :     if( !pfnProgress( 1.0, NULL, pProgressData ) )
    1549                 :     {
    1550               0 :         CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
    1551               0 :         CPLFree( pafData );
    1552               0 :         return CE_Failure;
    1553                 :     }
    1554                 : 
    1555                 : /* -------------------------------------------------------------------- */
    1556                 : /*      Produce the result values.                                      */
    1557                 : /* -------------------------------------------------------------------- */
    1558              10 :     if( pdfMean != NULL )
    1559              10 :         *pdfMean = dfSum / nSamples;
    1560                 : 
    1561              10 :     if( pdfStdDev != NULL )
    1562                 :     {
    1563              10 :         double  dfMean = dfSum / nSamples;
    1564                 : 
    1565              10 :         *pdfStdDev = sqrt((dfSum2 / nSamples) - (dfMean * dfMean));
    1566                 :     }
    1567                 : 
    1568              10 :     CPLFree( pafData );
    1569                 : 
    1570              10 :     return CE_None;
    1571                 : }
    1572                 : 
    1573                 : /************************************************************************/
    1574                 : /*                  GDALOverviewMagnitudeCorrection()                   */
    1575                 : /*                                                                      */
    1576                 : /*      Correct the mean and standard deviation of the overviews of     */
    1577                 : /*      the given band to match the base layer approximately.           */
    1578                 : /************************************************************************/
    1579                 : 
    1580                 : CPLErr
    1581               0 : GDALOverviewMagnitudeCorrection( GDALRasterBandH hBaseBand, 
    1582                 :                                  int nOverviewCount,
    1583                 :                                  GDALRasterBandH *pahOverviews,
    1584                 :                                  GDALProgressFunc pfnProgress, 
    1585                 :                                  void *pProgressData )
    1586                 : 
    1587                 : {
    1588               0 :     VALIDATE_POINTER1( hBaseBand, "GDALOverviewMagnitudeCorrection", CE_Failure );
    1589                 : 
    1590                 :     CPLErr      eErr;
    1591                 :     double      dfOrigMean, dfOrigStdDev;
    1592                 : 
    1593                 : /* -------------------------------------------------------------------- */
    1594                 : /*      Compute mean/stddev for source raster.                          */
    1595                 : /* -------------------------------------------------------------------- */
    1596                 :     eErr = GDALComputeBandStats( hBaseBand, 2, &dfOrigMean, &dfOrigStdDev, 
    1597               0 :                                  pfnProgress, pProgressData );
    1598                 : 
    1599               0 :     if( eErr != CE_None )
    1600               0 :         return eErr;
    1601                 :     
    1602                 : /* -------------------------------------------------------------------- */
    1603                 : /*      Loop on overview bands.                                         */
    1604                 : /* -------------------------------------------------------------------- */
    1605                 :     int         iOverview;
    1606                 : 
    1607               0 :     for( iOverview = 0; iOverview < nOverviewCount; iOverview++ )
    1608                 :     {
    1609               0 :         GDALRasterBand *poOverview = (GDALRasterBand *)pahOverviews[iOverview];
    1610                 :         double  dfOverviewMean, dfOverviewStdDev;
    1611                 :         double  dfGain;
    1612                 : 
    1613                 :         eErr = GDALComputeBandStats( pahOverviews[iOverview], 1, 
    1614                 :                                      &dfOverviewMean, &dfOverviewStdDev, 
    1615               0 :                                      pfnProgress, pProgressData );
    1616                 : 
    1617               0 :         if( eErr != CE_None )
    1618               0 :             return eErr;
    1619                 : 
    1620               0 :         if( dfOrigStdDev < 0.0001 )
    1621               0 :             dfGain = 1.0;
    1622                 :         else
    1623               0 :             dfGain = dfOrigStdDev / dfOverviewStdDev;
    1624                 : 
    1625                 : /* -------------------------------------------------------------------- */
    1626                 : /*      Apply gain and offset.                                          */
    1627                 : /* -------------------------------------------------------------------- */
    1628               0 :         GDALDataType    eWrkType, eType = poOverview->GetRasterDataType();
    1629                 :         int             iLine, nWidth, nHeight, bComplex;
    1630                 :         float           *pafData;
    1631                 : 
    1632               0 :         nWidth = poOverview->GetXSize();
    1633               0 :         nHeight = poOverview->GetYSize();
    1634                 : 
    1635               0 :         bComplex = GDALDataTypeIsComplex(eType);
    1636               0 :         if( bComplex )
    1637                 :         {
    1638               0 :             pafData = (float *) VSIMalloc2(nWidth, 2 * sizeof(float));
    1639               0 :             eWrkType = GDT_CFloat32;
    1640                 :         }
    1641                 :         else
    1642                 :         {
    1643               0 :             pafData = (float *) VSIMalloc2(nWidth, sizeof(float));
    1644               0 :             eWrkType = GDT_Float32;
    1645                 :         }
    1646                 : 
    1647               0 :         if( pafData == NULL )
    1648                 :         {
    1649                 :             CPLError( CE_Failure, CPLE_OutOfMemory,
    1650               0 :                       "GDALOverviewMagnitudeCorrection: Out of memory for buffer." );
    1651               0 :             return CE_Failure;
    1652                 :         }
    1653                 : 
    1654               0 :         for( iLine = 0; iLine < nHeight; iLine++ )
    1655                 :         {
    1656                 :             int iPixel;
    1657                 :             
    1658               0 :             if( !pfnProgress( iLine / (double) nHeight,
    1659                 :                               NULL, pProgressData ) )
    1660                 :             {
    1661               0 :                 CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
    1662               0 :                 CPLFree( pafData );
    1663               0 :                 return CE_Failure;
    1664                 :             }
    1665                 : 
    1666                 :             poOverview->RasterIO( GF_Read, 0, iLine, nWidth, 1,
    1667                 :                                   pafData, nWidth, 1, eWrkType,
    1668               0 :                                   0, 0 );
    1669                 :             
    1670               0 :             for( iPixel = 0; iPixel < nWidth; iPixel++ )
    1671                 :             {
    1672               0 :                 if( bComplex )
    1673                 :                 {
    1674               0 :                     pafData[iPixel*2] *= (float) dfGain;
    1675               0 :                     pafData[iPixel*2+1] *= (float) dfGain;
    1676                 :                 }
    1677                 :                 else
    1678                 :                 {
    1679               0 :                     pafData[iPixel] = (float)
    1680               0 :                         ((pafData[iPixel]-dfOverviewMean)*dfGain + dfOrigMean);
    1681                 : 
    1682                 :                 }
    1683                 :             }
    1684                 : 
    1685                 :             poOverview->RasterIO( GF_Write, 0, iLine, nWidth, 1,
    1686                 :                                   pafData, nWidth, 1, eWrkType,
    1687               0 :                                   0, 0 );
    1688                 :         }
    1689                 : 
    1690               0 :         if( !pfnProgress( 1.0, NULL, pProgressData ) )
    1691                 :         {
    1692               0 :             CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
    1693               0 :             CPLFree( pafData );
    1694               0 :             return CE_Failure;
    1695                 :         }
    1696                 :         
    1697               0 :         CPLFree( pafData );
    1698                 :     }
    1699                 : 
    1700               0 :     return CE_None;
    1701                 : }

Generated by: LCOV version 1.7