GDALDataset *ERSDataset::Open( GDALOpenInfo * poOpenInfo ) { /* -------------------------------------------------------------------- */ /* We assume the user selects the .ers file. */ /* -------------------------------------------------------------------- */ if( poOpenInfo->nHeaderBytes > 15 && EQUALN((const char *) poOpenInfo->pabyHeader,"Algorithm Begin",15) ) { CPLError( CE_Failure, CPLE_OpenFailed, "%s appears to be an algorithm ERS file, which is not currently supported.", poOpenInfo->pszFilename ); return NULL; } /* -------------------------------------------------------------------- */ /* We assume the user selects the .ers file. */ /* -------------------------------------------------------------------- */ if( poOpenInfo->nHeaderBytes < 15 || !EQUALN((const char *) poOpenInfo->pabyHeader,"DatasetHeader ",14) ) return NULL; /* -------------------------------------------------------------------- */ /* Open the .ers file, and read the first line. */ /* -------------------------------------------------------------------- */ VSILFILE *fpERS = VSIFOpenL( poOpenInfo->pszFilename, "rb" ); if( fpERS == NULL ) return NULL; CPLReadLineL( fpERS ); /* -------------------------------------------------------------------- */ /* Now ingest the rest of the file as a tree of header nodes. */ /* -------------------------------------------------------------------- */ ERSHdrNode *poHeader = new ERSHdrNode(); if( !poHeader->ParseChildren( fpERS ) ) { delete poHeader; VSIFCloseL( fpERS ); return NULL; } VSIFCloseL( fpERS ); /* -------------------------------------------------------------------- */ /* Do we have the minimum required information from this header? */ /* -------------------------------------------------------------------- */ if( poHeader->Find( "RasterInfo.NrOfLines" ) == NULL || poHeader->Find( "RasterInfo.NrOfCellsPerLine" ) == NULL || poHeader->Find( "RasterInfo.NrOfBands" ) == NULL ) { if( poHeader->FindNode( "Algorithm" ) != NULL ) { CPLError( CE_Failure, CPLE_OpenFailed, "%s appears to be an algorithm ERS file, which is not currently supported.", poOpenInfo->pszFilename ); } delete poHeader; return NULL; } /* -------------------------------------------------------------------- */ /* Create a corresponding GDALDataset. */ /* -------------------------------------------------------------------- */ ERSDataset *poDS; poDS = new ERSDataset(); poDS->poHeader = poHeader; poDS->eAccess = poOpenInfo->eAccess; /* -------------------------------------------------------------------- */ /* Capture some information from the file that is of interest. */ /* -------------------------------------------------------------------- */ int nBands = atoi(poHeader->Find( "RasterInfo.NrOfBands" )); poDS->nRasterXSize = atoi(poHeader->Find( "RasterInfo.NrOfCellsPerLine" )); poDS->nRasterYSize = atoi(poHeader->Find( "RasterInfo.NrOfLines" )); if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) || !GDALCheckBandCount(nBands, FALSE)) { delete poDS; return NULL; } /* -------------------------------------------------------------------- */ /* Get the HeaderOffset if it exists in the header */ /* -------------------------------------------------------------------- */ GIntBig nHeaderOffset = 0; if( poHeader->Find( "HeaderOffset" ) != NULL ) { nHeaderOffset = atoi(poHeader->Find( "HeaderOffset" )); } /* -------------------------------------------------------------------- */ /* Establish the data type. */ /* -------------------------------------------------------------------- */ GDALDataType eType; CPLString osCellType = poHeader->Find( "RasterInfo.CellType", "Unsigned8BitInteger" ); if( EQUAL(osCellType,"Unsigned8BitInteger") ) eType = GDT_Byte; else if( EQUAL(osCellType,"Signed8BitInteger") ) eType = GDT_Byte; else if( EQUAL(osCellType,"Unsigned16BitInteger") ) eType = GDT_UInt16; else if( EQUAL(osCellType,"Signed16BitInteger") ) eType = GDT_Int16; else if( EQUAL(osCellType,"Unsigned32BitInteger") ) eType = GDT_UInt32; else if( EQUAL(osCellType,"Signed32BitInteger") ) eType = GDT_Int32; else if( EQUAL(osCellType,"IEEE4ByteReal") ) eType = GDT_Float32; else if( EQUAL(osCellType,"IEEE8ByteReal") ) eType = GDT_Float64; else { CPLDebug( "ERS", "Unknown CellType '%s'", osCellType.c_str() ); eType = GDT_Byte; } /* -------------------------------------------------------------------- */ /* Pick up the word order. */ /* -------------------------------------------------------------------- */ int bNative; #ifdef CPL_LSB bNative = EQUAL(poHeader->Find( "ByteOrder", "LSBFirst" ), "LSBFirst"); #else bNative = EQUAL(poHeader->Find( "ByteOrder", "MSBFirst" ), "MSBFirst"); #endif /* -------------------------------------------------------------------- */ /* Figure out the name of the target file. */ /* -------------------------------------------------------------------- */ CPLString osPath = CPLGetPath( poOpenInfo->pszFilename ); CPLString osDataFile = poHeader->Find( "DataFile", "" ); CPLString osDataFilePath; if( osDataFile.length() == 0 ) // just strip off extension. { osDataFile = CPLGetFilename( poOpenInfo->pszFilename ); osDataFile = osDataFile.substr( 0, osDataFile.find_last_of('.') ); } osDataFilePath = CPLFormFilename( osPath, osDataFile, NULL ); /* -------------------------------------------------------------------- */ /* DataSetType = Translated files are links to things like ecw */ /* files. */ /* -------------------------------------------------------------------- */ if( EQUAL(poHeader->Find("DataSetType",""),"Translated") ) { poDS->poDepFile = (GDALDataset *) GDALOpenShared( osDataFilePath, poOpenInfo->eAccess ); if( poDS->poDepFile != NULL && poDS->poDepFile->GetRasterCount() >= nBands ) { int iBand; for( iBand = 0; iBand < nBands; iBand++ ) { // Assume pixel interleaved. poDS->SetBand( iBand+1, poDS->poDepFile->GetRasterBand( iBand+1 ) ); } } } /* ==================================================================== */ /* While ERStorage indicates a raw file. */ /* ==================================================================== */ else if( EQUAL(poHeader->Find("DataSetType",""),"ERStorage") ) { // Open data file. if( poOpenInfo->eAccess == GA_Update ) poDS->fpImage = VSIFOpenL( osDataFilePath, "r+" ); else poDS->fpImage = VSIFOpenL( osDataFilePath, "r" ); poDS->osRawFilename = osDataFilePath; if( poDS->fpImage != NULL ) { int iWordSize = GDALGetDataTypeSize(eType) / 8; int iBand; for( iBand = 0; iBand < nBands; iBand++ ) { // Assume pixel interleaved. poDS->SetBand( iBand+1, new RawRasterBand( poDS, iBand+1, poDS->fpImage, nHeaderOffset + iWordSize * iBand * poDS->nRasterXSize, iWordSize, iWordSize * nBands * poDS->nRasterXSize, eType, bNative, TRUE )); if( EQUAL(osCellType,"Signed8BitInteger") ) poDS->GetRasterBand(iBand+1)-> SetMetadataItem( "PIXELTYPE", "SIGNEDBYTE", "IMAGE_STRUCTURE" ); } } } /* -------------------------------------------------------------------- */ /* Otherwise we have an error! */ /* -------------------------------------------------------------------- */ if( poDS->nBands == 0 ) { delete poDS; return NULL; } /* -------------------------------------------------------------------- */ /* Look for band descriptions. */ /* -------------------------------------------------------------------- */ int iChild, iBand = 0; ERSHdrNode *poRI = poHeader->FindNode( "RasterInfo" ); for( iChild = 0; poRI != NULL && iChild < poRI->nItemCount && iBand < poDS->nBands; iChild++ ) { if( poRI->papoItemChild[iChild] != NULL && EQUAL(poRI->papszItemName[iChild],"BandId") ) { const char *pszValue = poRI->papoItemChild[iChild]->Find( "Value", NULL ); iBand++; if( pszValue ) { CPLPushErrorHandler( CPLQuietErrorHandler ); poDS->GetRasterBand( iBand )->SetDescription( pszValue ); CPLPopErrorHandler(); } pszValue = poRI->papoItemChild[iChild]->Find( "Units", NULL ); if ( pszValue ) { CPLPushErrorHandler( CPLQuietErrorHandler ); poDS->GetRasterBand( iBand )->SetUnitType( pszValue ); CPLPopErrorHandler(); } } } /* -------------------------------------------------------------------- */ /* Look for projection. */ /* -------------------------------------------------------------------- */ OGRSpatialReference oSRS; CPLString osProjection = poHeader->Find( "CoordinateSpace.Projection", "RAW" ); CPLString osDatum = poHeader->Find( "CoordinateSpace.Datum", "WGS84" ); CPLString osUnits = poHeader->Find( "CoordinateSpace.Units", "METERS" ); oSRS.importFromERM( osProjection, osDatum, osUnits ); CPLFree( poDS->pszProjection ); oSRS.exportToWkt( &(poDS->pszProjection) ); /* -------------------------------------------------------------------- */ /* Look for the geotransform. */ /* -------------------------------------------------------------------- */ if( poHeader->Find( "RasterInfo.RegistrationCoord.Eastings", NULL ) && poHeader->Find( "RasterInfo.CellInfo.Xdimension", NULL ) ) { poDS->bGotTransform = TRUE; poDS->adfGeoTransform[0] = CPLAtof( poHeader->Find( "RasterInfo.RegistrationCoord.Eastings", "" )); poDS->adfGeoTransform[1] = CPLAtof( poHeader->Find( "RasterInfo.CellInfo.Xdimension", "" )); poDS->adfGeoTransform[2] = 0.0; poDS->adfGeoTransform[3] = CPLAtof( poHeader->Find( "RasterInfo.RegistrationCoord.Northings", "" )); poDS->adfGeoTransform[4] = 0.0; poDS->adfGeoTransform[5] = -CPLAtof( poHeader->Find( "RasterInfo.CellInfo.Ydimension", "" )); } else if( poHeader->Find( "RasterInfo.RegistrationCoord.Latitude", NULL ) && poHeader->Find( "RasterInfo.CellInfo.Xdimension", NULL ) ) { poDS->bGotTransform = TRUE; poDS->adfGeoTransform[0] = ERSDMS2Dec( poHeader->Find( "RasterInfo.RegistrationCoord.Longitude", "" )); poDS->adfGeoTransform[1] = CPLAtof( poHeader->Find( "RasterInfo.CellInfo.Xdimension", "" )); poDS->adfGeoTransform[2] = 0.0; poDS->adfGeoTransform[3] = ERSDMS2Dec( poHeader->Find( "RasterInfo.RegistrationCoord.Latitude", "" )); poDS->adfGeoTransform[4] = 0.0; poDS->adfGeoTransform[5] = -CPLAtof( poHeader->Find( "RasterInfo.CellInfo.Ydimension", "" )); } /* -------------------------------------------------------------------- */ /* Adjust if we have a registration cell. */ /* -------------------------------------------------------------------- */ int iCellX = atoi(poHeader->Find("RasterInfo.RegistrationCellX", "1")); int iCellY = atoi(poHeader->Find("RasterInfo.RegistrationCellY", "1")); if( poDS->bGotTransform ) { poDS->adfGeoTransform[0] -= (iCellX-1) * poDS->adfGeoTransform[1] + (iCellY-1) * poDS->adfGeoTransform[2]; poDS->adfGeoTransform[3] -= (iCellX-1) * poDS->adfGeoTransform[4] + (iCellY-1) * poDS->adfGeoTransform[5]; } /* -------------------------------------------------------------------- */ /* Check for null values. */ /* -------------------------------------------------------------------- */ if( poHeader->Find( "RasterInfo.NullCellValue", NULL ) ) { CPLPushErrorHandler( CPLQuietErrorHandler ); for( iBand = 1; iBand <= poDS->nBands; iBand++ ) poDS->GetRasterBand(iBand)->SetNoDataValue( CPLAtofM(poHeader->Find( "RasterInfo.NullCellValue" )) ); CPLPopErrorHandler(); } /* -------------------------------------------------------------------- */ /* Do we have an "All" region? */ /* -------------------------------------------------------------------- */ ERSHdrNode *poAll = NULL; for( iChild = 0; poRI != NULL && iChild < poRI->nItemCount; iChild++ ) { if( poRI->papoItemChild[iChild] != NULL && EQUAL(poRI->papszItemName[iChild],"RegionInfo") ) { if( EQUAL(poRI->papoItemChild[iChild]->Find("RegionName",""), "All") ) poAll = poRI->papoItemChild[iChild]; } } /* -------------------------------------------------------------------- */ /* Do we have statistics? */ /* -------------------------------------------------------------------- */ if( poAll && poAll->FindNode( "Stats" ) ) { CPLPushErrorHandler( CPLQuietErrorHandler ); for( iBand = 1; iBand <= poDS->nBands; iBand++ ) { const char *pszValue = poAll->FindElem( "Stats.MinimumValue", iBand-1 ); if( pszValue ) poDS->GetRasterBand(iBand)->SetMetadataItem( "STATISTICS_MINIMUM", pszValue ); pszValue = poAll->FindElem( "Stats.MaximumValue", iBand-1 ); if( pszValue ) poDS->GetRasterBand(iBand)->SetMetadataItem( "STATISTICS_MAXIMUM", pszValue ); pszValue = poAll->FindElem( "Stats.MeanValue", iBand-1 ); if( pszValue ) poDS->GetRasterBand(iBand)->SetMetadataItem( "STATISTICS_MEAN", pszValue ); pszValue = poAll->FindElem( "Stats.MedianValue", iBand-1 ); if( pszValue ) poDS->GetRasterBand(iBand)->SetMetadataItem( "STATISTICS_MEDIAN", pszValue ); } CPLPopErrorHandler(); } /* -------------------------------------------------------------------- */ /* Do we have GCPs. */ /* -------------------------------------------------------------------- */ if( poHeader->FindNode( "RasterInfo.WarpControl" ) ) poDS->ReadGCPs(); /* -------------------------------------------------------------------- */ /* Initialize any PAM information. */ /* -------------------------------------------------------------------- */ poDS->SetDescription( poOpenInfo->pszFilename ); poDS->TryLoadXML(); // if no SR in xml, try aux const char* pszPrj = poDS->GDALPamDataset::GetProjectionRef(); if( !pszPrj || strlen(pszPrj) == 0 ) { // try aux GDALDataset* poAuxDS = GDALFindAssociatedAuxFile( poOpenInfo->pszFilename, GA_ReadOnly, poDS ); if( poAuxDS ) { pszPrj = poAuxDS->GetProjectionRef(); if( pszPrj && strlen(pszPrj) > 0 ) { CPLFree( poDS->pszProjection ); poDS->pszProjection = CPLStrdup(pszPrj); } GDALClose( poAuxDS ); } } /* -------------------------------------------------------------------- */ /* Check for overviews. */ /* -------------------------------------------------------------------- */ poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename ); return( poDS ); }
void ERSDataset::ReadGCPs() { const char *pszCP = poHeader->Find( "RasterInfo.WarpControl.ControlPoints", NULL ); if( pszCP == NULL ) return; /* -------------------------------------------------------------------- */ /* Parse the control points. They will look something like: */ /* */ /* "1035" Yes No 2344.650885 3546.419458 483270.73 3620906.21 3.105 */ /* -------------------------------------------------------------------- */ char **papszTokens = CSLTokenizeStringComplex( pszCP, "{ \t}", TRUE,FALSE); int nItemsPerLine; int nItemCount = CSLCount(papszTokens); /* -------------------------------------------------------------------- */ /* Work out if we have elevation values or not. */ /* -------------------------------------------------------------------- */ if( nItemCount == 7 ) nItemsPerLine = 7; else if( nItemCount == 8 ) nItemsPerLine = 8; else if( nItemCount < 14 ) { CPLAssert( FALSE ); return; } else if( EQUAL(papszTokens[8],"Yes") || EQUAL(papszTokens[8],"No") ) nItemsPerLine = 7; else if( EQUAL(papszTokens[9],"Yes") || EQUAL(papszTokens[9],"No") ) nItemsPerLine = 8; else { CPLAssert( FALSE ); return; } /* -------------------------------------------------------------------- */ /* Setup GCPs. */ /* -------------------------------------------------------------------- */ int iGCP; CPLAssert( nGCPCount == 0 ); nGCPCount = nItemCount / nItemsPerLine; pasGCPList = (GDAL_GCP *) CPLCalloc(nGCPCount,sizeof(GDAL_GCP)); GDALInitGCPs( nGCPCount, pasGCPList ); for( iGCP = 0; iGCP < nGCPCount; iGCP++ ) { GDAL_GCP *psGCP = pasGCPList + iGCP; CPLFree( psGCP->pszId ); psGCP->pszId = CPLStrdup(papszTokens[iGCP*nItemsPerLine+0]); psGCP->dfGCPPixel = atof(papszTokens[iGCP*nItemsPerLine+3]); psGCP->dfGCPLine = atof(papszTokens[iGCP*nItemsPerLine+4]); psGCP->dfGCPX = atof(papszTokens[iGCP*nItemsPerLine+5]); psGCP->dfGCPY = atof(papszTokens[iGCP*nItemsPerLine+6]); if( nItemsPerLine == 8 ) psGCP->dfGCPZ = atof(papszTokens[iGCP*nItemsPerLine+7]); } CSLDestroy( papszTokens ); /* -------------------------------------------------------------------- */ /* Parse the GCP projection. */ /* -------------------------------------------------------------------- */ OGRSpatialReference oSRS; CPLString osProjection = poHeader->Find( "RasterInfo.WarpControl.CoordinateSpace.Projection", "RAW" ); CPLString osDatum = poHeader->Find( "RasterInfo.WarpControl.CoordinateSpace.Datum", "WGS84" ); CPLString osUnits = poHeader->Find( "RasterInfo.WarpControl.CoordinateSpace.Units", "METERS" ); oSRS.importFromERM( osProjection, osDatum, osUnits ); CPLFree( pszGCPProjection ); oSRS.exportToWkt( &pszGCPProjection ); }