Skip to main content
1 of 2

Writing COG using GDAL C++ API fails with block order warning

I'm using the GDAL C++ API to write a COG which is constructed by the rest of the code. If I use the Geotiff driver, there are no problems. But when I switch over to the COG driver, I'm not able to get something that write correctly.

My code starts by opening an in-memory dataset and then uses the CreateCopy method to open the COG handle. Then, it does some work in a loop and writes the blocks to the raster.

// Create an in-memory dataset
auto temp_mem_dataset = GDALDatasetUniquePtr(GDALDataset::FromHandle(
    GDALCreate(GetGDALDriverManager()->GetDriverByName("MEM"), "", m_nx, m_ny,
                 1, GDT_Int32, nullptr)));

// Create the geo-transform and apply to raster
std::array<double, 6> transform = {this->x_start(), 
    this->x_resolution(), 
    0.0, this->y_start(), 
    0.0, -this->y_resolution()
};
temp_mem_dataset->SetGeoTransform(transform.data());

// Create the spatial reference
const std::string spatial_ref_str = "EPSG:4326";
OGRSpatialReference spatial_reference;
spatial_reference.SetWellKnownGeogCS(spatial_ref_str.c_str());
char *cwkt = nullptr;
spatial_reference.exportToWkt(&cwkt);
temp_mem_dataset->SetProjection(cwkt);
CPLFree(cwkt);

// Set the creation options for the COG raster
CPLStringList options;
options.SetNameValue("BIGTIFF", "YES");
options.SetNameValue("COMPRESS", "LZW");

// Create a copy of the raster as a COG
m_dataset = GDALDatasetUniquePtr(GDALDataset::FromHandle(
      GetGDALDriverManager()->GetDriverByName("COG")->CreateCopy(m_filename.c_str(),
      temp_mem_dataset.get(), 0, options.List(), nullptr, nullptr)));

// Get the band and set some metadata
auto *node_index_band = m_dataset->GetRasterBand(1);
node_index_band->GetBlockSize(&m_block_size_x, &m_block_size_y);
node_index_band->SetNoDataValue(-1);
node_index_band->SetDescription("Node Index");

From there, it's just a loop over the i,j blocks and creating a worker which generates the raster for the given block.

// ... Begin Work Loop ... //
for (int j = 0; j < n_j_blocks; j++) {
 for (int i = 0; i < n_i_blocks; i++) {
   auto work = generate_work_obj();
   std::vector<int> node_index = work->getResult();
   auto err = node_index_band->WriteBlock(i, j, node_index.data());
  }
}

For the GTiff driver, this is all fine. But the cog driver gives the following warning:

Warning 1: index.tiff: A strile cannot be rewritten in place, which invalidates the BLOCK_ORDER optimization.

I have assumed this had to do with the order of how I was writing blocks to the COG, however, I can't for the life of me figure out what the correct ordering should be. I see in the docs it should be ROW_MAJOR, but it's not clear why no permutation of the nested loop writes in the COG's preferred order. Also, when opening the COG after the warning is thrown, the COG does not appear to have been written and only contains the default values. I've tracked this to the source here but I'm not familiar enough with the inner workings of gdal just yet to decipher.

I'm hoping there is something obvious I'm missing here or that the warning has somehow pointed me in the wrong direction and I'm just looking in the wrong place. Any help appreciated.