All formats

GDAL

LanguageC++ with a C API (bindings for Python, Java, C#, Go, Rust)
LicenseMIT
Repositorygithub.com/OSGeo/gdal
Documentationgdal.org, GTiff driver, COG driver
Depends onPROJ, libtiff, libgeotiff (bundled copies available), many optional libraries
Read / writeyes / yes, GeoTIFF, BigTIFF, COG, tiles, overviews, all common compressions

GDAL (Geospatial Data Abstraction Library) is the standard library for raster and vector geodata. QGIS, ArcGIS, PostGIS, rasterio and most GIS software use it. Its GTiff driver reads and writes TIFF with georeferencing: the affine geotransform, the coordinate reference system, nodata values, overviews and metadata. A dataset has one or more bands; each band is a 2D array of a data type such as GDT_Byte, GDT_UInt16 or GDT_Float32.

GDAL is large. If you only need regular images (photos, scans), use libtiff directly.

Installation#

Shell
# Debian / Ubuntu
sudo apt install libgdal-dev gdal-bin
# Fedora
sudo dnf install gdal-devel
# macOS
brew install gdal
# Windows (vcpkg)
vcpkg install gdal

With CMake:

cmake
find_package(GDAL CONFIG REQUIRED)
target_link_libraries(myapp PRIVATE GDAL::GDAL)

Basic usage: read a GeoTIFF#

C++
#include <gdal_priv.h>
#include <cstdio>
#include <vector>

int main() {
    GDALAllRegister();
    GDALDataset *ds = GDALDataset::Open("dem.tif", GDAL_OF_RASTER | GDAL_OF_READONLY);
    if (!ds) return 1;

    int w = ds->GetRasterXSize(), h = ds->GetRasterYSize();
    printf("%d x %d, %d bands\n", w, h, ds->GetRasterCount());

    double gt[6];
    if (ds->GetGeoTransform(gt) == CE_None)
        printf("origin %f, %f, pixel size %f, %f\n", gt[0], gt[3], gt[1], gt[5]);
    if (const OGRSpatialReference *srs = ds->GetSpatialRef())
        printf("CRS: %s\n", srs->GetName());

    GDALRasterBand *band = ds->GetRasterBand(1);  // bands are 1-based
    std::vector<float> row(w);
    if (band->RasterIO(GF_Read, 0, 0, w, 1, row.data(), w, 1, GDT_Float32, 0, 0) == CE_None)
        printf("first value: %f\n", row[0]);

    GDALClose(ds);
    return 0;
}

gt[0], gt[3] are the coordinates of the top-left corner; gt[1], gt[5] are the pixel width and (negative) height.

How to create a compressed GeoTIFF#

C++
#include <gdal_priv.h>
#include <ogr_spatialref.h>
#include <cpl_string.h>
#include <vector>

int write_geotiff(const char *path, const std::vector<float> &data, int w, int h) {
    GDALAllRegister();
    GDALDriver *drv = GetGDALDriverManager()->GetDriverByName("GTiff");
    char **opts = nullptr;
    opts = CSLSetNameValue(opts, "COMPRESS", "DEFLATE");
    opts = CSLSetNameValue(opts, "PREDICTOR", "3");  // floating point predictor
    opts = CSLSetNameValue(opts, "TILED", "YES");
    GDALDataset *ds = drv->Create(path, w, h, 1, GDT_Float32, opts);
    CSLDestroy(opts);
    if (!ds) return 1;

    double gt[6] = {10.0, 0.001, 0.0, 50.0, 0.0, -0.001};  // origin lon 10, lat 50
    ds->SetGeoTransform(gt);
    OGRSpatialReference srs;
    srs.importFromEPSG(4326);
    ds->SetSpatialRef(&srs);

    GDALRasterBand *band = ds->GetRasterBand(1);
    band->SetNoDataValue(-9999);
    CPLErr err = band->RasterIO(GF_Write, 0, 0, w, h, const_cast<float *>(data.data()),
                                w, h, GDT_Float32, 0, 0);
    GDALClose(ds);  // flushes and closes the file
    return err == CE_None ? 0 : 1;
}

Useful creation options: COMPRESS=LZW|DEFLATE|ZSTD|JPEG|WEBP|LERC, BIGTIFF=YES|IF_SAFER, TILED=YES, BLOCKXSIZE=512.

How to convert a TIFF to a Cloud Optimized GeoTIFF#

The COG driver only supports CreateCopy. It adds tiles, overviews and the right layout:

C++
GDALDataset *src = GDALDataset::Open("in.tif", GDAL_OF_RASTER);
GDALDriver *cog = GetGDALDriverManager()->GetDriverByName("COG");
char **opts = CSLSetNameValue(nullptr, "COMPRESS", "DEFLATE");
GDALDataset *dst = cog->CreateCopy("out_cog.tif", src, FALSE, opts, nullptr, nullptr);
CSLDestroy(opts);
if (dst) GDALClose(dst);
GDALClose(src);

The same from the command line: gdal_translate in.tif out_cog.tif -of COG -co COMPRESS=DEFLATE.

How to read TIFF metadata#

C++
// TIFF tags such as TIFFTAG_SOFTWARE, TIFFTAG_DATETIME, plus GDAL metadata
char **md = ds->GetMetadata();
for (int i = 0; md && md[i]; i++) printf("%s\n", md[i]);

// compression and layout
if (const char *c = ds->GetMetadataItem("COMPRESSION", "IMAGE_STRUCTURE"))
    printf("compression: %s\n", c);

How to read a remote COG over HTTP#

Prefix the URL with /vsicurl/. GDAL reads only the bytes it needs with range requests:

C++
GDALDataset *ds = GDALDataset::Open("/vsicurl/https://example.com/data/cog.tif", GDAL_OF_RASTER);

Tips#