Exemple #1
0
// Returns true if georeferenced ...all geocoded and georeferenced GeoTIFFs qualify
int isGeotiff(const char *file)
{
    TIFF *tiff = NULL;
    GTIF *gtif = NULL;
    int num_tie_points = 0;
    int num_pixel_scales = 0;
    double *tie_point = NULL;
    double *pixel_scale = NULL;

    tiff = XTIFFOpen (file, "r");
    if (tiff != NULL) {
        gtif = GTIFNew (tiff);
    }
    if (gtif) {
        (gtif->gt_methods.get)(gtif->gt_tif, GTIFF_TIEPOINTS, &num_tie_points, &tie_point);
        (gtif->gt_methods.get)(gtif->gt_tif, GTIFF_PIXELSCALE, &num_pixel_scales, &pixel_scale);
    }

    if (gtif &&
        num_tie_points == 6 && num_pixel_scales == 3 &&
        pixel_scale[0] > 0.0 && pixel_scale[1] > 0.0)
    {
        GTIFFree(gtif);
        XTIFFClose(tiff);
        FREE(tie_point);
        FREE(pixel_scale);
        return 1;
    }

    if (gtif) GTIFFree(gtif);
    if (tiff) XTIFFClose(tiff);
    FREE(tie_point);
    FREE(pixel_scale);
    return 0;
}
Exemple #2
0
void set_geotif_header(char *tiff_fname, char *utm_zone, float xoff,
		float yoff, float scale)
{
	// open tiff file
	TIFF *tif = XTIFFOpen(tiff_fname, "r+");
	if (!tif)
		fail("failed in XTIFFOpen\n");

	GTIF *gtif = GTIFNew(tif);
	if (!gtif)
		fail("failed in GTIFNew\n");

	// write TIFF tags
	double pixsize[3] = {scale, scale, 0.0};
	TIFFSetField(tif, GTIFF_PIXELSCALE, 3, pixsize);

	double tiepoint[6] = {0.0, 0.0, 0.0, xoff, yoff, 0.0};
	TIFFSetField(tif, GTIFF_TIEPOINTS, 6, tiepoint);

	// write GEOTIFF keys
	int utm_ind = get_utm_zone_index_for_geotiff(utm_zone);
	GTIFKeySet(gtif, ProjectedCSTypeGeoKey, TYPE_SHORT, 1, utm_ind);
	GTIFWriteKeys(gtif);

	// free and close
	GTIFFree(gtif);
	XTIFFClose(tif);
}
Exemple #3
0
int main()
{
	char *fname = "newgeo.tif";
	TIFF *tif=(TIFF*)0;  /* TIFF-level descriptor */
	GTIF *gtif=(GTIF*)0; /* GeoKey-level descriptor */
	
	tif=XTIFFOpen(fname,"w");
	if (!tif) goto failure;
	
	gtif = GTIFNew(tif);
	if (!gtif)
	{
		printf("failed in GTIFNew\n");
		goto failure;
	}
	
	SetUpTIFFDirectory(tif);
	SetUpGeoKeys(gtif);
	WriteImage(tif);
	
	GTIFWriteKeys(gtif);
	GTIFFree(gtif);
	XTIFFClose(tif);
	return 0;
	
failure:
	printf("failure in makegeo\n");
	if (tif) TIFFClose(tif);
	if (gtif) GTIFFree(gtif);
	return -1;
}
Exemple #4
0
void main()
{
	TIFF *tif=(TIFF*)0;  /* TIFF-level descriptor */
	
	tif=XTIFFOpen("newtif.tif","w");
	if (!tif) goto failure;
	
	SetUpTIFFDirectory(tif);
	WriteImage(tif);
	
	XTIFFClose(tif);
	exit (0);
	
failure:
	printf("failure in maketif\n");
	if (tif) XTIFFClose(tif);
	exit (-1);
}
Exemple #5
0
bool	FetchTIFFCorners(const char * inFileName, double corners[8], int& post_pos)
{
	bool retVal = false;
	TIFF * tiffFile = XTIFFOpen(inFileName, "r");
	if (tiffFile)
	{
		retVal = FetchTIFFCornersWithTIFF(tiffFile, corners, post_pos);
		XTIFFClose(tiffFile);
	}
	
	return retVal;
}
Exemple #6
0
CPLErr 
GTIFFBuildOverviews( const char * pszFilename,
                     int nBands, GDALRasterBand **papoBandList, 
                     int nOverviews, int * panOverviewList,
                     const char * pszResampling, 
                     GDALProgressFunc pfnProgress, void * pProgressData )

{
    TIFF    *hOTIFF;
    int     nBitsPerPixel=0, nCompression=COMPRESSION_NONE, nPhotometric=0;
    int     nSampleFormat=0, nPlanarConfig, iOverview, iBand;
    int     nXSize=0, nYSize=0;

    if( nBands == 0 || nOverviews == 0 )
        return CE_None;

    if (!GTiffOneTimeInit())
        return CE_Failure;

/* -------------------------------------------------------------------- */
/*      Verify that the list of bands is suitable for emitting in       */
/*      TIFF file.                                                      */
/* -------------------------------------------------------------------- */
    for( iBand = 0; iBand < nBands; iBand++ )
    {
        int     nBandBits, nBandFormat;
        GDALRasterBand *hBand = papoBandList[iBand];

        switch( hBand->GetRasterDataType() )
        {
          case GDT_Byte:
            nBandBits = 8;
            nBandFormat = SAMPLEFORMAT_UINT;
            break;

          case GDT_UInt16:
            nBandBits = 16;
            nBandFormat = SAMPLEFORMAT_UINT;
            break;

          case GDT_Int16:
            nBandBits = 16;
            nBandFormat = SAMPLEFORMAT_INT;
            break;

          case GDT_UInt32:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_UINT;
            break;

          case GDT_Int32:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_INT;
            break;

          case GDT_Float32:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_IEEEFP;
            break;

          case GDT_Float64:
            nBandBits = 64;
            nBandFormat = SAMPLEFORMAT_IEEEFP;
            break;

          case GDT_CInt16:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_COMPLEXINT;
            break;

          case GDT_CInt32:
            nBandBits = 64;
            nBandFormat = SAMPLEFORMAT_COMPLEXINT;
            break;

          case GDT_CFloat32:
            nBandBits = 64;
            nBandFormat = SAMPLEFORMAT_COMPLEXIEEEFP;
            break;

          case GDT_CFloat64:
            nBandBits = 128;
            nBandFormat = SAMPLEFORMAT_COMPLEXIEEEFP;
            break;

          default:
            CPLAssert( FALSE );
            return CE_Failure;
        }

        if( hBand->GetMetadataItem( "NBITS", "IMAGE_STRUCTURE" ) )
        {
            nBandBits = 
                atoi(hBand->GetMetadataItem("NBITS","IMAGE_STRUCTURE"));

            if( nBandBits == 1 
                && EQUALN(pszResampling,"AVERAGE_BIT2",12) )
                nBandBits = 8;
        }

        if( iBand == 0 )
        {
            nBitsPerPixel = nBandBits;
            nSampleFormat = nBandFormat;
            nXSize = hBand->GetXSize();
            nYSize = hBand->GetYSize();
        }
        else if( nBitsPerPixel != nBandBits || nSampleFormat != nBandFormat )
        {
            CPLError( CE_Failure, CPLE_NotSupported, 
                      "GTIFFBuildOverviews() doesn't support a mixture of band"
                      " data types." );
            return CE_Failure;
        }
        else if( hBand->GetColorTable() != NULL )
        {
            CPLError( CE_Failure, CPLE_NotSupported, 
                      "GTIFFBuildOverviews() doesn't support building"
                      " overviews of multiple colormapped bands." );
            return CE_Failure;
        }
        else if( hBand->GetXSize() != nXSize 
                 || hBand->GetYSize() != nYSize )
        {
            CPLError( CE_Failure, CPLE_NotSupported, 
                      "GTIFFBuildOverviews() doesn't support building"
                      " overviews of different sized bands." );
            return CE_Failure;
        }
    }

/* -------------------------------------------------------------------- */
/*      Use specified compression method.                               */
/* -------------------------------------------------------------------- */
    const char *pszCompress = CPLGetConfigOption( "COMPRESS_OVERVIEW", NULL );

    if( pszCompress != NULL && pszCompress[0] != '\0' )
    {
        nCompression = GTIFFGetCompressionMethod(pszCompress, "COMPRESS_OVERVIEW");
        if (nCompression < 0)
            return CE_Failure;
    }
    
    if( nCompression == COMPRESSION_JPEG && nBitsPerPixel > 8 )
    {  
        if( nBitsPerPixel > 16 )
        {
            CPLError( CE_Failure, CPLE_NotSupported, 
                      "GTIFFBuildOverviews() doesn't support building"
                      " JPEG compressed overviews of nBitsPerPixel > 16." );
            return CE_Failure;
        }

        nBitsPerPixel = 12;
    }

/* -------------------------------------------------------------------- */
/*      Figure out the planar configuration to use.                     */
/* -------------------------------------------------------------------- */
    if( nBands == 1 )
        nPlanarConfig = PLANARCONFIG_CONTIG;
    else
        nPlanarConfig = PLANARCONFIG_SEPARATE;

    const char* pszInterleave = CPLGetConfigOption( "INTERLEAVE_OVERVIEW", NULL );
    if (pszInterleave != NULL && pszInterleave[0] != '\0')
    {
        if( EQUAL( pszInterleave, "PIXEL" ) )
            nPlanarConfig = PLANARCONFIG_CONTIG;
        else if( EQUAL( pszInterleave, "BAND" ) )
            nPlanarConfig = PLANARCONFIG_SEPARATE;
        else
        {
            CPLError( CE_Failure, CPLE_AppDefined, 
                      "INTERLEAVE_OVERVIEW=%s unsupported, value must be PIXEL or BAND. ignoring",
                      pszInterleave );
        }
    }

/* -------------------------------------------------------------------- */
/*      Figure out the photometric interpretation to use.               */
/* -------------------------------------------------------------------- */
    if( nBands == 3 )
        nPhotometric = PHOTOMETRIC_RGB;
    else if( papoBandList[0]->GetColorTable() != NULL 
             && !EQUALN(pszResampling,"AVERAGE_BIT2",12) )
    {
        nPhotometric = PHOTOMETRIC_PALETTE;
        /* should set the colormap up at this point too! */
    }
    else
        nPhotometric = PHOTOMETRIC_MINISBLACK;

    const char* pszPhotometric = CPLGetConfigOption( "PHOTOMETRIC_OVERVIEW", NULL );
    if (pszPhotometric != NULL && pszPhotometric[0] != '\0')
    {
        if( EQUAL( pszPhotometric, "MINISBLACK" ) )
            nPhotometric = PHOTOMETRIC_MINISBLACK;
        else if( EQUAL( pszPhotometric, "MINISWHITE" ) )
            nPhotometric = PHOTOMETRIC_MINISWHITE;
        else if( EQUAL( pszPhotometric, "RGB" ))
        {
            nPhotometric = PHOTOMETRIC_RGB;
        }
        else if( EQUAL( pszPhotometric, "CMYK" ))
        {
            nPhotometric = PHOTOMETRIC_SEPARATED;
        }
        else if( EQUAL( pszPhotometric, "YCBCR" ))
        {
            nPhotometric = PHOTOMETRIC_YCBCR;

            /* Because of subsampling, setting YCBCR without JPEG compression leads */
            /* to a crash currently. Would need to make GTiffRasterBand::IWriteBlock() */
            /* aware of subsampling so that it doesn't overrun buffer size returned */
            /* by libtiff */
            if ( nCompression != COMPRESSION_JPEG )
            {
                CPLError(CE_Failure, CPLE_NotSupported,
                         "Currently, PHOTOMETRIC_OVERVIEW=YCBCR requires COMPRESS_OVERVIEW=JPEG");
                return CE_Failure;
            }

            if (pszInterleave != NULL && pszInterleave[0] != '\0' && nPlanarConfig == PLANARCONFIG_SEPARATE)
            {
                CPLError(CE_Failure, CPLE_NotSupported,
                         "PHOTOMETRIC_OVERVIEW=YCBCR requires INTERLEAVE_OVERVIEW=PIXEL");
                return CE_Failure;
            }
            else
            {
                nPlanarConfig = PLANARCONFIG_CONTIG;
            }

            /* YCBCR strictly requires 3 bands. Not less, not more */
            /* Issue an explicit error message as libtiff one is a bit cryptic : */
            /* JPEGLib:Bogus input colorspace */
            if ( nBands != 3 )
            {
                CPLError(CE_Failure, CPLE_NotSupported,
                         "PHOTOMETRIC_OVERVIEW=YCBCR requires a source raster with only 3 bands (RGB)");
                return CE_Failure;
            }
        }
        else if( EQUAL( pszPhotometric, "CIELAB" ))
        {
            nPhotometric = PHOTOMETRIC_CIELAB;
        }
        else if( EQUAL( pszPhotometric, "ICCLAB" ))
        {
            nPhotometric = PHOTOMETRIC_ICCLAB;
        }
        else if( EQUAL( pszPhotometric, "ITULAB" ))
        {
            nPhotometric = PHOTOMETRIC_ITULAB;
        }
        else
        {
            CPLError( CE_Warning, CPLE_IllegalArg, 
                      "PHOTOMETRIC_OVERVIEW=%s value not recognised, ignoring.\n",
                      pszPhotometric );
        }
    }

/* -------------------------------------------------------------------- */
/*      Figure out the predictor value to use.                          */
/* -------------------------------------------------------------------- */
    int nPredictor = PREDICTOR_NONE;
    if ( nCompression == COMPRESSION_LZW ||
         nCompression == COMPRESSION_ADOBE_DEFLATE )
    {
        const char* pszPredictor = CPLGetConfigOption( "PREDICTOR_OVERVIEW", NULL );
        if( pszPredictor  != NULL )
        {
            nPredictor =  atoi( pszPredictor );
        }
    }

/* -------------------------------------------------------------------- */
/*      Create the file, if it does not already exist.                  */
/* -------------------------------------------------------------------- */
    VSIStatBufL  sStatBuf;
    VSILFILE* fpL = NULL;

    if( VSIStatExL( pszFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG ) != 0 )
    {
    /* -------------------------------------------------------------------- */
    /*      Compute the uncompressed size.                                  */
    /* -------------------------------------------------------------------- */
        double  dfUncompressedOverviewSize = 0;
        int nDataTypeSize = GDALGetDataTypeSize(papoBandList[0]->GetRasterDataType())/8;

        for( iOverview = 0; iOverview < nOverviews; iOverview++ )
        {
            int    nOXSize, nOYSize;

            nOXSize = (nXSize + panOverviewList[iOverview] - 1) 
                / panOverviewList[iOverview];
            nOYSize = (nYSize + panOverviewList[iOverview] - 1) 
                / panOverviewList[iOverview];

            dfUncompressedOverviewSize += 
                nOXSize * ((double)nOYSize) * nBands * nDataTypeSize;
        }

        if( nCompression == COMPRESSION_NONE 
            && dfUncompressedOverviewSize > 4200000000.0 )
        {
    #ifndef BIGTIFF_SUPPORT
            CPLError( CE_Failure, CPLE_NotSupported, 
                    "The overview file would be larger than 4GB\n"
                    "but this is the largest size a TIFF can be, and BigTIFF is unavailable.\n"
                    "Creation failed." );
            return CE_Failure;
    #endif
        }
    /* -------------------------------------------------------------------- */
    /*      Should the file be created as a bigtiff file?                   */
    /* -------------------------------------------------------------------- */
        const char *pszBIGTIFF = CPLGetConfigOption( "BIGTIFF_OVERVIEW", NULL );

        if( pszBIGTIFF == NULL )
            pszBIGTIFF = "IF_NEEDED";

        int bCreateBigTIFF = FALSE;
        if( EQUAL(pszBIGTIFF,"IF_NEEDED") )
        {
            if( nCompression == COMPRESSION_NONE 
                && dfUncompressedOverviewSize > 4200000000.0 )
                bCreateBigTIFF = TRUE;
        }
        else if( EQUAL(pszBIGTIFF,"IF_SAFER") )
        {
            /* Look at the size of the base image and suppose that */
            /* the added overview levels won't be more than 1/2 of */
            /* the size of the base image. The theory says 1/3 of the */
            /* base image size if the overview levels are 2, 4, 8, 16... */
            /* Thus take 1/2 as the security margin for 1/3 */
            double dfUncompressedImageSize =
                        nXSize * ((double)nYSize) * nBands * nDataTypeSize;
            if( dfUncompressedImageSize * .5 > 4200000000.0 )
                bCreateBigTIFF = TRUE;
        }
        else
        {
            bCreateBigTIFF = CSLTestBoolean( pszBIGTIFF );
            if (!bCreateBigTIFF && nCompression == COMPRESSION_NONE 
                && dfUncompressedOverviewSize > 4200000000.0 )
            {
                CPLError( CE_Failure, CPLE_NotSupported, 
                    "The overview file will be larger than 4GB, so BigTIFF is necessary.\n"
                    "Creation failed.");
                return CE_Failure;
            }
        }

    #ifndef BIGTIFF_SUPPORT
        if( bCreateBigTIFF )
        {
            CPLError( CE_Warning, CPLE_NotSupported,
                    "BigTIFF requested, but GDAL built without BigTIFF\n"
                    "enabled libtiff, request ignored." );
            bCreateBigTIFF = FALSE;
        }
    #endif

        if( bCreateBigTIFF )
            CPLDebug( "GTiff", "File being created as a BigTIFF." );

        fpL = VSIFOpenL( pszFilename, "w+" );
        if( fpL == NULL )
            hOTIFF = NULL;
        else
            hOTIFF = VSI_TIFFOpen( pszFilename, (bCreateBigTIFF) ? "w+8" : "w+", fpL );
        if( hOTIFF == NULL )
        {
            if( CPLGetLastErrorNo() == 0 )
                CPLError( CE_Failure, CPLE_OpenFailed,
                          "Attempt to create new tiff file `%s'\n"
                          "failed in VSI_TIFFOpen().\n",
                          pszFilename );
            if( fpL != NULL )
                VSIFCloseL(fpL);
            return CE_Failure;
        }
    }
/* -------------------------------------------------------------------- */
/*      Otherwise just open it for update access.                       */
/* -------------------------------------------------------------------- */
    else 
    {
        fpL = VSIFOpenL( pszFilename, "r+" );
        if( fpL == NULL )
            hOTIFF = NULL;
        else
            hOTIFF = VSI_TIFFOpen( pszFilename, "r+", fpL );
        if( hOTIFF == NULL )
        {
            if( CPLGetLastErrorNo() == 0 )
                CPLError( CE_Failure, CPLE_OpenFailed,
                          "Attempt to create new tiff file `%s'\n"
                          "failed in VSI_TIFFOpen().\n",
                          pszFilename );
            if( fpL != NULL )
                VSIFCloseL(fpL);
            return CE_Failure;
        }
    }

/* -------------------------------------------------------------------- */
/*      Do we have a palette?  If so, create a TIFF compatible version. */
/* -------------------------------------------------------------------- */
    unsigned short      *panRed=NULL, *panGreen=NULL, *panBlue=NULL;

    if( nPhotometric == PHOTOMETRIC_PALETTE )
    {
        GDALColorTable *poCT = papoBandList[0]->GetColorTable();
        int nColorCount;

        if( nBitsPerPixel <= 8 )
            nColorCount = 256;
        else
            nColorCount = 65536;

        panRed   = (unsigned short *) 
            CPLCalloc(nColorCount,sizeof(unsigned short));
        panGreen = (unsigned short *) 
            CPLCalloc(nColorCount,sizeof(unsigned short));
        panBlue  = (unsigned short *) 
            CPLCalloc(nColorCount,sizeof(unsigned short));

        for( int iColor = 0; iColor < nColorCount; iColor++ )
        {
            GDALColorEntry  sRGB;

            if( poCT->GetColorEntryAsRGB( iColor, &sRGB ) )
            {
                panRed[iColor] = (unsigned short) (257 * sRGB.c1);
                panGreen[iColor] = (unsigned short) (257 * sRGB.c2);
                panBlue[iColor] = (unsigned short) (257 * sRGB.c3);
            }
        }
    }

/* -------------------------------------------------------------------- */
/*      Do we need some metadata for the overviews?                     */
/* -------------------------------------------------------------------- */
    CPLString osMetadata;
    GDALDataset *poBaseDS = papoBandList[0]->GetDataset();

    GTIFFBuildOverviewMetadata( pszResampling, poBaseDS, osMetadata );

/* -------------------------------------------------------------------- */
/*      Loop, creating overviews.                                       */
/* -------------------------------------------------------------------- */
    int nOvrBlockXSize, nOvrBlockYSize;
    GTIFFGetOverviewBlockSize(&nOvrBlockXSize, &nOvrBlockYSize);
    for( iOverview = 0; iOverview < nOverviews; iOverview++ )
    {
        int    nOXSize, nOYSize;

        nOXSize = (nXSize + panOverviewList[iOverview] - 1) 
            / panOverviewList[iOverview];
        nOYSize = (nYSize + panOverviewList[iOverview] - 1) 
            / panOverviewList[iOverview];

        GTIFFWriteDirectory(hOTIFF, FILETYPE_REDUCEDIMAGE,
                            nOXSize, nOYSize, nBitsPerPixel, 
                            nPlanarConfig, nBands,
                            nOvrBlockXSize, nOvrBlockYSize, TRUE, nCompression,
                            nPhotometric, nSampleFormat, nPredictor,
                            panRed, panGreen, panBlue,
                            0, NULL, /* FIXME? how can we fetch extrasamples */
                            osMetadata );
    }

    if (panRed)
    {
        CPLFree(panRed);
        CPLFree(panGreen);
        CPLFree(panBlue);
        panRed = panGreen = panBlue = NULL;
    }

    XTIFFClose( hOTIFF );
    VSIFCloseL(fpL);
    fpL = NULL;

/* -------------------------------------------------------------------- */
/*      Open the overview dataset so that we can get at the overview    */
/*      bands.                                                          */
/* -------------------------------------------------------------------- */
    GDALDataset *hODS;
    CPLErr eErr = CE_None;

    hODS = (GDALDataset *) GDALOpen( pszFilename, GA_Update );
    if( hODS == NULL )
        return CE_Failure;
    
/* -------------------------------------------------------------------- */
/*      Do we need to set the jpeg quality?                             */
/* -------------------------------------------------------------------- */
    TIFF *hTIFF = (TIFF*) hODS->GetInternalHandle(NULL);

    if( nCompression == COMPRESSION_JPEG 
        && CPLGetConfigOption( "JPEG_QUALITY_OVERVIEW", NULL ) != NULL )
    {
        int nJpegQuality = atoi(CPLGetConfigOption("JPEG_QUALITY_OVERVIEW","75"));
        TIFFSetField( hTIFF, TIFFTAG_JPEGQUALITY, 
                      nJpegQuality );
        GTIFFSetJpegQuality((GDALDatasetH)hODS, nJpegQuality);
    }

/* -------------------------------------------------------------------- */
/*      Loop writing overview data.                                     */
/* -------------------------------------------------------------------- */

    if (nCompression != COMPRESSION_NONE &&
        nPlanarConfig == PLANARCONFIG_CONTIG &&
        GDALDataTypeIsComplex(papoBandList[0]->GetRasterDataType()) == FALSE &&
        papoBandList[0]->GetColorTable() == NULL &&
        (EQUALN(pszResampling, "NEAR", 4) || EQUAL(pszResampling, "AVERAGE") ||
         EQUAL(pszResampling, "GAUSS") || EQUAL(pszResampling, "CUBIC") ||
         EQUAL(pszResampling, "CUBICSPLINE") || EQUAL(pszResampling, "LANCZOS") ||
         EQUAL(pszResampling, "BILINEAR")))
    {
        /* In the case of pixel interleaved compressed overviews, we want to generate */
        /* the overviews for all the bands block by block, and not band after band, */
        /* in order to write the block once and not loose space in the TIFF file */
        GDALRasterBand ***papapoOverviewBands;

        papapoOverviewBands = (GDALRasterBand ***) CPLCalloc(sizeof(void*),nBands);
        for( iBand = 0; iBand < nBands && eErr == CE_None; iBand++ )
        {
            GDALRasterBand    *hSrcBand = papoBandList[iBand];
            GDALRasterBand    *hDstBand = hODS->GetRasterBand( iBand+1 );
            papapoOverviewBands[iBand] = (GDALRasterBand **) CPLCalloc(sizeof(void*),nOverviews);
            papapoOverviewBands[iBand][0] = hDstBand;

            int bHasNoData;
            double noDataValue = hSrcBand->GetNoDataValue(&bHasNoData);
            if (bHasNoData)
                hDstBand->SetNoDataValue(noDataValue);

            for( int i = 0; i < nOverviews-1 && eErr == CE_None; i++ )
            {
                papapoOverviewBands[iBand][i+1] = hDstBand->GetOverview(i);
                if (papapoOverviewBands[iBand][i+1] == NULL)
                    eErr = CE_Failure;
                else
                {
                    if (bHasNoData)
                        papapoOverviewBands[iBand][i+1]->SetNoDataValue(noDataValue);
                }
            }
        }

        if (eErr == CE_None)
            eErr = GDALRegenerateOverviewsMultiBand(nBands, papoBandList,
                                            nOverviews, papapoOverviewBands,
                                            pszResampling, pfnProgress, pProgressData );

        for( iBand = 0; iBand < nBands; iBand++ )
        {
            CPLFree(papapoOverviewBands[iBand]);
        }
        CPLFree(papapoOverviewBands);
    }
    else
    {
        GDALRasterBand   **papoOverviews;

        papoOverviews = (GDALRasterBand **) CPLCalloc(sizeof(void*),128);

        for( iBand = 0; iBand < nBands && eErr == CE_None; iBand++ )
        {
            GDALRasterBand    *hSrcBand = papoBandList[iBand];
            GDALRasterBand    *hDstBand;
            int               nDstOverviews;

            hDstBand = hODS->GetRasterBand( iBand+1 );

            int bHasNoData;
            double noDataValue = hSrcBand->GetNoDataValue(&bHasNoData);
            if (bHasNoData)
                hDstBand->SetNoDataValue(noDataValue);

            papoOverviews[0] = hDstBand;
            nDstOverviews = hDstBand->GetOverviewCount() + 1;
            CPLAssert( nDstOverviews < 128 );
            nDstOverviews = MIN(128,nDstOverviews);

            for( int i = 0; i < nDstOverviews-1 && eErr == CE_None; i++ )
            {
                papoOverviews[i+1] = hDstBand->GetOverview(i);
                if (papoOverviews[i+1] == NULL)
                    eErr = CE_Failure;
                else
                {
                    if (bHasNoData)
                        papoOverviews[i+1]->SetNoDataValue(noDataValue);
                }
            }

            void         *pScaledProgressData;

            pScaledProgressData = 
                GDALCreateScaledProgress( iBand / (double) nBands, 
                                        (iBand+1) / (double) nBands,
                                        pfnProgress, pProgressData );

            if (eErr == CE_None)
                eErr = 
                    GDALRegenerateOverviews( (GDALRasterBandH) hSrcBand, 
                                        nDstOverviews, 
                                        (GDALRasterBandH *) papoOverviews, 
                                        pszResampling,
                                        GDALScaledProgress, 
                                        pScaledProgressData);

            GDALDestroyScaledProgress( pScaledProgressData );
        }

        CPLFree( papoOverviews );
    }

/* -------------------------------------------------------------------- */
/*      Cleanup                                                         */
/* -------------------------------------------------------------------- */
    if (eErr == CE_None)
        hODS->FlushCache();
    delete hODS;

    pfnProgress( 1.0, NULL, pProgressData );

    return eErr;
}
Exemple #7
0
int isgeotiff(char *inFile)
{
    FILE *fp;
    TIFF *tiff=NULL;
    GTIF *gtif=NULL;
    int isGeotiff = 0;
    char magic[2];

    fp = fopen(inFile, "r");
    if (!fp) {
        char n[1024];
        sprintf(n, "%s.tif", inFile);
        fp = fopen(n, "r");
    }
    if (!fp) {
        char *basename = get_basename(inFile);
        char n[1024];
        sprintf(n, "%s.tif", basename);
        fp = fopen(n, "r");
        FREE(basename);
    }
    if (!fp) {
        char *basename = get_basename(inFile);
        char n[1024];
        sprintf(n, "%s.tiff", basename);
        fp = fopen(n, "r");
        FREE(basename);
    }
    if (fp) {
        magic[0] = fgetc(fp);
        magic[1] = fgetc(fp);
        if ((magic[0] == 'I' && magic[1] == 'I') ||
            (magic[0] == 'M' && magic[1] == 'M')  )
        {
            // Looks like a TIFF file, so let's see if it's a GeoTIFF file
            tiff = XTIFFOpen(inFile, "r");
            if (!tiff) isGeotiff = 0; // Not a TIFF (or GeoTIFF) file ...rare if the magic bytes were correct.
            if (tiff) gtif = GTIFNew(tiff);
            if (tiff && !gtif) isGeotiff = 0; // Usually GTIFNew() succeeds even if not a GeoTIFF ...

            if (tiff && gtif) {
                double *tie_point=NULL;
                double *pixel_scale=NULL;
                int tp_count=0, ps_count=0;
                (gtif->gt_methods.get)(gtif->gt_tif, GTIFF_TIEPOINTS, &tp_count, &tie_point);
                (gtif->gt_methods.get)(gtif->gt_tif, GTIFF_PIXELSCALE, &ps_count, &pixel_scale);

                if (tie_point && pixel_scale && tp_count == 6 && ps_count == 3) {
                    // Assume that if tie points and pixel scales exist that the file is a
                    // GeoTIFF ...it's still possible that read_generic_geotiff_metadata() will
                    // fail due to the file only being a georeferenced rather than a geocoded
                    // GeoTIFF, but that's a different problem...
                    isGeotiff = 1;
                }
                FREE(tie_point);
                FREE(pixel_scale);
            }

            if (gtif) GTIFFree(gtif);
            if (tiff) XTIFFClose(tiff);
        }
        fclose(fp);
    }

    return isGeotiff;
}
Exemple #8
0
CPLErr 
GTIFFBuildOverviews( const char * pszFilename,
                     int nBands, GDALRasterBand **papoBandList, 
                     int nOverviews, int * panOverviewList,
                     const char * pszResampling, 
                     GDALProgressFunc pfnProgress, void * pProgressData )

{
    TIFF    *hOTIFF;
    int     nBitsPerPixel=0, nCompression=COMPRESSION_NONE, nPhotometric=0;
    int     nSampleFormat=0, nPlanarConfig, iOverview, iBand;
    int     nXSize=0, nYSize=0;

    if( nBands == 0 || nOverviews == 0 )
        return CE_None;

    GTiffOneTimeInit();

/* -------------------------------------------------------------------- */
/*      Verify that the list of bands is suitable for emitting in       */
/*      TIFF file.                                                      */
/* -------------------------------------------------------------------- */
    for( iBand = 0; iBand < nBands; iBand++ )
    {
        int     nBandBits, nBandFormat;
        GDALRasterBand *hBand = papoBandList[iBand];

        switch( hBand->GetRasterDataType() )
        {
          case GDT_Byte:
            nBandBits = 8;
            nBandFormat = SAMPLEFORMAT_UINT;
            break;

          case GDT_UInt16:
            nBandBits = 16;
            nBandFormat = SAMPLEFORMAT_UINT;
            break;

          case GDT_Int16:
            nBandBits = 16;
            nBandFormat = SAMPLEFORMAT_INT;
            break;

          case GDT_UInt32:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_UINT;
            break;

          case GDT_Int32:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_INT;
            break;

          case GDT_Float32:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_IEEEFP;
            break;

          case GDT_Float64:
            nBandBits = 64;
            nBandFormat = SAMPLEFORMAT_IEEEFP;
            break;

          case GDT_CInt16:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_COMPLEXINT;
            break;

          case GDT_CFloat32:
            nBandBits = 64;
            nBandFormat = SAMPLEFORMAT_COMPLEXIEEEFP;
            break;

          case GDT_CFloat64:
            nBandBits = 128;
            nBandFormat = SAMPLEFORMAT_COMPLEXIEEEFP;
            break;

          default:
            CPLAssert( FALSE );
            return CE_Failure;
        }

        if( iBand == 0 )
        {
            nBitsPerPixel = nBandBits;
            nSampleFormat = nBandFormat;
            nXSize = hBand->GetXSize();
            nYSize = hBand->GetYSize();
        }
        else if( nBitsPerPixel != nBandBits || nSampleFormat != nBandFormat )
        {
            CPLError( CE_Failure, CPLE_NotSupported, 
                      "GTIFFBuildOverviews() doesn't support a mixture of band"
                      " data types." );
            return CE_Failure;
        }
        else if( hBand->GetColorTable() != NULL )
        {
            CPLError( CE_Failure, CPLE_NotSupported, 
                      "GTIFFBuildOverviews() doesn't support building"
                      " overviews of multiple colormapped bands." );
            return CE_Failure;
        }
        else if( hBand->GetXSize() != nXSize 
                 || hBand->GetYSize() != nYSize )
        {
            CPLError( CE_Failure, CPLE_NotSupported, 
                      "GTIFFBuildOverviews() doesn't support building"
                      " overviews of different sized bands." );
            return CE_Failure;
        }
    }

/* -------------------------------------------------------------------- */
/*      Use specified compression method.                               */
/* -------------------------------------------------------------------- */
    const char *pszCompress = CPLGetConfigOption( "COMPRESS_OVERVIEW", NULL );

    if( pszCompress != NULL && pszCompress[0] != '\0' )
    {
        if( EQUAL( pszCompress, "JPEG" ) )
            nCompression = COMPRESSION_JPEG;
        else if( EQUAL( pszCompress, "LZW" ) )
            nCompression = COMPRESSION_LZW;
        else if( EQUAL( pszCompress, "PACKBITS" ))
            nCompression = COMPRESSION_PACKBITS;
        else if( EQUAL( pszCompress, "DEFLATE" ) || EQUAL( pszCompress, "ZIP" ))
            nCompression = COMPRESSION_ADOBE_DEFLATE;
        else
            CPLError( CE_Warning, CPLE_IllegalArg, 
                      "COMPRESS_OVERVIEW=%s value not recognised, ignoring.",
                      pszCompress );
    }

/* -------------------------------------------------------------------- */
/*      Figure out the planar configuration to use.                     */
/* -------------------------------------------------------------------- */
    if( nBands == 1 )
        nPlanarConfig = PLANARCONFIG_CONTIG;
    else
        nPlanarConfig = PLANARCONFIG_SEPARATE;

    const char* pszInterleave = CPLGetConfigOption( "INTERLEAVE_OVERVIEW", NULL );
    if (pszInterleave != NULL && pszInterleave[0] != '\0')
    {
        if( EQUAL( pszInterleave, "PIXEL" ) )
            nPlanarConfig = PLANARCONFIG_CONTIG;
        else if( EQUAL( pszInterleave, "BAND" ) )
            nPlanarConfig = PLANARCONFIG_SEPARATE;
        else
        {
            CPLError( CE_Failure, CPLE_AppDefined, 
                      "INTERLEAVE_OVERVIEW=%s unsupported, value must be PIXEL or BAND. ignoring",
                      pszInterleave );
        }
    }

/* -------------------------------------------------------------------- */
/*      Figure out the photometric interpretation to use.               */
/* -------------------------------------------------------------------- */
    if( nBands == 3 )
        nPhotometric = PHOTOMETRIC_RGB;
    else if( papoBandList[0]->GetColorTable() != NULL 
             && !EQUALN(pszResampling,"AVERAGE_BIT2",12) )
    {
        nPhotometric = PHOTOMETRIC_PALETTE;
        /* should set the colormap up at this point too! */
    }
    else
        nPhotometric = PHOTOMETRIC_MINISBLACK;

    const char* pszPhotometric = CPLGetConfigOption( "PHOTOMETRIC_OVERVIEW", NULL );
    if (pszPhotometric != NULL && pszPhotometric[0] != '\0')
    {
        if( EQUAL( pszPhotometric, "MINISBLACK" ) )
            nPhotometric = PHOTOMETRIC_MINISBLACK;
        else if( EQUAL( pszPhotometric, "MINISWHITE" ) )
            nPhotometric = PHOTOMETRIC_MINISWHITE;
        else if( EQUAL( pszPhotometric, "RGB" ))
        {
            nPhotometric = PHOTOMETRIC_RGB;
        }
        else if( EQUAL( pszPhotometric, "CMYK" ))
        {
            nPhotometric = PHOTOMETRIC_SEPARATED;
        }
        else if( EQUAL( pszPhotometric, "YCBCR" ))
        {
            nPhotometric = PHOTOMETRIC_YCBCR;
        }
        else if( EQUAL( pszPhotometric, "CIELAB" ))
        {
            nPhotometric = PHOTOMETRIC_CIELAB;
        }
        else if( EQUAL( pszPhotometric, "ICCLAB" ))
        {
            nPhotometric = PHOTOMETRIC_ICCLAB;
        }
        else if( EQUAL( pszPhotometric, "ITULAB" ))
        {
            nPhotometric = PHOTOMETRIC_ITULAB;
        }
        else
        {
            CPLError( CE_Warning, CPLE_IllegalArg, 
                      "PHOTOMETRIC_OVERVIEW=%s value not recognised, ignoring.\n",
                      pszPhotometric );
        }
    }

/* -------------------------------------------------------------------- */
/*      Create the file, if it does not already exist.                  */
/* -------------------------------------------------------------------- */
    VSIStatBuf  sStatBuf;

    if( VSIStat( pszFilename, &sStatBuf ) != 0 )
    {
        hOTIFF = XTIFFOpen( pszFilename, "w+" );
        if( hOTIFF == NULL )
        {
            if( CPLGetLastErrorNo() == 0 )
                CPLError( CE_Failure, CPLE_OpenFailed,
                          "Attempt to create new tiff file `%s'\n"
                          "failed in XTIFFOpen().\n",
                          pszFilename );

            return CE_Failure;
        }
    }
/* -------------------------------------------------------------------- */
/*      Otherwise just open it for update access.                       */
/* -------------------------------------------------------------------- */
    else 
    {
        hOTIFF = XTIFFOpen( pszFilename, "r+" );
        if( hOTIFF == NULL )
        {
            if( CPLGetLastErrorNo() == 0 )
                CPLError( CE_Failure, CPLE_OpenFailed,
                          "Attempt to create new tiff file `%s'\n"
                          "failed in XTIFFOpen().\n",
                          pszFilename );

            return CE_Failure;
        }
    }

/* -------------------------------------------------------------------- */
/*      Do we have a palette?  If so, create a TIFF compatible version. */
/* -------------------------------------------------------------------- */
    unsigned short      *panRed=NULL, *panGreen=NULL, *panBlue=NULL;

    if( nPhotometric == PHOTOMETRIC_PALETTE )
    {
        GDALColorTable *poCT = papoBandList[0]->GetColorTable();
        int nColorCount;

        if( nBitsPerPixel <= 8 )
            nColorCount = 256;
        else
            nColorCount = 65536;

        panRed   = (unsigned short *) 
            CPLCalloc(nColorCount,sizeof(unsigned short));
        panGreen = (unsigned short *) 
            CPLCalloc(nColorCount,sizeof(unsigned short));
        panBlue  = (unsigned short *) 
            CPLCalloc(nColorCount,sizeof(unsigned short));

        for( int iColor = 0; iColor < nColorCount; iColor++ )
        {
            GDALColorEntry  sRGB;

            if( poCT->GetColorEntryAsRGB( iColor, &sRGB ) )
            {
                panRed[iColor] = (unsigned short) (257 * sRGB.c1);
                panGreen[iColor] = (unsigned short) (257 * sRGB.c2);
                panBlue[iColor] = (unsigned short) (257 * sRGB.c3);
            }
        }
    }

/* -------------------------------------------------------------------- */
/*      Do we need some metadata for the overviews?                     */
/* -------------------------------------------------------------------- */
    CPLString osMetadata;
    GDALDataset *poBaseDS = papoBandList[0]->GetDataset();

    GTIFFBuildOverviewMetadata( pszResampling, poBaseDS, osMetadata );

/* -------------------------------------------------------------------- */
/*      Loop, creating overviews.                                       */
/* -------------------------------------------------------------------- */
    for( iOverview = 0; iOverview < nOverviews; iOverview++ )
    {
        int    nOXSize, nOYSize;
        uint32 nDirOffset;

        nOXSize = (nXSize + panOverviewList[iOverview] - 1) 
            / panOverviewList[iOverview];
        nOYSize = (nYSize + panOverviewList[iOverview] - 1) 
            / panOverviewList[iOverview];

        nDirOffset = 
            GTIFFWriteDirectory(hOTIFF, FILETYPE_REDUCEDIMAGE,
                                nOXSize, nOYSize, nBitsPerPixel, 
                                nPlanarConfig, nBands,
                                128, 128, TRUE, nCompression,
                                nPhotometric, nSampleFormat, 
                                panRed, panGreen, panBlue,
                                0, NULL, /* FIXME ? how can we fetch extrasamples from here */
                                osMetadata );
    }

    if (panRed)
    {
        CPLFree(panRed);
        CPLFree(panGreen);
        CPLFree(panBlue);
        panRed = panGreen = panBlue = NULL;
    }

    XTIFFClose( hOTIFF );

/* -------------------------------------------------------------------- */
/*      Open the overview dataset so that we can get at the overview    */
/*      bands.                                                          */
/* -------------------------------------------------------------------- */
    GDALDataset *hODS;

    hODS = (GDALDataset *) GDALOpen( pszFilename, GA_Update );
    if( hODS == NULL )
        return CE_Failure;
    
/* -------------------------------------------------------------------- */
/*      Loop writing overview data.                                     */
/* -------------------------------------------------------------------- */

    if (nCompression != COMPRESSION_NONE &&
        nPlanarConfig == PLANARCONFIG_CONTIG &&
        GDALDataTypeIsComplex(papoBandList[0]->GetRasterDataType()) == FALSE &&
        papoBandList[0]->GetColorTable() == NULL &&
        (EQUALN(pszResampling, "NEAR", 4) || EQUAL(pszResampling, "AVERAGE") || EQUAL(pszResampling, "GAUSS")))
    {
        /* In the case of pixel interleaved compressed overviews, we want to generate */
        /* the overviews for all the bands block by block, and not band after band, */
        /* in order to write the block once and not loose space in the TIFF file */

        GDALRasterBand ***papapoOverviewBands;

        papapoOverviewBands = (GDALRasterBand ***) CPLCalloc(sizeof(void*),nBands);
        for( iBand = 0; iBand < nBands; iBand++ )
        {
            GDALRasterBand    *hDstBand = hODS->GetRasterBand( iBand+1 );
            papapoOverviewBands[iBand] = (GDALRasterBand **) CPLCalloc(sizeof(void*),nOverviews);
            papapoOverviewBands[iBand][0] = hDstBand;
            for( int i = 0; i < nOverviews-1; i++ )
            {
                papapoOverviewBands[iBand][i+1] = hDstBand->GetOverview(i);
            }
        }

        GDALRegenerateOverviewsMultiBand(nBands, papoBandList,
                                         nOverviews, papapoOverviewBands,
                                         pszResampling, pfnProgress, pProgressData );

        for( iBand = 0; iBand < nBands; iBand++ )
        {
            CPLFree(papapoOverviewBands[iBand]);
        }
        CPLFree(papapoOverviewBands);
    }
    else
    {
        GDALRasterBand   **papoOverviews;

        papoOverviews = (GDALRasterBand **) CPLCalloc(sizeof(void*),128);

        for( iBand = 0; iBand < nBands; iBand++ )
        {
            GDALRasterBand    *hSrcBand = papoBandList[iBand];
            GDALRasterBand    *hDstBand;
            int               nDstOverviews;
            CPLErr            eErr;

            hDstBand = hODS->GetRasterBand( iBand+1 );

            papoOverviews[0] = hDstBand;
            nDstOverviews = hDstBand->GetOverviewCount() + 1;
            CPLAssert( nDstOverviews < 128 );
            nDstOverviews = MIN(128,nDstOverviews);

            for( int i = 0; i < nDstOverviews-1; i++ )
            {
                papoOverviews[i+1] = hDstBand->GetOverview(i);
            }

            void         *pScaledProgressData;

            pScaledProgressData = 
                GDALCreateScaledProgress( iBand / (double) nBands, 
                                        (iBand+1) / (double) nBands,
                                        pfnProgress, pProgressData );

            eErr = 
                GDALRegenerateOverviews( (GDALRasterBandH) hSrcBand, 
                                        nDstOverviews, 
                                        (GDALRasterBandH *) papoOverviews, 
                                        pszResampling,
                                        GDALScaledProgress, 
                                        pScaledProgressData);

            GDALDestroyScaledProgress( pScaledProgressData );

            if( eErr != CE_None )
            {
                delete hODS;
                return eErr;
            }
        }

        CPLFree( papoOverviews );
    }

/* -------------------------------------------------------------------- */
/*      Cleanup                                                         */
/* -------------------------------------------------------------------- */
    hODS->FlushCache();
    delete hODS;

    pfnProgress( 1.0, NULL, pProgressData );

    return CE_None;
}
Exemple #9
0
int main(int argc, char *argv[])
{
    char	*fname = NULL;
    TIFF 	*tif=(TIFF*)0;  /* TIFF-level descriptor */
    GTIF	*gtif=(GTIF*)0; /* GeoKey-level descriptor */
    int		i, norm_print_flag = 1, proj4_print_flag = 0;
    int		tfw_flag = 0, inv_flag = 0, dec_flag = 0;

    /*
     * Handle command line options.
     */
    for( i = 1; i < argc; i++ )
    {
        if( strcmp(argv[i],"-no_norm") == 0 )
            norm_print_flag = 0;
        else if( strcmp(argv[i],"-t") == 0 )
        {
            CSVDirName = argv[++i];
            SetCSVFilenameHook( CSVFileOverride );
        }
        else if( strcmp(argv[i],"-tfw") == 0 )
            tfw_flag = 1;
        else if( strcmp(argv[i],"-proj4") == 0 )
            proj4_print_flag = 1;
        else if( strcmp(argv[i],"-i") == 0 )
            inv_flag = 1;
        else if( strcmp(argv[i],"-d") == 0 )
            dec_flag = 1;
        else if( fname == NULL && argv[i][0] != '-' )
            fname = argv[i];
        else
        {
            Usage();
        }
    }

    if( fname == NULL )
        Usage();

    /*
     * Open the file, read the GeoTIFF information, and print to stdout. 
     */

    tif=XTIFFOpen(fname,"r");
    if (!tif) goto failure;
	
    gtif = GTIFNew(tif);
    if (!gtif)
    {
        fprintf(stderr,"failed in GTIFNew\n");
        goto failure;
    }

    if( tfw_flag )
    {
        WriteTFWFile( gtif, fname );

        goto Success;
    }
	
    /* dump the GeoTIFF metadata to std out */

    GTIFPrint(gtif,0,0);

    /*
     * Capture, and report normalized information if requested.
     */

    if( norm_print_flag )
    {
        GTIFDefn	defn;
        
        if( GTIFGetDefn( gtif, &defn ) )
        {
            int		xsize, ysize;
            
            printf( "\n" );
            GTIFPrintDefn( &defn, stdout );

            if( proj4_print_flag )
            {
                printf( "\n" );
                printf( "PROJ.4 Definition: %s\n", GTIFGetProj4Defn(&defn));
            }
            
            TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &xsize );
            TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &ysize );
            GTIFPrintCorners( gtif, &defn, stdout, xsize, ysize, inv_flag, dec_flag );
        }

    }

  Success:
    GTIFFree(gtif);
    XTIFFClose(tif);
    return 0;
		
  failure:
    fprintf(stderr,"failure in listgeo\n");
    if (tif) XTIFFClose(tif);
    if (gtif) GTIFFree(gtif);
    return 1;
}
Exemple #10
0
CPLErr
GTIFFBuildOverviews( const char * pszFilename,
                     int nBands, GDALRasterBand **papoBandList,
                     int nOverviews, int * panOverviewList,
                     const char * pszResampling,
                     GDALProgressFunc pfnProgress, void * pProgressData )

{
    if( nBands == 0 || nOverviews == 0 )
        return CE_None;

    if( !GTiffOneTimeInit() )
        return CE_Failure;

    TIFF *hOTIFF = nullptr;
    int nBitsPerPixel = 0;
    int nCompression = COMPRESSION_NONE;
    int nPhotometric = 0;
    int nSampleFormat = 0;
    int nPlanarConfig = 0;
    int iOverview = 0;
    int nXSize = 0;
    int nYSize = 0;

/* -------------------------------------------------------------------- */
/*      Verify that the list of bands is suitable for emitting in       */
/*      TIFF file.                                                      */
/* -------------------------------------------------------------------- */
    for( int iBand = 0; iBand < nBands; iBand++ )
    {
        int nBandBits = 0;
        int nBandFormat = 0;
        GDALRasterBand *hBand = papoBandList[iBand];

        switch( hBand->GetRasterDataType() )
        {
          case GDT_Byte:
            nBandBits = 8;
            nBandFormat = SAMPLEFORMAT_UINT;
            break;

          case GDT_UInt16:
            nBandBits = 16;
            nBandFormat = SAMPLEFORMAT_UINT;
            break;

          case GDT_Int16:
            nBandBits = 16;
            nBandFormat = SAMPLEFORMAT_INT;
            break;

          case GDT_UInt32:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_UINT;
            break;

          case GDT_Int32:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_INT;
            break;

          case GDT_Float32:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_IEEEFP;
            break;

          case GDT_Float64:
            nBandBits = 64;
            nBandFormat = SAMPLEFORMAT_IEEEFP;
            break;

          case GDT_CInt16:
            nBandBits = 32;
            nBandFormat = SAMPLEFORMAT_COMPLEXINT;
            break;

          case GDT_CInt32:
            nBandBits = 64;
            nBandFormat = SAMPLEFORMAT_COMPLEXINT;
            break;

          case GDT_CFloat32:
            nBandBits = 64;
            nBandFormat = SAMPLEFORMAT_COMPLEXIEEEFP;
            break;

          case GDT_CFloat64:
            nBandBits = 128;
            nBandFormat = SAMPLEFORMAT_COMPLEXIEEEFP;
            break;

          default:
            CPLAssert( false );
            return CE_Failure;
        }

        if( hBand->GetMetadataItem( "NBITS", "IMAGE_STRUCTURE" ) )
        {
            nBandBits =
                atoi(hBand->GetMetadataItem("NBITS", "IMAGE_STRUCTURE"));

            if( nBandBits == 1
                && STARTS_WITH_CI(pszResampling, "AVERAGE_BIT2") )
                nBandBits = 8;
        }

        if( iBand == 0 )
        {
            nBitsPerPixel = nBandBits;
            nSampleFormat = nBandFormat;
            nXSize = hBand->GetXSize();
            nYSize = hBand->GetYSize();
        }
        else if( nBitsPerPixel != nBandBits || nSampleFormat != nBandFormat )
        {
            CPLError( CE_Failure, CPLE_NotSupported,
                      "GTIFFBuildOverviews() doesn't support a mixture of band"
                      " data types." );
            return CE_Failure;
        }
        else if( hBand->GetColorTable() != nullptr )
        {
            CPLError( CE_Failure, CPLE_NotSupported,
                      "GTIFFBuildOverviews() doesn't support building"
                      " overviews of multiple colormapped bands." );
            return CE_Failure;
        }
        else if( hBand->GetXSize() != nXSize
                 || hBand->GetYSize() != nYSize )
        {
            CPLError( CE_Failure, CPLE_NotSupported,
                      "GTIFFBuildOverviews() doesn't support building"
                      " overviews of different sized bands." );
            return CE_Failure;
        }
    }

/* -------------------------------------------------------------------- */
/*      Use specified compression method.                               */
/* -------------------------------------------------------------------- */
    const char *pszCompress = CPLGetConfigOption( "COMPRESS_OVERVIEW", nullptr );

    if( pszCompress != nullptr && pszCompress[0] != '\0' )
    {
        nCompression =
            GTIFFGetCompressionMethod(pszCompress, "COMPRESS_OVERVIEW");
        if( nCompression < 0 )
            return CE_Failure;
    }

    if( nCompression == COMPRESSION_JPEG && nBitsPerPixel > 8 )
    {
        if( nBitsPerPixel > 16 )
        {
            CPLError( CE_Failure, CPLE_NotSupported,
                      "GTIFFBuildOverviews() doesn't support building"
                      " JPEG compressed overviews of nBitsPerPixel > 16." );
            return CE_Failure;
        }

        nBitsPerPixel = 12;
    }

/* -------------------------------------------------------------------- */
/*      Figure out the planar configuration to use.                     */
/* -------------------------------------------------------------------- */
    if( nBands == 1 )
        nPlanarConfig = PLANARCONFIG_CONTIG;
    else
        nPlanarConfig = PLANARCONFIG_SEPARATE;

    bool bSourceIsPixelInterleaved = false;
    bool bSourceIsJPEG2000 = false;
    if( nBands > 1 )
    {
        GDALDataset* poSrcDS = papoBandList[0]->GetDataset();
        if( poSrcDS )
        {
            const char* pszSrcInterleave = poSrcDS->GetMetadataItem("INTERLEAVE",
                                                                "IMAGE_STRUCTURE");
            if( pszSrcInterleave && EQUAL(pszSrcInterleave, "PIXEL") )
            {
                bSourceIsPixelInterleaved = true;
            }
        }

        const char* pszSrcCompression = papoBandList[0]->GetMetadataItem("COMPRESSION",
                                                                "IMAGE_STRUCTURE");
        if( pszSrcCompression )
        {
            bSourceIsJPEG2000 = EQUAL(pszSrcCompression, "JPEG2000");
        }
        if( bSourceIsPixelInterleaved && bSourceIsJPEG2000 )
        {
            nPlanarConfig = PLANARCONFIG_CONTIG;
        }
    }

    const char* pszInterleave =
        CPLGetConfigOption( "INTERLEAVE_OVERVIEW", nullptr );
    if( pszInterleave != nullptr && pszInterleave[0] != '\0' )
    {
        if( EQUAL( pszInterleave, "PIXEL" ) )
            nPlanarConfig = PLANARCONFIG_CONTIG;
        else if( EQUAL( pszInterleave, "BAND" ) )
            nPlanarConfig = PLANARCONFIG_SEPARATE;
        else
        {
            CPLError(
                CE_Failure, CPLE_AppDefined,
                "INTERLEAVE_OVERVIEW=%s unsupported, "
                "value must be PIXEL or BAND. ignoring",
                pszInterleave );
        }
    }

/* -------------------------------------------------------------------- */
/*      Figure out the photometric interpretation to use.               */
/* -------------------------------------------------------------------- */
    if( nBands == 3 )
        nPhotometric = PHOTOMETRIC_RGB;
    else if( papoBandList[0]->GetColorTable() != nullptr
             && !STARTS_WITH_CI(pszResampling, "AVERAGE_BIT2") )
    {
        nPhotometric = PHOTOMETRIC_PALETTE;
        // Should set the colormap up at this point too!
    }
    else if( nBands >= 3 &&
             papoBandList[0]->GetColorInterpretation() == GCI_RedBand &&
             papoBandList[1]->GetColorInterpretation() == GCI_GreenBand &&
             papoBandList[2]->GetColorInterpretation() == GCI_BlueBand )
    {
        nPhotometric = PHOTOMETRIC_RGB;
    }
    else
        nPhotometric = PHOTOMETRIC_MINISBLACK;

    const char* pszPhotometric =
        CPLGetConfigOption( "PHOTOMETRIC_OVERVIEW", nullptr );
    if( pszPhotometric != nullptr && pszPhotometric[0] != '\0' )
    {
        if( EQUAL( pszPhotometric, "MINISBLACK" ) )
            nPhotometric = PHOTOMETRIC_MINISBLACK;
        else if( EQUAL( pszPhotometric, "MINISWHITE" ) )
            nPhotometric = PHOTOMETRIC_MINISWHITE;
        else if( EQUAL( pszPhotometric, "RGB" ))
        {
            nPhotometric = PHOTOMETRIC_RGB;
        }
        else if( EQUAL( pszPhotometric, "CMYK" ))
        {
            nPhotometric = PHOTOMETRIC_SEPARATED;
        }
        else if( EQUAL( pszPhotometric, "YCBCR" ))
        {
            nPhotometric = PHOTOMETRIC_YCBCR;

            // Because of subsampling, setting YCBCR without JPEG compression
            // leads to a crash currently. Would need to make
            // GTiffRasterBand::IWriteBlock() aware of subsampling so that it
            // doesn't overrun buffer size returned by libtiff.
            if( nCompression != COMPRESSION_JPEG )
            {
                CPLError(
                    CE_Failure, CPLE_NotSupported,
                    "Currently, PHOTOMETRIC_OVERVIEW=YCBCR requires "
                    "COMPRESS_OVERVIEW=JPEG" );
                return CE_Failure;
            }

            if( pszInterleave != nullptr &&
                pszInterleave[0] != '\0' &&
                nPlanarConfig == PLANARCONFIG_SEPARATE )
            {
                CPLError(
                    CE_Failure, CPLE_NotSupported,
                    "PHOTOMETRIC_OVERVIEW=YCBCR requires "
                    "INTERLEAVE_OVERVIEW=PIXEL" );
                return CE_Failure;
            }
            else
            {
                nPlanarConfig = PLANARCONFIG_CONTIG;
            }

            // YCBCR strictly requires 3 bands. Not less, not more
            // Issue an explicit error message as libtiff one is a bit cryptic:
            // JPEGLib:Bogus input colorspace.
            if( nBands != 3 )
            {
                CPLError(
                    CE_Failure, CPLE_NotSupported,
                    "PHOTOMETRIC_OVERVIEW=YCBCR requires a source raster "
                    "with only 3 bands (RGB)" );
                return CE_Failure;
            }
        }
        else if( EQUAL( pszPhotometric, "CIELAB" ))
        {
            nPhotometric = PHOTOMETRIC_CIELAB;
        }
        else if( EQUAL( pszPhotometric, "ICCLAB" ))
        {
            nPhotometric = PHOTOMETRIC_ICCLAB;
        }
        else if( EQUAL( pszPhotometric, "ITULAB" ))
        {
            nPhotometric = PHOTOMETRIC_ITULAB;
        }
        else
        {
            CPLError(
                CE_Warning, CPLE_IllegalArg,
                "PHOTOMETRIC_OVERVIEW=%s value not recognised, ignoring.",
                pszPhotometric );
        }
    }

/* -------------------------------------------------------------------- */
/*      Figure out the predictor value to use.                          */
/* -------------------------------------------------------------------- */
    int nPredictor = PREDICTOR_NONE;
    if( nCompression == COMPRESSION_LZW ||
        nCompression == COMPRESSION_ADOBE_DEFLATE )
    {
        const char* pszPredictor =
            CPLGetConfigOption( "PREDICTOR_OVERVIEW", nullptr );
        if( pszPredictor != nullptr )
        {
            nPredictor = atoi( pszPredictor );
        }
    }

/* -------------------------------------------------------------------- */
/*      Create the file, if it does not already exist.                  */
/* -------------------------------------------------------------------- */
    VSIStatBufL sStatBuf;
    VSILFILE* fpL = nullptr;

    if( VSIStatExL( pszFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG ) != 0 )
    {
    /* -------------------------------------------------------------------- */
    /*      Compute the uncompressed size.                                  */
    /* -------------------------------------------------------------------- */
        double dfUncompressedOverviewSize = 0;
        int nDataTypeSize =
            GDALGetDataTypeSizeBytes(papoBandList[0]->GetRasterDataType());

        for( iOverview = 0; iOverview < nOverviews; iOverview++ )
        {
            const int nOXSize = (nXSize + panOverviewList[iOverview] - 1)
                / panOverviewList[iOverview];
            const int nOYSize = (nYSize + panOverviewList[iOverview] - 1)
                / panOverviewList[iOverview];

            dfUncompressedOverviewSize +=
                nOXSize * static_cast<double>(nOYSize) * nBands * nDataTypeSize;
        }

        if( nCompression == COMPRESSION_NONE
            && dfUncompressedOverviewSize > 4200000000.0 )
        {
    #ifndef BIGTIFF_SUPPORT
            CPLError(
                CE_Failure, CPLE_NotSupported,
                "The overview file would be larger than 4GB, "
                "but this is the largest size a TIFF can be, "
                "and BigTIFF is unavailable.  "
                "Creation failed." );
            return CE_Failure;
    #endif
        }
    /* -------------------------------------------------------------------- */
    /*      Should the file be created as a bigtiff file?                   */
    /* -------------------------------------------------------------------- */
        const char *pszBIGTIFF = CPLGetConfigOption( "BIGTIFF_OVERVIEW", nullptr );

        if( pszBIGTIFF == nullptr )
            pszBIGTIFF = "IF_SAFER";

        bool bCreateBigTIFF = false;
        if( EQUAL(pszBIGTIFF,"IF_NEEDED") )
        {
            if( nCompression == COMPRESSION_NONE
                && dfUncompressedOverviewSize > 4200000000.0 )
                bCreateBigTIFF = true;
        }
        else if( EQUAL(pszBIGTIFF,"IF_SAFER") )
        {
            // Look at the size of the base image and suppose that
            // the added overview levels won't be more than 1/2 of
            // the size of the base image. The theory says 1/3 of the
            // base image size if the overview levels are 2, 4, 8, 16.
            // Thus take 1/2 as the security margin for 1/3.
            const double dfUncompressedImageSize =
                nXSize * static_cast<double>(nYSize) * nBands * nDataTypeSize;
            if( dfUncompressedImageSize * 0.5 > 4200000000.0 )
                bCreateBigTIFF = true;
        }
        else
        {
            bCreateBigTIFF = CPLTestBool( pszBIGTIFF );
            if( !bCreateBigTIFF && nCompression == COMPRESSION_NONE
                && dfUncompressedOverviewSize > 4200000000.0 )
            {
                CPLError(
                    CE_Failure, CPLE_NotSupported,
                    "The overview file will be larger than 4GB, "
                    "so BigTIFF is necessary.  "
                    "Creation failed.");
                return CE_Failure;
            }
        }

    #ifndef BIGTIFF_SUPPORT
        if( bCreateBigTIFF )
        {
            CPLError(
                CE_Warning, CPLE_NotSupported,
                "BigTIFF requested, but GDAL built without BigTIFF "
                "enabled libtiff, request ignored." );
            bCreateBigTIFF = false;
        }
    #endif

        if( bCreateBigTIFF )
            CPLDebug( "GTiff", "File being created as a BigTIFF." );

        fpL = VSIFOpenL( pszFilename, "w+" );
        if( fpL == nullptr )
            hOTIFF = nullptr;
        else
            hOTIFF =
               VSI_TIFFOpen( pszFilename, bCreateBigTIFF ? "w+8" : "w+", fpL );
        if( hOTIFF == nullptr )
        {
            if( CPLGetLastErrorNo() == 0 )
                CPLError( CE_Failure, CPLE_OpenFailed,
                          "Attempt to create new tiff file `%s' "
                          "failed in VSI_TIFFOpen().",
                          pszFilename );
            if( fpL != nullptr )
                CPL_IGNORE_RET_VAL(VSIFCloseL(fpL));
            return CE_Failure;
        }
    }
/* -------------------------------------------------------------------- */
/*      Otherwise just open it for update access.                       */
/* -------------------------------------------------------------------- */
    else
    {
        fpL = VSIFOpenL( pszFilename, "r+" );
        if( fpL == nullptr )
            hOTIFF = nullptr;
        else
            hOTIFF = VSI_TIFFOpen( pszFilename, "r+", fpL );
        if( hOTIFF == nullptr )
        {
            if( CPLGetLastErrorNo() == 0 )
                CPLError( CE_Failure, CPLE_OpenFailed,
                          "Attempt to create new tiff file `%s' "
                          "failed in VSI_TIFFOpen().",
                          pszFilename );
            if( fpL != nullptr )
                CPL_IGNORE_RET_VAL(VSIFCloseL(fpL));
            return CE_Failure;
        }
    }

/* -------------------------------------------------------------------- */
/*      Do we have a palette?  If so, create a TIFF compatible version. */
/* -------------------------------------------------------------------- */
    unsigned short *panRed = nullptr;
    unsigned short *panGreen = nullptr;
    unsigned short *panBlue = nullptr;

    if( nPhotometric == PHOTOMETRIC_PALETTE )
    {
        GDALColorTable *poCT = papoBandList[0]->GetColorTable();
        int nColorCount = 65536;

        if( nBitsPerPixel <= 8 )
            nColorCount = 256;

        panRed = static_cast<unsigned short *>(
            CPLCalloc(nColorCount, sizeof(unsigned short)) );
        panGreen = static_cast<unsigned short *>(
            CPLCalloc(nColorCount, sizeof(unsigned short)) );
        panBlue = static_cast<unsigned short *>(
            CPLCalloc(nColorCount, sizeof(unsigned short)) );

        for( int iColor = 0; iColor < nColorCount; iColor++ )
        {
          GDALColorEntry sRGB = { 0, 0, 0, 0 };

            if( poCT->GetColorEntryAsRGB( iColor, &sRGB ) )
            {
                // TODO(schwehr): Check for underflow.
                // Going from signed short to unsigned short.
                panRed[iColor] = static_cast<unsigned short>(257 * sRGB.c1);
                panGreen[iColor] = static_cast<unsigned short>(257 * sRGB.c2);
                panBlue[iColor] = static_cast<unsigned short>(257 * sRGB.c3);
            }
        }
    }

/* -------------------------------------------------------------------- */
/*      Do we need some metadata for the overviews?                     */
/* -------------------------------------------------------------------- */
    CPLString osMetadata;
    GDALDataset *poBaseDS = papoBandList[0]->GetDataset();

    GTIFFBuildOverviewMetadata( pszResampling, poBaseDS, osMetadata );

/* -------------------------------------------------------------------- */
/*      Loop, creating overviews.                                       */
/* -------------------------------------------------------------------- */
    int nOvrBlockXSize = 0;
    int nOvrBlockYSize = 0;
    GTIFFGetOverviewBlockSize(&nOvrBlockXSize, &nOvrBlockYSize);

    CPLString osNoData; // don't move this in inner scope
    const char* pszNoData = nullptr;
    int bNoDataSet = FALSE;
    const double dfNoDataValue = papoBandList[0]->GetNoDataValue(&bNoDataSet);
    if( bNoDataSet )
    {
        osNoData = GTiffFormatGDALNoDataTagValue(dfNoDataValue);
        pszNoData = osNoData.c_str();
    }

    std::vector<uint16> anExtraSamples;
    for( int i = GTIFFGetMaxColorChannels(nPhotometric)+1; i <= nBands; i++ )
    {
        if( papoBandList[i-1]->GetColorInterpretation() == GCI_AlphaBand )
        {
            anExtraSamples.push_back(
                GTiffGetAlphaValue(CPLGetConfigOption("GTIFF_ALPHA", nullptr),
                                   DEFAULT_ALPHA_TYPE));
        }
        else
        {
            anExtraSamples.push_back(EXTRASAMPLE_UNSPECIFIED);
        }
    }

    for( iOverview = 0; iOverview < nOverviews; iOverview++ )
    {
        const int nOXSize = (nXSize + panOverviewList[iOverview] - 1)
            / panOverviewList[iOverview];
        const int nOYSize = (nYSize + panOverviewList[iOverview] - 1)
            / panOverviewList[iOverview];

        GTIFFWriteDirectory( hOTIFF, FILETYPE_REDUCEDIMAGE,
                             nOXSize, nOYSize, nBitsPerPixel,
                             nPlanarConfig, nBands,
                             nOvrBlockXSize, nOvrBlockYSize, TRUE, nCompression,
                             nPhotometric, nSampleFormat, nPredictor,
                             panRed, panGreen, panBlue,
                             static_cast<int>(anExtraSamples.size()),
                             anExtraSamples.empty() ? nullptr : anExtraSamples.data(),
                             osMetadata,
                             CPLGetConfigOption( "JPEG_QUALITY_OVERVIEW", nullptr ),
                             CPLGetConfigOption( "JPEG_TABLESMODE_OVERVIEW", nullptr ),
                             pszNoData,
                             nullptr
                           );
    }

    if( panRed )
    {
        CPLFree(panRed);
        CPLFree(panGreen);
        CPLFree(panBlue);
        panRed = nullptr;
        panGreen = nullptr;
        panBlue = nullptr;
    }

    XTIFFClose( hOTIFF );
    if( VSIFCloseL(fpL) != 0 )
        return CE_Failure;
    fpL = nullptr;

/* -------------------------------------------------------------------- */
/*      Open the overview dataset so that we can get at the overview    */
/*      bands.                                                          */
/* -------------------------------------------------------------------- */
    GDALDataset *hODS = GDALDataset::Open( pszFilename,
                                           GDAL_OF_RASTER | GDAL_OF_UPDATE );
    if( hODS == nullptr )
        return CE_Failure;

/* -------------------------------------------------------------------- */
/*      Do we need to set the jpeg quality?                             */
/* -------------------------------------------------------------------- */
    TIFF *hTIFF = static_cast<TIFF *>( hODS->GetInternalHandle(nullptr) );

    if( nCompression == COMPRESSION_JPEG
        && CPLGetConfigOption( "JPEG_QUALITY_OVERVIEW", nullptr ) != nullptr )
    {
        const int nJpegQuality =
            atoi(CPLGetConfigOption("JPEG_QUALITY_OVERVIEW","75"));
        TIFFSetField( hTIFF, TIFFTAG_JPEGQUALITY,
                      nJpegQuality );
        GTIFFSetJpegQuality(GDALDataset::ToHandle(hODS), nJpegQuality);
    }

    if( nCompression == COMPRESSION_JPEG
        && CPLGetConfigOption( "JPEG_TABLESMODE_OVERVIEW", nullptr ) != nullptr )
    {
        const int nJpegTablesMode =
            atoi(CPLGetConfigOption("JPEG_TABLESMODE_OVERVIEW",
                            CPLSPrintf("%d", knGTIFFJpegTablesModeDefault)));
        TIFFSetField( hTIFF, TIFFTAG_JPEGTABLESMODE,
                      nJpegTablesMode );
        GTIFFSetJpegTablesMode(GDALDataset::ToHandle(hODS), nJpegTablesMode);
    }

/* -------------------------------------------------------------------- */
/*      Loop writing overview data.                                     */
/* -------------------------------------------------------------------- */

    int *panOverviewListSorted =
        static_cast<int*>(CPLMalloc(sizeof(int) * nOverviews));
    memcpy( panOverviewListSorted, panOverviewList, sizeof(int) * nOverviews);
    std::sort(panOverviewListSorted, panOverviewListSorted + nOverviews);

    GTIFFSetInExternalOvr(true);

    CPLErr eErr = CE_None;

    if(  ((bSourceIsPixelInterleaved && bSourceIsJPEG2000) ||
          (nCompression != COMPRESSION_NONE)) &&
         nPlanarConfig == PLANARCONFIG_CONTIG &&
         !GDALDataTypeIsComplex(papoBandList[0]->GetRasterDataType()) &&
         papoBandList[0]->GetColorTable() == nullptr &&
         (STARTS_WITH_CI(pszResampling, "NEAR") ||
          EQUAL(pszResampling, "AVERAGE") ||
          EQUAL(pszResampling, "GAUSS") ||
          EQUAL(pszResampling, "CUBIC") ||
          EQUAL(pszResampling, "CUBICSPLINE") ||
          EQUAL(pszResampling, "LANCZOS") ||
          EQUAL(pszResampling, "BILINEAR")) )
    {
        // In the case of pixel interleaved compressed overviews, we want to
        // generate the overviews for all the bands block by block, and not
        // band after band, in order to write the block once and not loose
        // space in the TIFF file.
        GDALRasterBand ***papapoOverviewBands =
            static_cast<GDALRasterBand ***>(
                CPLCalloc(sizeof(void *), nBands) );
        for( int iBand = 0; iBand < nBands && eErr == CE_None; iBand++ )
        {
            GDALRasterBand *poSrcBand = papoBandList[iBand];
            GDALRasterBand *poDstBand = hODS->GetRasterBand( iBand + 1 );
            papapoOverviewBands[iBand] =
                static_cast<GDALRasterBand **>(
                    CPLCalloc(sizeof(void *), nOverviews) );

            int bHasNoData = FALSE;
            const double noDataValue = poSrcBand->GetNoDataValue(&bHasNoData);
            if( bHasNoData )
                poDstBand->SetNoDataValue(noDataValue);

            for( int i = 0; i < nOverviews && eErr == CE_None; i++ )
            {
                for( int j = -1; j < poDstBand->GetOverviewCount() &&
                                 eErr == CE_None; j++ )
                {
                    GDALRasterBand * poOverview =
                            (j < 0 ) ? poDstBand : poDstBand->GetOverview( j );
                    if( poOverview == nullptr )
                    {
                        eErr = CE_Failure;
                        continue;
                    }

                    const int nOvFactor =
                        GDALComputeOvFactor(poOverview->GetXSize(),
                                            poSrcBand->GetXSize(),
                                            poOverview->GetYSize(),
                                            poSrcBand->GetYSize());

                    if( nOvFactor == panOverviewListSorted[i]
                        || nOvFactor == GDALOvLevelAdjust2(
                                            panOverviewListSorted[i],
                                            poSrcBand->GetXSize(),
                                            poSrcBand->GetYSize() ) )
                    {
                        papapoOverviewBands[iBand][i] = poOverview;
                        if( bHasNoData )
                            poOverview->SetNoDataValue(noDataValue);
                        break;
                    }
                }
                CPLAssert( papapoOverviewBands[iBand][i] != nullptr );
            }
        }

        if( eErr == CE_None )
            eErr =
                GDALRegenerateOverviewsMultiBand(
                    nBands, papoBandList,
                    nOverviews, papapoOverviewBands,
                    pszResampling, pfnProgress, pProgressData );

        for( int iBand = 0; iBand < nBands; iBand++ )
        {
            CPLFree(papapoOverviewBands[iBand]);
        }
        CPLFree(papapoOverviewBands);
    }
    else
    {
        GDALRasterBand **papoOverviews =
            static_cast<GDALRasterBand **>(
                CPLCalloc( sizeof(void*), knMaxOverviews ) );

        for( int iBand = 0; iBand < nBands && eErr == CE_None; iBand++ )
        {
            GDALRasterBand *hSrcBand = papoBandList[iBand];
            GDALRasterBand *hDstBand = hODS->GetRasterBand( iBand + 1 );

            int bHasNoData = FALSE;
            const double noDataValue = hSrcBand->GetNoDataValue(&bHasNoData);
            if( bHasNoData )
                hDstBand->SetNoDataValue(noDataValue);

            // FIXME: this logic regenerates all overview bands, not only the
            // ones requested.

            papoOverviews[0] = hDstBand;
            int nDstOverviews = hDstBand->GetOverviewCount() + 1;
            CPLAssert( nDstOverviews < knMaxOverviews );
            nDstOverviews = std::min(knMaxOverviews, nDstOverviews);

            // TODO(schwehr): Convert to starting with i = 1 and remove +1.
            for( int i = 0; i < nDstOverviews - 1 && eErr == CE_None; i++ )
            {
                papoOverviews[i+1] = hDstBand->GetOverview(i);
                if( papoOverviews[i+1] == nullptr )
                {
                    eErr = CE_Failure;
                }
                else
                {
                    if( bHasNoData )
                        papoOverviews[i+1]->SetNoDataValue(noDataValue);
                }
            }

            void *pScaledProgressData =
                GDALCreateScaledProgress(
                    iBand / static_cast<double>( nBands ),
                    (iBand + 1) / static_cast<double>( nBands ),
                    pfnProgress, pProgressData );

            if( eErr == CE_None )
                eErr =
                    GDALRegenerateOverviews(
                        hSrcBand,
                        nDstOverviews,
                        reinterpret_cast<GDALRasterBandH *>( papoOverviews ),
                        pszResampling,
                        GDALScaledProgress,
                        pScaledProgressData );

            GDALDestroyScaledProgress( pScaledProgressData );
        }

        CPLFree( papoOverviews );
    }

/* -------------------------------------------------------------------- */
/*      Cleanup                                                         */
/* -------------------------------------------------------------------- */
    if( eErr == CE_None )
        hODS->FlushCache();
    delete hODS;

    GTIFFSetInExternalOvr(false);

    CPLFree(panOverviewListSorted);

    pfnProgress( 1.0, nullptr, pProgressData );

    return eErr;
}
Exemple #11
0
int main(int argc, char *argv[])
{
    char	*fname = NULL;
    char        *outfile = NULL;
    TIFF 	*tif=(TIFF*)0;  /* TIFF-level descriptor */
    GTIF	*gtif=(GTIF*)0; /* GeoKey-level descriptor */
    int		i, j, norm_print_flag = 0, proj4_print_flag = 0;
    int		tfw_flag = 0, inv_flag = 0, dec_flag = 1;
    int         st_test_flag = 0;
    size_t npixels;
    int16* elevations;
    int x, y, skip;
    GTIFDefn	defn;
    FILE* out;

    /*
     * Handle command line options.
     */
    for( i = 1; i < argc; i++ )
    {
        if( fname == NULL && argv[i][0] != '-' )
            fname = argv[i];
        else
        {
            Usage();
        }
    }
    if( fname == NULL)
        Usage();

    skip = 5;

    /*
     * Open the file, read the GeoTIFF information, and print to stdout. 
     */
    int flength = strlen(fname);
    outfile = (char *) malloc(flength);
    strncpy(outfile,fname,flength-4);
    strcat(outfile, ".asc\0");
    out = fopen(outfile, "w");
    printf("Writing to %s\n\n",outfile);
    free(outfile);

    tif=XTIFFOpen(fname,"r");
    if (!tif) goto failure;
    
    gtif = GTIFNew(tif);
    if (!gtif)
      {
	fprintf(stderr,"failed in GTIFNew\n");
	goto failure;
      }
	
    /* dump the GeoTIFF metadata to std out */

    GTIFPrint(gtif,0,0);

    if( GTIFGetDefn( gtif, &defn ) )
      {
	uint32		xsize, ysize;
        
	printf( "\n" );
	GTIFPrintDefn( &defn, stdout );
	
	if( proj4_print_flag )
	  {
	    printf( "\n" );
	    printf( "PROJ.4 Definition: %s\n", GTIFGetProj4Defn(&defn));
	  }
	int count, orient;
	double* data;
	TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &xsize );
	TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &ysize );
	TIFFGetField( tif, TIFFTAG_GEOPIXELSCALE, &count, &data);
	TIFFGetField( tif, TIFFTAG_ORIENTATION, &orient );
	printf("Orientation:%d\n",orient);

	GTIFPrintCorners( gtif, &defn, stdout, xsize, ysize, inv_flag, dec_flag );
	const char* project = "ASTERGDEM";
	const char* yymmdd = "090629";
	double originx, originy;
	GTIFImageToPCS( gtif, &originx, &originy);
	int lat = (int)originy*1000;
	int lon = (int)originx*1000;
	int xmin = 0;
	int ymin = 0;
	int nx = xsize/skip + 1;
	int ny = ysize/skip + 1;
	int dx = 30 * skip;
	int dy = 30 * skip;
	int16 elev = 0;
	fprintf(out, "%12s%12s%7d%7d%7d%7d%7d%7d%7d%7d\n",
	       project, yymmdd, lat, lon, xmin, ymin, nx, ny, dx,dy);
	npixels = xsize * ysize;
	int16* buf;
	tsample_t sample;
	int nbytes;
	nbytes = TIFFScanlineSize(tif);
	buf = (int16*) _TIFFmalloc(nbytes);
	elevations = (int16*) _TIFFmalloc(npixels * sizeof (int16));
	if (elevations != NULL) {
	    for( y = 0; y < ysize; y++ )
	      {
		uint32 row = ysize - 1 - y;
		TIFFReadScanline(tif, buf, row, sample);
		for( x = 0; x < xsize; x++ ) 
		  {
		    elevations[y*xsize + x] = buf[x];
		  }
	      }	    
	  _TIFFfree(buf);
	}
	for( y = 0; y < ysize; y+=skip ) {
	  for( x = 0; x < xsize; x+=skip ) {
	    fprintf(out, "%6d", elevations[y*xsize + x]);
	  }
	  fprintf(out, "\n");
	}
	_TIFFfree(elevations);

      }
    
  Success:
    GTIFFree(gtif);
    if( st_test_flag )
        ST_Destroy( (ST_TIFF *) tif );
    else
        XTIFFClose(tif);
    GTIFDeaccessCSV();
    return 0;
		
  failure:
    fprintf(stderr,"failure in listgeo\n");
    if (tif) XTIFFClose(tif);
    if (gtif) GTIFFree(gtif);
    GTIFDeaccessCSV();
    return 1;
}
Exemple #12
0
bool TiffDetails::savePict(QString strFilename, QImage img, const SessionItem *pItem)
{
   if (strFilename.isEmpty() || img.isNull())
   {
      return false;
   }

   std::string filename = strFilename.toStdString();

   unsigned int outputWidth = img.width();
   unsigned int outputHeight = img.height();

   if (mpOptionsWidget.get() == NULL)
   {
      computeExportResolution(outputWidth, outputHeight);
   }
   else
   {
      mpOptionsWidget->getResolution(outputWidth, outputHeight);
   }
   img = img.scaled(outputWidth, outputHeight);

#if defined(WIN_API)
   // replace "/" with "\\" to accommodate the sgi specific code
   // in the library
   unsigned int i;
   for (i = 0; i < filename.length(); i++)
   {
      if (filename[i] == '/')
      {
         filename[i] = '\\';
      }
   }
#endif

   //open the file to write
   TIFF* pOut = XTIFFOpen(filename.c_str(), "wb");
   if (pOut == NULL)
   {
      return false;
   }

   unsigned int rowsPerStrip = OptionsTiffExporter::getSettingRowsPerStrip();
   bool packBits = OptionsTiffExporter::getSettingPackBitsCompression();
   bool saveBackgroundAsTransparent = isBackgroundTransparent();
   if (mpOptionsWidget.get() != NULL)
   {
      rowsPerStrip = mpOptionsWidget->getRowsPerStrip();
      packBits = mpOptionsWidget->getPackBitsCompression();
   }
   int samplesPerPixel = 3;
   if (saveBackgroundAsTransparent)
   {
      samplesPerPixel = 4;
   }
   // Initialize private variables for tiff
   TIFFSetField(pOut, TIFFTAG_IMAGEWIDTH, static_cast<uint32>(img.width()));
   TIFFSetField(pOut, TIFFTAG_IMAGELENGTH, static_cast<uint32>(img.height()));
   TIFFSetField(pOut, TIFFTAG_BITSPERSAMPLE, 8);
   TIFFSetField(pOut, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
   TIFFSetField(pOut, TIFFTAG_SAMPLESPERPIXEL, samplesPerPixel);
   TIFFSetField(pOut, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
   TIFFSetField(pOut, TIFFTAG_ROWSPERSTRIP, rowsPerStrip);
   TIFFSetField(pOut, TIFFTAG_COMPRESSION, (packBits ? COMPRESSION_PACKBITS : COMPRESSION_NONE));

   //allocate the memory needed
   tdata_t pBuf = _TIFFmalloc(TIFFScanlineSize(pOut));

   //determine if we should mask out the background pixels
   //loop through the image and convert to tiff and write to the file
   int x;
   int y;
   for (y = 0; y < img.height(); y++) 
   {
      uint8* pp = static_cast<uint8*>(pBuf);

      QRgb* pData = reinterpret_cast<QRgb*>(img.scanLine(y));
      for (x = 0; x < img.width(); x++) 
      {
         pp[0] = qRed(pData[x]);
         pp[1] = qGreen(pData[x]);
         pp[2] = qBlue(pData[x]);
         if (saveBackgroundAsTransparent)
         {
            pp[3] = qAlpha(pData[x]);
         }

         pp += samplesPerPixel;
      }

      //write out 1 row and check for error
      if (TIFFWriteScanline(pOut, pBuf, y, 0) < 0)
      {
         //error message
         return false;
      }
   }

   // Add in the geo info if it is available
   addGeoKeys(pOut, img.width(), img.height(), pItem);

   XTIFFClose(pOut);
   return true;
}
Exemple #13
0
static int
InstallGeoTIFF(const char *geofile, const char *tiffile)
{
    TIFF *tif = (TIFF*)0; /* TIFF-level descriptor */
    GTIF *gtif=(GTIF*)0; /* GeoKey-level descriptor */
    FILE *fp;

    uint16 *panVI = NULL;
    uint16 nKeyCount;
     
    tif = XTIFFOpen(tiffile, "r+");
    if (!tif)
    {
        perror(tiffile);
        fprintf(stderr, "Cannot open TIFF file %s (does not exist or not a valid TIFF file)\n", tiffile);
        return(-1);
    }

    /* If we have existing geokeys, try to wipe them
    by writing a dummy geokey directory. (#2546) */


    if( TIFFGetField( tif, TIFFTAG_GEOKEYDIRECTORY, 
                      &nKeyCount, &panVI ) )
    {
        uint16 anGKVersionInfo[4] = { 1, 1, 0, 0 };
        double  adfDummyDoubleParams[1] = { 0.0 };

        TIFFSetField( tif, TIFFTAG_GEOKEYDIRECTORY, 
                      4, anGKVersionInfo );
        TIFFSetField( tif, TIFFTAG_GEODOUBLEPARAMS, 
                      1, adfDummyDoubleParams );
        TIFFSetField( tif, TIFFTAG_GEOASCIIPARAMS, "" );
    }

    gtif = GTIFNew(tif);
    if (!gtif)
    {
        fprintf(stderr, "Internal error (GTIFNew)\n");
        return(-2);
    }
 
    /* Read GeoTIFF projection information from geofile */
    fp = fopen(geofile, "r");
    if( fp == NULL )
    {
        perror( geofile );
        fprintf(stderr, "Cannot open projection definition file %s\n", geofile);
        return(-3);
    }
    if (!GTIFImport(gtif, 0, fp))
    {
        fprintf(stderr,"Projection definition file is not valid (%s)\n", geofile);
        return(-4);
    }
    fclose(fp);
 
    /* Install GeoTIFF keys into the TIFF file */
    GTIFWriteKeys(gtif);
 
    /* Clean up */
    GTIFFree(gtif);
    TIFFRewriteDirectory(tif);
    XTIFFClose(tif);
    return(0);
}
Exemple #14
0
bool DEM::readDem(char* fname) 
{

    demFilename = fname;
    TIFF 	*tif=(TIFF*)0;  /* TIFF-level descriptor */
    GTIF	*gtif=(GTIF*)0; /* GeoKey-level descriptor */
    int	proj4_print_flag = 0;
    int	inv_flag = 0, dec_flag = 1;
    int      st_test_flag = 0;
    GTIFDefn	defn;

    /*
     * Open the file, read the GeoTIFF information, and print some info to stdout. 
     */
	
    tif=XTIFFOpen(fname,"r");
    if (!tif) goto failure;
    
    gtif = GTIFNew(tif);
    if (!gtif)
	{
		fprintf(stderr,"failed in GTIFNew\n");
		goto failure;
	}
	
    /* dump the GeoTIFF metadata to std out */
	
    GTIFPrint(gtif,0,0);
	
    if( GTIFGetDefn( gtif, &defn ) )
	{
		printf( "\n" );
		GTIFPrintDefn( &defn, stdout );
		
		if( proj4_print_flag )
		{
			printf( "\n" );
			printf( "PROJ.4 Definition: %s\n", GTIFGetProj4Defn(&defn));
		}
		int count, orient;
		double* data;
		TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &xsize );
		TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &ysize );
		TIFFGetField( tif, TIFFTAG_GEOPIXELSCALE, &count, &data);
		TIFFGetField( tif, TIFFTAG_ORIENTATION, &orient );
		printf("Orientation:%d\n",orient);
		
		GTIFPrintCorners( gtif, &defn, stdout, xsize, ysize, inv_flag, dec_flag );
		double originx = 0.0;
		double originy = ysize;
		GTIFImageToPCS( gtif, &originx, &originy);
		refLat = originy;
		refLon = originx;
		npixels = xsize * ysize;
		int16* buf;
		tsample_t sample;
		int nbytes;
		nbytes = TIFFScanlineSize(tif);
		buf = (int16*) _TIFFmalloc(nbytes);
		elevations = (int16*) _TIFFmalloc(npixels * sizeof (int16));
		if (elevations != NULL) {
			for(unsigned int y = 0; y < ysize; y++ )
			{
				uint32 row = ysize - 1 - y;
				TIFFReadScanline(tif, buf, row, sample);
				for(unsigned int x = 0; x < xsize; x++ ) 
				{
					elevations[y*xsize + x] = buf[x];
				}
			}	    
			_TIFFfree(buf);
		}
		_TIFFfree(elevations);
		
	}
    

    GTIFFree(gtif);
    if( st_test_flag )
        ST_Destroy( (ST_TIFF *) tif );
    else
        XTIFFClose(tif);
    GTIFDeaccessCSV();
    return true;
	
failure:
    fprintf(stderr,"failure in listgeo\n");
    if (tif) XTIFFClose(tif);
    if (gtif) GTIFFree(gtif);
    GTIFDeaccessCSV();
    return false;
}
void import_radarsat2(const char *inBaseName, radiometry_t radiometry,
		      const char *outBaseName, int ampOnly)
{
  FILE *fp;
  radarsat2_meta *radarsat2;
  meta_parameters *meta;
  char **inDataNames=NULL, inDataName[1024], *inMetaName=NULL;
  char *outDataName=NULL, str[512];
  float *amp = NULL, *phase = NULL, *tmp = NULL, re, im;
  int band, sample;

  // Check radiometry
  if (radiometry != r_AMP) {
    asfPrintWarning("Radiometry other than AMPLITUDE is currently not "
		    "supported.\n");
    radiometry = r_AMP;
  }
  
  if (!fileExists(inBaseName))
    inMetaName = appendExt(inBaseName, ".xml");
  else {
    inMetaName = (char *) MALLOC(sizeof(char)*1024);
    strcpy(inMetaName, inBaseName);
  }
  outDataName = appendExt(outBaseName, ".img");

  radarsat2 = read_radarsat2_meta(inMetaName);
  asfPrintStatus("   DataType: %s, ProductType: %s\n",
		 radarsat2->dataType, radarsat2->productType);
  if (strcmp_case(radarsat2->dataType, "COMPLEX") != 0)
    asfPrintError("Currently only complex data supported!\n");
  meta = radarsat2meta(radarsat2);
  meta_write(meta, outDataName);

  // Let's check the GeoTIFF data.
  // Unfortunately, there is no identifier in the GeoTIFF that would identify
  // the data as Radarsat-2 data.
  //
  // The only thing that we can actually do is to look whether the data in the
  // GeoTIFF file fit the general bill. We can the image dimensions. The data
  // needs to have 2 bands (I and Q) and 16 bit. The citation geokey needs to
  // be the really non-descriptive "Uncorrected Satellite Data".

  TIFF *tiff = NULL;
  GTIF *gtif = NULL;
  data_type_t data_type;
  short sample_format, bits_per_sample, planar_config;
  short num_bands;
  int is_scanline_format, is_palette_color_tiff, wrong=FALSE;
  char *error_message = (char *) MALLOC(sizeof(char)*2048);

  inDataNames = extract_band_names(meta->general->basename, 
				   meta->general->band_count);
  fp = FOPEN(outDataName, "wb");

  int band_count = radarsat2->band_count;
  if (ampOnly) {
    strcpy(meta->general->bands, "AMP");
    meta->general->band_count = 1;
    band_count = 1;
  }
  for (band=0; band<band_count; band++) {

    // path from the xml (metadata) file
    char *path = get_dirname(inBaseName);
    if (strlen(path)>0) {
      strcpy(inDataName, path);
      if (inDataName[strlen(inDataName)-1] != '/')
        strcat(inDataName, "/");
    }
    else
      strcpy(inDataName, "");
    free(path);
    strcat(inDataName, inDataNames[band]);

    tiff = XTIFFOpen(inDataName, "r");
    if (!tiff)
      asfPrintError("Could not open data file (%s)\n", inDataName);
    gtif = GTIFNew(tiff);
    if (!gtif)
      asfPrintError("Could not read GeoTIFF keys from data file (%s)\n",
		    inDataName);

    // Check image dimensions
    uint32 tif_sample_count;
    uint32 tif_line_count;

    TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &tif_line_count);
    TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &tif_sample_count);
    if ((meta->general->sample_count != tif_sample_count) ||
	(meta->general->line_count != tif_line_count))
      asfPrintError(error_message, 
		    "Problem with image dimensions. Was looking for %d lines "
		    "and %d samples.\nFound %ld lines and %ld samples instead!"
		    "\n", 
		    meta->general->line_count, meta->general->sample_count, 
		    tif_line_count, tif_sample_count);

    // Check general TIFF tags
    get_tiff_data_config(tiff, &sample_format, &bits_per_sample, &planar_config,
			 &data_type, &num_bands, &is_scanline_format, 
			 &is_palette_color_tiff, REPORT_LEVEL_WARNING);

    // The specs say the data is supposed to be unsigned but it is not.
    // Let is pass as long as we are talking about integer data here
    strcpy(error_message, "");
    if (sample_format != SAMPLEFORMAT_UINT && 
	sample_format != SAMPLEFORMAT_INT) {
      strcat(error_message, 
	     "Problem with sampling format. Was looking for integer, ");
      if (sample_format == SAMPLEFORMAT_COMPLEXIEEEFP)
	strcat(error_message, "found complex floating point instead!\n");
      else if (sample_format == SAMPLEFORMAT_COMPLEXINT)
	strcat(error_message, "found complex integer instead!\n");
      else if (sample_format == SAMPLEFORMAT_IEEEFP)
	strcat(error_message, "found floating point instead!\n");
      else if (sample_format == SAMPLEFORMAT_VOID)
	strcat(error_message, "found void instead!\n");
      wrong = TRUE;
    }
    if (bits_per_sample != 16) {
      sprintf(str, "Problem with bits per sample. Was looking for 16, found %d "
	      "instead!\n", bits_per_sample);
      strcat(error_message, str);
      wrong = TRUE;
    }
    if (data_type != INTEGER16) {
      strcat(error_message, "Problem with data type. Was looking INTEGER16, ");
      if (data_type == ASF_BYTE)
	strcat(error_message, "found BYTE instead!\n");
      else if (data_type == INTEGER32)
	strcat(error_message, "found INTEGER32 instead!\n");
      else if (data_type == REAL32)
	strcat(error_message, "found REAL32 instead!\n");
      else if (data_type == REAL64)
	strcat(error_message, "found REAL64 instead!\n");
      else if (data_type == COMPLEX_BYTE)
	strcat(error_message, "found COMPLEX_BYTE instead!\n");
      else if (data_type == COMPLEX_INTEGER16)
	strcat(error_message, "found COMPLEX_INTEGER16 instead!\n");
      else if (data_type == COMPLEX_INTEGER32)
	strcat(error_message, "found COMPLEX_INTEGER32 instead!\n");
      else if (data_type == COMPLEX_REAL32)
	strcat(error_message, "found COMPLEX_REAL32 instead!\n");
      else if (data_type == COMPLEX_REAL64)
	strcat(error_message, "found COMPLEX_REAL64 instead!\n");
      wrong = TRUE;
    }
    if (num_bands != 2) {
      sprintf(str, "Problem with number of bands. Was looking for 2, "
	      "found %d instead!\n", num_bands);
      strcat(error_message, str);
      wrong = TRUE;
    }
    if (wrong)
      asfPrintError(error_message);

    // Check GTCitationGeoKey
    char *citation = NULL;
    int citation_length, typeSize;
    tagtype_t citation_type;

    citation_length = GTIFKeyInfo(gtif, GTCitationGeoKey, &typeSize,
				  &citation_type);
    if (citation_length > 0) {
      citation = (char *) MALLOC(citation_length * typeSize);
      GTIFKeyGet(gtif, GTCitationGeoKey, citation, 0, citation_length);
      if (citation && 
	  strcmp_case(citation, "UNCORRECTED SATELLITE DATA") != 0) {
	asfPrintError("Problem with GTCitationGeoKey. Was looking for "
		      "'Uncorrected Satellite Data',\nfound '%s' instead!\n", 
		      citation);
      }
    }
    else
      asfPrintError("Problem with GTCitationGeoKey. Was looking for "
		    "'Uncorrected Satellite Data',\ndid not find any key!\n");

    tiff_type_t tiffInfo;
    get_tiff_type(tiff, &tiffInfo);
    if (tiffInfo.format != SCANLINE_TIFF &&
	tiffInfo.format != STRIP_TIFF    &&
	tiffInfo.format != TILED_TIFF)
      asfPrintError("Can't read the GeoTIFF file (%s). Unrecognized TIFF "
		    "type!\n", inDataNames[band]);

    // If we made it here, we are reasonably sure that we have the file that
    // we are looking for.
    asfPrintStatus("\n   Importing %s ...\n", inDataNames[band]);

    uint32 scanlineSize = TIFFScanlineSize(tiff);
    tdata_t *tiff_real_buf = _TIFFmalloc(scanlineSize);
    tdata_t *tiff_imag_buf = _TIFFmalloc(scanlineSize);
    if (!tiff_real_buf || !tiff_imag_buf)
      asfPrintError("Can't allocate buffer for reading TIFF lines!\n");

    amp = (float *) MALLOC(sizeof(float)*meta->general->sample_count);
    phase = (float *) MALLOC(sizeof(float)*meta->general->sample_count);

    // Check whether we need to flip the image in any fashion
    int flip_vertical = FALSE;
    if (strcmp_case(radarsat2->lineTimeOrdering, "DECREASING") == 0) {
      asfPrintStatus("   Data will be flipped vertically while ingesting!\n");
      flip_vertical = TRUE;
    }
    int flip_horizontal = FALSE;
    if (strcmp_case(radarsat2->pixelTimeOrdering, "DECREASING") == 0) {
      asfPrintStatus("   Data will be flipped horizontally while ingesting!\n");
      flip_horizontal = TRUE;
    }
    if (flip_horizontal)
      tmp = (float *) MALLOC(sizeof(float)*meta->general->sample_count);

    // FIXME: still need to implement flipping vertically
    // Read file line by line
    uint32 row;
    int sample_count = meta->general->sample_count;
    int line_count = meta->general->line_count;
    for (row=0; row<(uint32)meta->general->line_count; row++) {
      asfLineMeter(row, meta->general->line_count);
      if (flip_vertical) {
	switch (tiffInfo.format) 
	  {
	  case SCANLINE_TIFF:
	    TIFFReadScanline(tiff, tiff_real_buf, line_count-row-1, 0);
	    TIFFReadScanline(tiff, tiff_imag_buf, line_count-row-1, 1);
	    break;
	  case STRIP_TIFF:
	    ReadScanline_from_TIFF_Strip(tiff, tiff_real_buf, 
					 line_count-row-1, 0);
	    ReadScanline_from_TIFF_Strip(tiff, tiff_imag_buf, 
					 line_count-row-1, 1);
	    break;
	  case TILED_TIFF:
	    ReadScanline_from_TIFF_TileRow(tiff, tiff_real_buf, 
					   line_count-row-1, 0);
	    ReadScanline_from_TIFF_TileRow(tiff, tiff_imag_buf, 
					   line_count-row-1, 1);
	    break;
	  default:
	    asfPrintError("Can't read this TIFF format!\n");
	    break;
	  }
      }
      else {
	switch (tiffInfo.format) 
	  {
	  case SCANLINE_TIFF:
	    TIFFReadScanline(tiff, tiff_real_buf, row, 0);
	    TIFFReadScanline(tiff, tiff_imag_buf, row, 1);
	    break;
	  case STRIP_TIFF:
	    ReadScanline_from_TIFF_Strip(tiff, tiff_real_buf, row, 0);
	    ReadScanline_from_TIFF_Strip(tiff, tiff_imag_buf, row, 1);
	    break;
	  case TILED_TIFF:
	    ReadScanline_from_TIFF_TileRow(tiff, tiff_real_buf, row, 0);
	    ReadScanline_from_TIFF_TileRow(tiff, tiff_imag_buf, row, 1);
	    break;
	  default:
	    asfPrintError("Can't read this TIFF format!\n");
	    break;
	  }
      }
      for (sample=0; sample<sample_count; sample++) {
	switch (sample_format)
	  {
	  case SAMPLEFORMAT_UINT:
	    re = (float)(((uint16*)tiff_real_buf)[sample]);
	    im = (float)(((uint16*)tiff_imag_buf)[sample]);
	    break;
	  case SAMPLEFORMAT_INT:
	    re = (float)(((int16*)tiff_real_buf)[sample]);
	    im = (float)(((int16*)tiff_imag_buf)[sample]);
	    break;
	  }
	amp[sample] = sqrt(re*re + im*im);
	phase[sample] = atan2(im, re);
      }
      if (flip_horizontal) {
	for (sample=0; sample<sample_count; sample++)
	  tmp[sample] = amp[sample];
	for (sample=0; sample<sample_count; sample++)
	  amp[sample] = tmp[sample_count-sample-1];
      }
	  
      put_band_float_line(fp, meta, band*2, (int)row, amp);
      if (!ampOnly)
	put_band_float_line(fp, meta, band*2+1, (int)row, phase);
    }
      
    FREE(amp);
    FREE(phase);
    if (tmp)
      FREE(tmp);
    _TIFFfree(tiff_real_buf);
    _TIFFfree(tiff_imag_buf);
    GTIFFree(gtif);
    XTIFFClose(tiff);
  }

  // update the name field with directory name
  char *path = get_dirname(inBaseName);
  if (strlen(path)<=0)
    path = g_get_current_dir();
  char *p = path, *q = path;
  while (q) {
    if ((q = strchr(p, DIR_SEPARATOR)) != NULL)
      p = q+1;
  }
  sprintf(meta->general->basename, "%s", p);
  FREE(path);
  meta_write(meta, outDataName);

  meta_free(meta);
  FREE(radarsat2);
  FCLOSE(fp);
}