#ifndef DOXYGEN_SKIP /* $Id: vrt_tutorial.dox 24950 2012-09-22 13:54:36Z rouault $ */ #endif /* DOXYGEN_SKIP */ /*! \page gdal_vrttut GDAL Virtual Format Tutorial \section gdal_vrttut_intro Introduction The VRT driver is a format driver for GDAL that allows a virtual GDAL dataset to be composed from other GDAL datasets with repositioning, and algorithms potentially applied as well as various kinds of metadata altered or added. VRT descriptions of datasets can be saved in an XML format normally given the extension .vrt.
An example of a simple .vrt file referring to a 512x512 dataset with one band
loaded from utm.tif might look like this:
\code
VRT files can be produced by translating to VRT format. The resulting file can then be edited to modify mappings, add metadata or other purposes. VRT files can also be produced programmatically by various means.
This tutorial will cover the .vrt file format (suitable for users editing .vrt files), and how .vrt files may be created and manipulated programmatically for developers.
\section gdal_vrttut_format .vrt Format Virtual files stored on disk are kept in an XML format with the following elements.
VRTDataset: This is the root element for the whole GDAL dataset.
It must have the attributes rasterXSize and rasterYSize describing the width
and height of the dataset in pixels. It may have SRS, GeoTransform,
GCPList, Metadata, MaskBand and VRTRasterBand subelements.
\code
\code
\code
The allowed subelements for VRTRasterBand are :
\code
\code
\code
\code
\code
\code
To create a VRT dataset that is a clone of an existing dataset use the
CreateCopy() method. For example to clone utm.tif into a wrk.vrt file in
C++ the following could be used:
\code
GDALDriver *poDriver = (GDALDriver *) GDALGetDriverByName( "VRT" );
GDALDataset *poSrcDS, *poVRTDS;
poSrcDS = (GDALDataset *) GDALOpenShared( "utm.tif", GA_ReadOnly );
poVRTDS = poDriver->CreateCopy( "wrk.vrt", poSrcDS, FALSE, NULL, NULL, NULL );
GDALClose((GDALDatasetH) poVRTDS);
GDALClose((GDALDatasetH) poSrcDS);
\endcode
Note the use of GDALOpenShared() when opening the source dataset. It is advised
to use GDALOpenShared() in this situation so that you are able to release
the explicit reference to it before closing the VRT dataset itself. In other
words, in the previous example, you could also invert the 2 last lines, whereas
if you open the source dataset with GDALOpen(), you'd need to close the VRT dataset
before closing the source dataset.
To create a virtual copy of a dataset with some attributes added or changed
such as metadata or coordinate system that are often hard to change on other
formats, you might do the following. In this case, the virtual dataset is
created "in memory" only by virtual of creating it with an empty filename, and
then used as a modified source to pass to a CreateCopy() written out in TIFF
format.
\code
poVRTDS = poDriver->CreateCopy( "", poSrcDS, FALSE, NULL, NULL, NULL );
poVRTDS->SetMetadataItem( "SourceAgency", "United States Geological Survey");
poVRTDS->SetMetadataItem( "SourceDate", "July 21, 2003" );
poVRTDS->GetRasterBand( 1 )->SetNoDataValue( -999.0 );
GDALDriver *poTIFFDriver = (GDALDriver *) GDALGetDriverByName( "GTiff" );
GDALDataset *poTiffDS;
poTiffDS = poTIFFDriver->CreateCopy( "wrk.tif", poVRTDS, FALSE, NULL, NULL, NULL );
GDALClose((GDALDatasetH) poTiffDS);
\endcode
In the above example the nodata value is set as -999. You can set the
HideNoDataValue element in the VRT dataset's band using SetMetadataItem() on
that band.
\code
poVRTDS->GetRasterBand( 1 )->SetMetadataItem( "HideNoDataValue" , "1" );
\endcode
In this example a virtual dataset is created with the Create() method, and
adding bands and sources programmatically, but still via the "generic" API.
A special attribute of VRT datasets is that sources can be added to the VRTRasterBand
(but not to VRTRawRasterBand) by passing the XML describing the source into SetMetadata() on the special
domain target "new_vrt_sources". The domain target "vrt_sources" may also be
used, in which case any existing sources will be discarded before adding the
new ones. In this example we construct a simple averaging filter source
instead of using the simple source.
\code
// construct XML for simple 3x3 average filter kernel source.
const char *pszFilterSourceXML =
"
\section gdal_vrttut_vrt .vrt Descriptions for Raw Files
So far we have described how to derive new virtual datasets from existing
files supports by GDAL. However, it is also common to need to utilize
raw binary raster files for which the regular layout of the data is known
but for which no format specific driver exists. This can be accomplished
by writing a .vrt file describing the raw file.
For example, the following .vrt describes a raw raster file containing
floating point complex pixels in a file called l2p3hhsso.img. The
image data starts from the first byte (ImageOffset=0). The byte offset
between pixels is 8 (PixelOffset=8), the size of a CFloat32. The byte offset
from the start of one line to the start of the next is 9376 bytes
(LineOffset=9376) which is the width (1172) times the size of a pixel (8).
\code
\code
A few other notes:
Another example, in this case a 400x300 RGB pixel interleaved image.
\code
Using Derived Bands
A specialized type of band is a 'derived' band which derives its pixel
information from its source bands. With this type of band you must also
specify a pixel function, which has the responsibility of generating the
output raster. Pixel functions are created by an application and then
registered with GDAL using a unique key.
Using derived bands you can create VRT datasets that manipulate bands on
the fly without having to create new band files on disk. For example, you
might want to generate a band using four source bands from a nine band input
dataset (x0, x3, x4, and x8):
\code
band_value = sqrt((x3*x3+x4*x4)/(x0*x8));
\endcode
You could write the pixel function to compute this value and then register
it with GDAL with the name "MyFirstFunction". Then, the following VRT XML
could be used to display this derived band:
\code
Writing Pixel Functions
To register this function with GDAL (prior to accessing any VRT datasets
with derived bands that use this function), an application calls
GDALAddDerivedBandPixelFunc with a key and a GDALDerivedPixelFunc:
\code
GDALAddDerivedBandPixelFunc("MyFirstFunction", TestFunction);
\endcode
A good time to do this is at the beginning of an application when the
GDAL drivers are registered.
GDALDerivedPixelFunc is defined with a signature similar to IRasterIO:
@param papoSources A pointer to packed rasters; one per source. The
datatype of all will be the same, specified in the eSrcType parameter.
@param nSources The number of source rasters.
@param pData The buffer into which the data should be read, or from which
it should be written. This buffer must contain at least nBufXSize *
nBufYSize words of type eBufType. It is organized in left to right,
top to bottom pixel order. Spacing is controlled by the nPixelSpace,
and nLineSpace parameters.
@param nBufXSize The width of the buffer image into which the desired
region is to be read, or from which it is to be written.
@param nBufYSize The height of the buffer image into which the desired
region is to be read, or from which it is to be written.
@param eSrcType The type of the pixel values in the papoSources raster
array.
@param eBufType The type of the pixel values that the pixel function must
generate in the pData data buffer.
@param nPixelSpace The byte offset from the start of one pixel value in
pData to the start of the next pixel value within a scanline. If
defaulted (0) the size of the datatype eBufType is used.
@param nLineSpace The byte offset from the start of one scanline in
pData to the start of the next.
@return CE_Failure on failure, otherwise CE_None.
\code
typedef CPLErr
(*GDALDerivedPixelFunc)(void **papoSources, int nSources, void *pData,
int nXSize, int nYSize,
GDALDataType eSrcType, GDALDataType eBufType,
int nPixelSpace, int nLineSpace);
\endcode
The following is an implementation of the pixel function:
\code
#include "gdal.h"
CPLErr TestFunction(void **papoSources, int nSources, void *pData,
int nXSize, int nYSize,
GDALDataType eSrcType, GDALDataType eBufType,
int nPixelSpace, int nLineSpace)
{
int ii, iLine, iCol;
double pix_val;
double x0, x3, x4, x8;
// ---- Init ----
if (nSources != 4) return CE_Failure;
// ---- Set pixels ----
for( iLine = 0; iLine < nYSize; iLine++ )
{
for( iCol = 0; iCol < nXSize; iCol++ )
{
ii = iLine * nXSize + iCol;
/* Source raster pixels may be obtained with SRCVAL macro */
x0 = SRCVAL(papoSources[0], eSrcType, ii);
x3 = SRCVAL(papoSources[1], eSrcType, ii);
x4 = SRCVAL(papoSources[2], eSrcType, ii);
x8 = SRCVAL(papoSources[3], eSrcType, ii);
pix_val = sqrt((x3*x3+x4*x4)/(x0*x8));
GDALCopyWords(&pix_val, GDT_Float64, 0,
((GByte *)pData) + nLineSpace * iLine + iCol * nPixelSpace,
eBufType, nPixelSpace, 1);
}
}
// ---- Return success ----
return CE_None;
}
\endcode
\section gdal_vrttut_mt Multi-threading issues
When using VRT datasets in a multi-threading environment, you should be
careful to open the VRT dataset by the thread that will use it afterwards. The
reason for that is that the VRT dataset uses GDALOpenShared when opening the
underlying datasets. So, if you open twice the same VRT dataset by the same
thread, both VRT datasets will share the same handles to the underlying
datasets.
*/