Как только драйверы зарегистрированы, приложение должно вызвать функцию GDALOpen() для открытия набора данных. В качестве параметров функция принимает название набора данных и режим доступа (GA_ReadOnly или GA_Update).
На языке C++:
#include "gdal_priv.h" int main() { GDALDataset *poDataset; GDALAllRegister(); poDataset = (GDALDataset *) GDALOpen( pszFilename, GA_ReadOnly ); if( poDataset == NULL ) { ...; }
На языке C:
#include "gdal.h" int main() { GDALDatasetH hDataset; GDALAllRegister(); hDataset = GDALOpen( pszFilename, GA_ReadOnly ); if( hDataset == NULL ) { ...; }
На языке Python:
import gdal from gdalconst import * dataset = gdal.Open( filename, GA_ReadOnly ) if dataset is None: ...
Если GDALOpen() возвращает NULL, это означает, что операция не удалась и что сообщения об ошибке были посланы с помощью функции CPLError(). Если вы хотите управлять процессом выдачи пользователю сообщений об ошибках, то обратитесь к документации на функцию CPLError(). Вообще говоря, CPLError() применяется во всех компонентах GDAL для выдачи сообщений об ошибках. Заметим также, что pszFilename не должна обязательно быть именем файла на физическом носителе (хотя обычно это так). Интерпретация этого параметра зависит от драйвера, это может быть URL или имя файла с дополнительными параметрами, управляющими процессом чтения, либо чем-то иным. Пожалуйста, не ограничивайте диалоги выбора набора данных для открытия только лишь файлами на физических носителях.
adfGeoTransform[0] /* координата x верхнего левого угла */ adfGeoTransform[1] /* ширина пиксела */ adfGeoTransform[2] /* поворот, 0, если изображение ориентировано на север */ adfGeoTransform[3] /* координата y верхнего левого угла */ adfGeoTransform[4] /* поворот, 0, если изображение ориентировано на север */ adfGeoTransform[5] /* высота пиксела */
Если мы хотим вывести некоторую общую информацию о наборе данных, то можно сделать следующее:
На языке C++:
double adfGeoTransform[6]; printf( "Драйвер: %s/%s\n", poDataset->GetDriver()->GetDescription(), poDataset->GetDriver()->GetMetadataItem( GDAL_DMD_LONGNAME ) ); printf( "Размер %dx%dx%d\n", poDataset->GetRasterXSize(), poDataset->GetRasterYSize(), poDataset->GetRasterCount() ); if( poDataset->GetProjectionRef() != NULL ) printf( "Проекция \"%s\"\n", poDataset->GetProjectionRef() ); if( poDataset->GetGeoTransform( adfGeoTransform ) == CE_None ) { printf( "Начало координат (%.6f,%.6f)\n", adfGeoTransform[0], adfGeoTransform[3] ); printf( "Размер пиксела (%.6f,%.6f)\n", adfGeoTransform[1], adfGeoTransform[5] ); }
На языке C:
GDALDriverH hDriver; double adfGeoTransform[6]; hDriver = GDALGetDatasetDriver( hDataset ); printf( "Драйвер: %s/%s\n", GDALGetDriverShortName( hDriver ), GDALGetDriverLongName( hDriver ) ); printf( "Размер %dx%dx%d\n", GDALGetRasterXSize( hDataset ), GDALGetRasterYSize( hDataset ), GDALGetRasterCount( hDataset ) ); if( GDALGetProjectionRef( hDataset ) != NULL ) printf( "Проекция \"%s\"\n", GDALGetProjectionRef( hDataset ) ); if( GDALGetGeoTransform( hDataset, adfGeoTransform ) == CE_None ) { printf( "Начало координат (%.6f,%.6f)\n", adfGeoTransform[0], adfGeoTransform[3] ); printf( "Размер пиксела (%.6f,%.6f)\n", adfGeoTransform[1], adfGeoTransform[5] ); }
На языке Python:
print 'Драйвер: ', dataset.GetDriver().ShortName,'/', \ dataset.GetDriver().LongName print 'Размер ',dataset.RasterXSize,'x',dataset.RasterYSize, \ 'x',dataset.RasterCount print 'Проекция ',dataset.GetProjection() geotransform = dataset.GetGeoTransform() if not geotransform is None: print 'Начало координат (',geotransform[0], ',',geotransform[3],')' print 'Размер пиксела = (',geotransform[1], ',',geotransform[5],')'
На языке C++:
GDALRasterBand *poBand; int nBlockXSize, nBlockYSize; int bGotMin, bGotMax; double adfMinMax[2]; poBand = poDataset->GetRasterBand( 1 ); poBand->GetBlockSize( &nBlockXSize, &nBlockYSize ); printf( "Размер блока %dx%d, тип данных %s, ColorInterp=%s\n", nBlockXSize, nBlockYSize, GDALGetDataTypeName(poBand->GetRasterDataType()), GDALGetColorInterpretationName( poBand->GetColorInterpretation()) ); adfMinMax[0] = poBand->GetMinimum( &bGotMin ); adfMinMax[1] = poBand->GetMaximum( &bGotMax ); if( ! (bGotMin && bGotMax) ) GDALComputeRasterMinMax((GDALRasterBandH)poBand, TRUE, adfMinMax); printf( "Min=%.3fd, Max=%.3f\n", adfMinMax[0], adfMinMax[1] ); if( poBand->GetOverviewCount() > 0 ) printf( "Канал содержит %d обзорных изображений.\n", poBand->GetOverviewCount() ); if( poBand->GetColorTable() != NULL ) printf( "Канал содержит таблицу цветов с %d записями.\n", poBand->GetColorTable()->GetColorEntryCount() );
In C:
GDALRasterBandH hBand; int nBlockXSize, nBlockYSize; int bGotMin, bGotMax; double adfMinMax[2]; hBand = GDALGetRasterBand( hDataset, 1 ); GDALGetBlockSize( hBand, &nBlockXSize, &nBlockYSize ); printf( "Размер блока %dx%d, тип данных %s, ColorInterp=%s\n", nBlockXSize, nBlockYSize, GDALGetDataTypeName(GDALGetRasterDataType(hBand)), GDALGetColorInterpretationName( GDALGetRasterColorInterpretation(hBand)) ); adfMinMax[0] = GDALGetRasterMinimum( hBand, &bGotMin ); adfMinMax[1] = GDALGetRasterMaximum( hBand, &bGotMax ); if( ! (bGotMin && bGotMax) ) GDALComputeRasterMinMax( hBand, TRUE, adfMinMax ); printf( "Min=%.3fd, Max=%.3f\n", adfMinMax[0], adfMinMax[1] ); if( GDALGetOverviewCount(hBand) > 0 ) printf( "Канал содержит %d обзорных изображений.\n", GDALGetOverviewCount(hBand)); if( GDALGetRasterColorTable( hBand ) != NULL ) printf( "Канал содержит таблицу цветов с %d записями.\n", GDALGetColorEntryCount( GDALGetRasterColorTable( hBand ) ) );
На языке Python:
band = dataset.GetRasterBand(1) print 'Тип данных',gdal.GetDataTypeName(band.DataType) min = band.GetMinimum() max = band.GetMaximum() if min is not None and max is not None: (min,max) = ComputeRasterMinMax(1) print 'Min=%.3f, Max=%.3f' % (min,max) if band.GetOverviewCount() > 0: print 'Канал содержит ', band.GetOverviewCount(), \ ' обзорных изображений.' if not band.GetRasterColorTable() is None: print 'Канал содержит таблицу цветов с ', \ band.GetRasterColorTable().GetCount(), ' записями.'
На языке C++:
float *pafScanline; int nXSize = poBand->GetXSize(); pafScanline = (float *) CPLMalloc(sizeof(float)*nXSize); poBand->RasterIO( GF_Read, 0, 0, nXSize, 1, pafScanline, nXSize, 1, GDT_Float32, 0, 0 );
На языке C:
float *pafScanline; int nXSize = GDALGetRasterBandXSize( hBand ); pafScanline = (float *) CPLMalloc(sizeof(float)*nXSize); GDALRasterIO( hBand, GF_Read, 0, 0, nXSize, 1, pafScanline, nXSize, 1, GDT_Float32, 0, 0 );
На языке Python:
scanline = band.ReadRaster( 0, 0, band.XSize, 1, \ band.XSize, 1, GDT_Float32 )
Здесь возвращаемая строка имеет тип string, и содержит xsize*4 байт вещественных данных. Эта строка может быть преобразована в базовые типы языка Python с помощью модуля struct из стандартной библиотеки:
import struct tuple_of_floats = struct.unpack('f' * b2.XSize, scanline)
Вызов функции The RasterIO производится со следующими аргументами:
CPLErr GDALRasterBand::RasterIO( GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize, void * pData, int nBufXSize, int nBufYSize, GDALDataType eBufType, int nPixelSpace, int nLineSpace )
Заметим, что один и тот же вызов RasterIO() применяется как для чтения, так и для записи, в зависимости от значения флага eRWFlag (GF_Read или GF_Write). Аргументы nXOff, nYOff, nXSize, nYSize описывают окно растра для чтения (или записи). Это окно необязательно должно совпадать с границами смежных блоков, однако считывание может быть более эффективным, если границы совпадают.
pData --- это указатель на буфер в памяти, куда должны быть прочитаны (или откуда записаны) данные. Фактический тип этого буфера должен совпадать с типом, передаваемым в параметре eBufType, например, GDT_Float32 или GDT_Byte. Функция RasterIO() возьмёт на себя преобразование между типом данных буфера и типом данных канала. Обратите внимание, что при преобразовании вещественных данных в целые RasterIO() округляет в меньшую сторону, а если значение выходит за рамки допустимого диапазона, оно преобразуется в ближайшее допустимое значение. Это, например, означает, что при чтении 16-битных данных в буфер типа GDT_Byte все значения, превышающие 255 будут отображены в значение 255, масштабирования данных не произойдёт!
Параметры nBufXSize и nBufYSize задают размер буфера. При загрузке данных в полном разрешении он будет совпадать с размером окна. Однако для загрузки уменьшенного обзорного изображения размер буфера можно установить меньшим, чем размер окна. В этом случае RasterIO() будет использовать подходящие обзорные изображения (пирамиду) для более эффективного ввода/вывода.
Параметры nPixelSpace и nLineSpace обычно равны нулю, что приводит к использованию значений по умолчанию. Однако они могут быть использованы для управления доступом к буферу данных, давая возможность читать в буфер, который уже содержит другие данные, чередуя пиксели или строки.
Способ CreateCopy предполагает вызов функции CreateCopy() с указанием требуемого драйвера выходного формата и передачей исходного набора данных, копия которого должна быть создана. Способ Create предполагает вызов метода Create() с указанием необходимого драйвера, а затем непосредственной записью всех метаданных и изображения соответствующими отдельными вызовами. Все драйверы, которые могут создавать новые файлы, поддерживают метод CreateCopy(), однако не все поддерживают метод Create().
Для того, чтобы определить, какой метод поддерживает конкретный драйвер, можно проверить метаданные DCAP_CREATE и DCAP_CREATECOPY у объекта драйвера. Убедитесь, что функция GDALAllRegister() была вызвана прежде, чем вызывать функцию GetDriverByName(). В следующем примере мы запросим драйвер и проверим, поддерживает ли он методы Create() и/или CreateCopy().
На языке C++:
#include "cpl_string.h" ... const char *pszFormat = "GTiff"; GDALDriver *poDriver; char **papszMetadata; poDriver = GetGDALDriverManager()->GetDriverByName(pszFormat); if( poDriver == NULL ) exit( 1 ); papszMetadata = poDriver->GetMetadata(); if( CSLFetchBoolean( papszMetadata, GDAL_DCAP_CREATE, FALSE ) ) printf( "Драйвер %s поддерживает метод Create().\n", pszFormat ); if( CSLFetchBoolean( papszMetadata, GDAL_DCAP_CREATECOPY, FALSE ) ) printf( "Драйвер %s поддерживает метод CreateCopy().\n", pszFormat );
На языке C:
#include "cpl_string.h" ... const char *pszFormat = "GTiff"; GDALDriverH hDriver = GDALGetDriverByName( pszFormat ); char **papszMetadata; if( hDriver == NULL ) exit( 1 ); papszMetadata = GDALGetMetadata( hDriver, NULL ); if( CSLFetchBoolean( papszMetadata, GDAL_DCAP_CREATE, FALSE ) ) printf( "Драйвер %s поддерживает метод Create().\n", pszFormat ); if( CSLFetchBoolean( papszMetadata, GDAL_DCAP_CREATECOPY, FALSE ) ) printf( "Драйвер %s поддерживает метод CreateCopy().\n", pszFormat );
На языке Python:
format = "GTiff" driver = gdal.GetDriverByName( format ) metadata = driver.GetMetadata() if metadata.has_key(gdal.DCAP_CREATE) \ and metadata[gdal.DCAP_CREATE] == 'YES': print 'Драйвер %s поддерживает метод Create().' % format if metadata.has_key(gdal.DCAP_CREATECOPY) \ and metadata[gdal.DCAP_CREATECOPY] == 'YES': print 'Драйвер %s поддерживает метод CreateCopy().' % format
Заметим, что некоторые драйверы могут только читать данные и не поддерживают ни метод Create(), ни CreateCopy().
На языке C++:
GDALDataset *poSrcDS = (GDALDataset *) GDALOpen( pszSrcFilename, GA_ReadOnly ); GDALDataset *poDstDS; poDstDS = poDriver->CreateCopy( pszDstFilename, poSrcDS, FALSE, NULL, NULL, NULL ); if( poDstDS != NULL ) delete poDstDS;
На языке C:
GDALDatasetH hSrcDS = GDALOpen( pszSrcFilename, GA_ReadOnly );
GDALDatasetH hDstDS;
hDstDS = GDALCreateCopy( hDriver, pszDstFilename, hSrcDS, FALSE,
NULL, NULL, NULL );
if( hDstDS != NULL )
GDALClose( hDstDS );
На языке Python:
src_ds = gdal.Open( src_filename ) dst_ds = driver.CreateCopy( dst_filename, src_ds, 0 )
Заметим, что метод CreateCopy() возвращает набор данных, пригодный для записи и он должен быть соответствующим образом закрыт для завершения записи и сброса данных на диск. В случае языка Python это произойдёт автоматически, когда "dst_ds" выйдет из области видимости. Значение FALSE (или 0), используемое для параметра bStrict, следующего сразу за именем выходного набора данных в вызове CreateCopy(), показывает, что CreateCopy() должен завершиться без фатальной ошибки даже в случае, если создаваемый набор данных не может быть идентичен входному набору. Такое может произойти, например, поскольку выходной формат не поддерживает тип данных входного формата, или потому, что выходной формат не поддерживает географическую привязку.
Более сложный случай может включать указание параметров для создания выходного файла и использование индикатора хода работы:
На языке C++:
#include "cpl_string.h" ... char **papszOptions = NULL; papszOptions = CSLSetNameValue( papszOptions, "TILED", "YES" ); papszOptions = CSLSetNameValue( papszOptions, "COMPRESS", "PACKBITS" ); poDstDS = poDriver->CreateCopy( pszDstFilename, poSrcDS, FALSE, papszOptions, GDALTermProgress, NULL ); if( poDstDS != NULL ) delete poDstDS; CSLDestroy( papszOptions );
На языке C:
#include "cpl_string.h" ... char **papszOptions = NULL; papszOptions = CSLSetNameValue( papszOptions, "TILED", "YES" ); papszOptions = CSLSetNameValue( papszOptions, "COMPRESS", "PACKBITS" ); hDstDS = GDALCreateCopy( hDriver, pszDstFilename, hSrcDS, FALSE, papszOptions, GDALTermProgres, NULL ); if( hDstDS != NULL ) GDALClose( hDstDS ); CSLDestroy( papszOptions );
На языке Python:
src_ds = gdal.Open( src_filename ) dst_ds = driver.CreateCopy( dst_filename, src_ds, 0, [ 'TILED=YES', 'COMPRESS=PACKBITS' ] )
На языке C++:
GDALDataset *poDstDS;
char **papszOptions = NULL;
poDstDS = poDriver->Create( pszDstFilename, 512, 512, 1, GDT_Byte,
papszOptions );
На языке C:
GDALDatasetH hDstDS;
char **papszOptions = NULL;
hDstDS = GDALCreate( hDriver, pszDstFilename, 512, 512, 1, GDT_Byte,
papszOptions );
На языке Python:
dst_ds = driver.Create( dst_filename, 512, 512, 1, gdal.GDT_Byte )
Как только набор данных будет успешно создан, все необходимые метаданные и собственно изображение должны быть записаны в файл. Конкретная реализация очень сильно зависит от задачи, но в простейшем случае, включающем запись проекции, географической привязки и растрового изображения, может выглядеть так:
На языке C++:
double adfGeoTransform[6] = { 444720, 30, 0, 3751320, 0, -30 }; OGRSpatialReference oSRS; char *pszSRS_WKT = NULL; GDALRasterBand *poBand; GByte abyRaster[512*512]; poDstDS->SetGeoTransform( adfGeoTransform ); oSRS.SetUTM( 11, TRUE ); oSRS.SetWellKnownGeogCS( "NAD27" ); oSRS.exportToWkt( &pszSRS_WKT ); poDstDS->SetProjection( pszSRS_WKT ); CPLFree( pszSRS_WKT ); poBand = poDstDS->GetRasterBand(1); poBand->RasterIO( GF_Write, 0, 0, 512, 512, abyRaster, 512, 512, GDT_Byte, 0, 0 ); delete poDstDS;
На языке C:
double adfGeoTransform[6] = { 444720, 30, 0, 3751320, 0, -30 }; OGRSpatialReferenceH hSRS; char *pszSRS_WKT = NULL; GDALRasterBandH hBand; GByte abyRaster[512*512]; GDALSetGeoTransform( hDstDS, adfGeoTransform ); hSRS = OSRNewSpatialReference( NULL ); OSRSetUTM( hSRS, 11, TRUE ); OSRSetWellKnownGeogCS( hSRS, "NAD27" ); OSRExportToWkt( hSRS, &pszSRS_WKT ); OSRDestroySpatialReference( hSRS ); GDALSetProjection( hDstDS, pszSRS_WKT ); CPLFree( pszSRS_WKT ); hBand = GDALGetRasterBand( hDstDS, 1 ); GDALRasterIO( hBand, GF_Write, 0, 0, 512, 512, abyRaster, 512, 512, GDT_Byte, 0, 0 ); GDALClose( hDstDS );
На языке Python:
import Numeric, osr dst_ds.SetGeoTransform( [ 444720, 30, 0, 3751320, 0, -30 ] ) srs = osr.SpatialReference() srs.SetUTM( 11, 1 ) srs.SetWellKnownGeogCS( 'NAD27' ) dst_ds.SetProjection( srs.ExportToWkt() ) raster = Numeric.zeros( (512, 512) ) dst_ds.GetRasterBand(1).WriteArray( raster )
$Id: gdal_tutorial_ru.dox 14542 2008-05-27 18:11:25Z dron $