Skip to content

Commit

Permalink
GTiff: no longer allow INTERLEAVE=TILE (only in a secret way use by t…
Browse files Browse the repository at this point in the history
…he COG driver)
  • Loading branch information
rouault committed Jan 10, 2025
1 parent 6245339 commit a3d090e
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 75 deletions.
8 changes: 1 addition & 7 deletions autotest/gcore/tiff_write.py
Original file line number Diff line number Diff line change
Expand Up @@ -11998,18 +11998,12 @@ def test_tiff_write_warn_ignore_predictor_option(tmp_vsimem):
@pytest.mark.parametrize("COPY_SRC_OVERVIEWS", ["YES", "NO"])
def test_tiff_write_interleave_tile(tmp_vsimem, COPY_SRC_OVERVIEWS):
out_filename = str(tmp_vsimem / "out.tif")
with pytest.raises(
Exception, match="INTERLEAVE=TILE is only supported for CreateCopy"
):
gdal.GetDriverByName("GTiff").Create(
out_filename, 1, 1, 2, options=["INTERLEAVE=TILE"]
)

ds = gdal.GetDriverByName("GTiff").CreateCopy(
out_filename,
gdal.Open("data/rgbsmall.tif"),
options=[
"INTERLEAVE=TILE",
"@TILE_INTERLEAVE=YES",
"TILED=YES",
"BLOCKXSIZE=32",
"BLOCKYSIZE=32",
Expand Down
38 changes: 6 additions & 32 deletions doc/source/drivers/raster/gtiff.rst
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ This driver supports the following creation options:
RPC information is available.

- .. co:: INTERLEAVE
:choices: BAND, PIXEL, TILE
:choices: BAND, PIXEL

Set the interleaving to use

Expand Down Expand Up @@ -481,42 +481,16 @@ This driver supports the following creation options:
end_for


* ``TILE`` (added in 3.11, only for CreateCopy()): this is a sort of
compromise between PIXEL and BAND, using the ``separate`` configuration,
but where data for a same spatial block is written for all bands, before
the data of the next spatial block.
When the block height is 1, this is also known as a
``BIL (Band Interleaved per Line)`` organization.

Such a layout may be useful for writing hyperspectral datasets (several
hundred of bands), to get a compromise between efficient spatial query,
and partial band selection.

Assuming a pixel[band][y][x] indexed array, when using CreateCopy(),
the pseudo code for the file disposition is:

::

for y in 0 ... numberOfBlocksInHeight - 1:
for x in 0 ... numberOfTilesInWidth - 1:
for band in 0 ... numberBands -1:
start_new_strip_or_tile()
for j in 0 ... blockHeight - 1:
for i in 0 ... blockWidth -1:
write(pixel[band][y*blockHeight+j][x*blockWidth+i])
end_for
end_for
end_new_strip_or_tile()
end_for
end_for
end_for


Starting with GDAL 3.5, when copying from a source dataset with multiple bands
which advertises a INTERLEAVE metadata item, if the INTERLEAVE creation option
is not specified, the source dataset INTERLEAVE will be automatically taken
into account, unless the COMPRESS creation option is specified.

.. note::

Starting with GDAL 3.11, a ``TILE`` interleaving is available,
but only when using the :ref:`raster.cog` driver.

- .. co:: TILED
:choices: YES, NO
:default: NO
Expand Down
10 changes: 9 additions & 1 deletion frmts/gtiff/cogdriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1361,7 +1361,15 @@ GDALDataset *GDALCOGCreator::Create(const char *pszFilename,
aosOptions.AddNameValue("SRC_MDD", *papszSrcMDDIter);
CSLDestroy(papszSrcMDD);

aosOptions.SetNameValue("INTERLEAVE", pszInterleave);
if (EQUAL(pszInterleave, "TILE"))
{
aosOptions.SetNameValue("INTERLEAVE", "BAND");
aosOptions.SetNameValue("@TILE_INTERLEAVE", "YES");
}
else
{
aosOptions.SetNameValue("INTERLEAVE", pszInterleave);
}

CPLDebug("COG", "Generating final product: start");
auto poRet =
Expand Down
1 change: 0 additions & 1 deletion frmts/gtiff/geotiff.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1340,7 +1340,6 @@ void GDALRegister_GTiff()
" <Option name='INTERLEAVE' type='string-select' default='PIXEL'>"
" <Value>BAND</Value>"
" <Value>PIXEL</Value>"
" <Value remark='Only for CreateCopy()'>TILE</Value>"
" </Option>"
" <Option name='TILED' type='boolean' description='Switch to tiled "
"format'/>"
Expand Down
65 changes: 31 additions & 34 deletions frmts/gtiff/gtiffdataset_write.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4284,9 +4284,9 @@ bool GTiffDataset::WriteMetadata(GDALDataset *poSrcDS, TIFF *l_hTIFF,
if (CPLTestBool(
CPLGetConfigOption("GTIFF_WRITE_IMAGE_STRUCTURE_METADATA", "YES")))
{
const char *pszInterleave =
CSLFetchNameValue(papszCreationOptions, "INTERLEAVE");
if (pszInterleave && EQUAL(pszInterleave, "TILE"))
const char *pszTileInterleave =
CSLFetchNameValue(papszCreationOptions, "@TILE_INTERLEAVE");
if (pszTileInterleave && CPLTestBool(pszTileInterleave))
{
AppendMetadataItem(&psRoot, &psTail, "INTERLEAVE", "TILE", 0,
nullptr, "IMAGE_STRUCTURE");
Expand Down Expand Up @@ -5121,47 +5121,44 @@ TIFF *GTiffDataset::CreateLL(const char *pszFilename, int nXSize, int nYSize,
}

int nPlanar = 0;
pszValue = CSLFetchNameValue(papszParamList, "INTERLEAVE");
if (pszValue != nullptr)

// Hidden @TILE_INTERLEAVE=YES parameter used by the COG driver
if (bCreateCopy &&
(pszValue = CSLFetchNameValue(papszParamList, "@TILE_INTERLEAVE")) &&
CPLTestBool(pszValue))
{
if (EQUAL(pszValue, "PIXEL"))
nPlanar = PLANARCONFIG_CONTIG;
else if (EQUAL(pszValue, "BAND"))
{
nPlanar = PLANARCONFIG_SEPARATE;
}
else if (EQUAL(pszValue, "BAND"))
{
nPlanar = PLANARCONFIG_SEPARATE;
}
else if (EQUAL(pszValue, "TILE"))
bTileInterleavingOut = true;
nPlanar = PLANARCONFIG_SEPARATE;
}
else
{
pszValue = CSLFetchNameValue(papszParamList, "INTERLEAVE");
if (pszValue != nullptr)
{
bTileInterleavingOut = true;
nPlanar = PLANARCONFIG_SEPARATE;
if (!bCreateCopy)
if (EQUAL(pszValue, "PIXEL"))
nPlanar = PLANARCONFIG_CONTIG;
else if (EQUAL(pszValue, "BAND"))
{
nPlanar = PLANARCONFIG_SEPARATE;
}
else if (EQUAL(pszValue, "BAND"))
{
nPlanar = PLANARCONFIG_SEPARATE;
}
else
{
CPLError(CE_Failure, CPLE_NotSupported,
"INTERLEAVE=TILE is only supported for CreateCopy(), "
"not Create()");
ReportError(
pszFilename, CE_Failure, CPLE_IllegalArg,
"INTERLEAVE=%s unsupported, value must be PIXEL or BAND.",
pszValue);
return nullptr;
}
}
else
{
ReportError(
pszFilename, CE_Failure, CPLE_IllegalArg,
bCreateCopy
? "INTERLEAVE=%s unsupported, value must be PIXEL, BAND or "
"TILE."
: "INTERLEAVE=%s unsupported, value must be PIXEL or BAND.",
pszValue);
return nullptr;
nPlanar = PLANARCONFIG_CONTIG;
}
}
else
{
nPlanar = PLANARCONFIG_CONTIG;
}

int l_nCompression = COMPRESSION_NONE;
pszValue = CSLFetchNameValue(papszParamList, "COMPRESS");
Expand Down

0 comments on commit a3d090e

Please sign in to comment.