gdal/autotest/gcore/tiff_write.py

10505 строки
331 KiB
Python
Исполняемый файл

#!/usr/bin/env pytest
# -*- coding: utf-8 -*-
###############################################################################
# $Id$
#
# Project: GDAL/OGR Test Suite
# Purpose: Test read/write functionality for GeoTIFF format.
# Author: Frank Warmerdam <warmerdam@pobox.com>
#
###############################################################################
# Copyright (c) 2003, Frank Warmerdam <warmerdam@pobox.com>
# Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Library General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
###############################################################################
import copy
import math
import os
import shutil
import struct
import sys
import gdaltest
import pytest
from test_py_scripts import samples_path
from osgeo import gdal, osr
###############################################################################
@pytest.fixture(autouse=True, scope="module")
def module_disable_exceptions():
with gdaltest.disable_exceptions():
yield
###############################################################################
def _check_cog(filename, check_tiled=True, full_check=False):
path = samples_path
if path not in sys.path:
sys.path.append(path)
import validate_cloud_optimized_geotiff
try:
_, errors, _ = validate_cloud_optimized_geotiff.validate(
filename, check_tiled=check_tiled, full_check=full_check
)
assert not errors, "validate_cloud_optimized_geotiff failed"
except OSError:
pytest.fail("validate_cloud_optimized_geotiff failed")
###############################################################################
# Get the GeoTIFF driver, and verify a few things about it.
def test_tiff_write_1():
gdaltest.tiff_drv = gdal.GetDriverByName("GTiff")
assert gdaltest.tiff_drv is not None, "GTiff driver not found!"
drv_md = gdaltest.tiff_drv.GetMetadata()
assert drv_md["DMD_MIMETYPE"] == "image/tiff", "mime type is wrong"
###############################################################################
# Create a simple file by copying from an existing one.
def test_tiff_write_2():
src_ds = gdal.Open("data/cfloat64.tif")
new_ds = gdaltest.tiff_drv.CreateCopy("tmp/test_2.tif", src_ds)
assert new_ds.FlushCache() == gdal.CE_None
bnd = new_ds.GetRasterBand(1)
assert bnd.Checksum() == 5028, "Didn't get expected checksum on still-open file"
bnd = None
new_ds = None
# hopefully it's closed now!
new_ds = gdal.Open("tmp/test_2.tif")
bnd = new_ds.GetRasterBand(1)
assert bnd.Checksum() == 5028, "Didn't get expected checksum on reopened file"
assert bnd.ComputeRasterMinMax() == (
74.0,
255.0,
), "ComputeRasterMinMax() returned wrong value"
bnd = None
new_ds = None
gdaltest.tiff_drv.Delete("tmp/test_2.tif")
###############################################################################
# Create a simple file by copying from an existing one.
def test_tiff_write_3():
src_ds = gdal.Open("data/utmsmall.tif")
options = ["TILED=YES", "BLOCKXSIZE=32", "BLOCKYSIZE=32"]
new_ds = gdaltest.tiff_drv.CreateCopy("tmp/test_3.tif", src_ds, options=options)
bnd = new_ds.GetRasterBand(1)
assert bnd.Checksum() == 50054, "Didn't get expected checksum on still-open file"
bnd = None
new_ds = None
gdaltest.tiff_drv.Delete("tmp/test_3.tif")
###############################################################################
# Create a tiled file.
def test_tiff_write_4():
np = pytest.importorskip("numpy")
options = ["TILED=YES", "BLOCKXSIZE=32", "BLOCKYSIZE=32"]
new_ds = gdaltest.tiff_drv.Create(
"tmp/test_4.tif", 40, 50, 3, gdal.GDT_Byte, options
)
data_red = np.zeros((50, 40), dtype=np.uint8)
data_green = np.zeros((50, 40), dtype=np.uint8)
data_blue = np.zeros((50, 40), dtype=np.uint8)
for y in range(50):
for x in range(40):
data_red[y][x] = x
data_green[y][x] = y
data_blue[y][x] = x + y
new_ds.GetRasterBand(1).WriteArray(data_red)
new_ds.GetRasterBand(2).WriteArray(data_green)
new_ds.GetRasterBand(3).WriteArray(data_blue)
gt = (0.0, 1.0, 0.0, 50.0, 0.0, -1.0)
new_ds.SetGeoTransform(gt)
assert (
new_ds.GetRasterBand(1).Checksum() == 21577
and new_ds.GetRasterBand(2).Checksum() == 20950
and new_ds.GetRasterBand(3).Checksum() == 23730
), "Wrong checksum."
assert gt == new_ds.GetGeoTransform(), "Wrong geotransform."
new_ds.SetMetadata({"TEST_KEY": "TestValue <>"})
new_ds = None
new_ds = gdal.Open("tmp/test_4.tif")
assert (
new_ds.GetRasterBand(1).Checksum() == 21577
and new_ds.GetRasterBand(2).Checksum() == 20950
and new_ds.GetRasterBand(3).Checksum() == 23730
), "Wrong checksum (2)."
assert gt == new_ds.GetGeoTransform(), "Wrong geotransform(2)."
nd = new_ds.GetRasterBand(1).GetNoDataValue()
assert nd is None, "Got unexpected nodata value."
md_dict = new_ds.GetMetadata()
assert md_dict["TEST_KEY"] == "TestValue <>", "Missing metadata"
new_ds = None
gdaltest.tiff_drv.Delete("tmp/test_4.tif")
###############################################################################
# Write a file with GCPs.
def test_tiff_write_5():
src_ds = gdal.Open("data/gcps.vrt")
new_ds = gdaltest.tiff_drv.CreateCopy("tmp/test_5.tif", src_ds)
assert (
new_ds.GetGCPProjection().find('AUTHORITY["EPSG","26711"]') != -1
), "GCP Projection not set properly."
gcps = new_ds.GetGCPs()
assert len(gcps) == 4, "GCP count wrong."
new_ds = None
gdaltest.tiff_drv.Delete("tmp/test_5.tif")
# Test SetGCPs on a new GTiff
new_ds = gdaltest.tiff_drv.Create("tmp/test_5.tif", 10, 10, 1)
new_ds.SetGCPs(gcps, src_ds.GetGCPProjection())
new_ds = None
new_ds = gdal.Open("tmp/test_5.tif")
gcps = new_ds.GetGCPs()
assert len(gcps) == 4, "GCP count wrong."
new_ds = None
gdaltest.tiff_drv.Delete("tmp/test_5.tif")
###############################################################################
# Test a mixture of reading and writing on a DEFLATE compressed file.
def test_tiff_write_6():
options = [
"TILED=YES",
"BLOCKXSIZE=32",
"BLOCKYSIZE=32",
"COMPRESS=DEFLATE",
"PREDICTOR=2",
]
ds = gdaltest.tiff_drv.Create("tmp/test_6.tif", 200, 200, 1, gdal.GDT_Byte, options)
# make a 32x32 byte buffer
buf = b"".join(struct.pack("B", v) for v in range(32)) * 32
ds.WriteRaster(0, 0, 32, 32, buf, buf_type=gdal.GDT_Byte)
ds.FlushCache()
ds.WriteRaster(32, 0, 32, 32, buf, buf_type=gdal.GDT_Byte)
ds.FlushCache()
buf_read = ds.ReadRaster(0, 0, 32, 32, buf_type=gdal.GDT_Byte)
if buf_read != buf:
gdaltest.tiff_write_6_failed = True
pytest.fail("did not get back expected data.")
ds = None
ds = gdal.Open("tmp/test_6.tif")
assert ds.GetMetadataItem("COMPRESSION", "IMAGE_STRUCTURE") == "DEFLATE"
assert ds.GetMetadataItem("PREDICTOR", "IMAGE_STRUCTURE") == "2"
ds = None
gdaltest.tiff_write_6_failed = False
gdaltest.tiff_drv.Delete("tmp/test_6.tif")
###############################################################################
# Test a mixture of reading and writing on a LZW compressed file.
def test_tiff_write_7():
options = ["TILED=YES", "COMPRESS=LZW", "PREDICTOR=2"]
ds = gdaltest.tiff_drv.Create("tmp/test_7.tif", 200, 200, 1, gdal.GDT_Byte, options)
# make a 32x32 byte buffer
buf = b"".join(struct.pack("B", v) for v in range(32)) * 32
ds.WriteRaster(0, 0, 32, 32, buf, buf_type=gdal.GDT_Byte)
ds.FlushCache()
ds.WriteRaster(32, 0, 32, 32, buf, buf_type=gdal.GDT_Byte)
ds.FlushCache()
buf_read = ds.ReadRaster(0, 0, 32, 32, buf_type=gdal.GDT_Byte)
assert buf_read == buf, "did not get back expected data."
ds = None
gdaltest.tiff_drv.Delete("tmp/test_7.tif")
###############################################################################
# Test a mixture of reading and writing on a PACKBITS compressed file.
def test_tiff_write_8():
options = ["TILED=YES", "BLOCKXSIZE=32", "BLOCKYSIZE=32", "COMPRESS=PACKBITS"]
ds = gdaltest.tiff_drv.Create("tmp/test_8.tif", 200, 200, 1, gdal.GDT_Byte, options)
# make a 32x32 byte buffer
buf = b"".join(struct.pack("B", v) for v in range(32)) * 32
ds.WriteRaster(0, 0, 32, 32, buf, buf_type=gdal.GDT_Byte)
ds.FlushCache()
ds.WriteRaster(32, 0, 32, 32, buf, buf_type=gdal.GDT_Byte)
ds.FlushCache()
buf_read = ds.ReadRaster(0, 0, 32, 32, buf_type=gdal.GDT_Byte)
assert buf_read == buf, "did not get back expected data."
ds = None
gdaltest.tiff_drv.Delete("tmp/test_8.tif")
###############################################################################
# Create a simple file by copying from an existing one.
def test_tiff_write_9():
src_ds = gdal.Open("data/byte.tif")
new_ds = gdaltest.tiff_drv.CreateCopy("tmp/test_9.tif", src_ds, options=["NBITS=5"])
with gdaltest.error_handler():
new_ds = None
new_ds = gdal.Open("tmp/test_9.tif")
bnd = new_ds.GetRasterBand(1)
assert bnd.Checksum() == 5287, "Didn't get expected checksum on reopened file"
bnd = None
new_ds = None
gdaltest.tiff_drv.Delete("tmp/test_9.tif")
###############################################################################
# 1bit file but with band interleaving, and odd size (not multiple of 8) #1957
def test_tiff_write_10():
ut = gdaltest.GDALTest(
"GTiff", "oddsize_1bit2b.tif", 2, 5918, options=["NBITS=1", "INTERLEAVE=BAND"]
)
return ut.testCreate(out_bands=2)
###############################################################################
# Simple 1 bit file, treated through the GTiffBitmapBand class.
def test_tiff_write_11():
ut = gdaltest.GDALTest(
"GTiff", "oddsize1bit.tif", 1, 5918, options=["NBITS=1", "COMPRESS=CCITTFAX4"]
)
return ut.testCreateCopy()
###############################################################################
# Read JPEG Compressed YCbCr subsampled image.
@pytest.mark.require_creation_option("GTiff", "JPEG")
def test_tiff_write_12():
ds = gdal.Open("data/sasha.tif")
cs = ds.GetRasterBand(3).Checksum()
assert cs == 31952 or cs == 30145
###############################################################################
# Write JPEG Compressed YCbCr subsampled image.
@pytest.mark.require_creation_option("GTiff", "JPEG")
def test_tiff_write_13():
src_ds = gdal.Open("data/sasha.tif")
ds = gdaltest.tiff_drv.CreateCopy(
"tmp/sasha.tif",
src_ds,
options=[
"PROFILE=BASELINE",
"TILED=YES",
"COMPRESS=JPEG",
"PHOTOMETRIC=YCBCR",
"JPEG_QUALITY=31",
],
)
ds = None
ds = gdal.Open("tmp/sasha.tif")
cs = ds.GetRasterBand(3).Checksum()
ds = None
size = os.stat("tmp/sasha.tif").st_size
gdaltest.tiff_drv.Delete("tmp/sasha.tif")
assert cs in (
17347,
14445,
14135, # libjpeg 9e
)
md = gdaltest.tiff_drv.GetMetadata()
if md["LIBTIFF"] == "INTERNAL":
# 22816 with libjpeg-6b or libjpeg-turbo
# 22828 with libjpeg-9d
assert size <= 22828, "fail: bad size"
###############################################################################
# Test creating an in memory copy.
def test_tiff_write_14():
tst = gdaltest.GDALTest("GTiff", "byte.tif", 1, 4672)
return tst.testCreateCopy(vsimem=1)
###############################################################################
# Test that we can restrict metadata and georeferencing in the output
# file using the PROFILE creation option with CreateCopy()
def test_tiff_write_15():
ds_in = gdal.Open("data/byte.vrt")
ds = gdaltest.tiff_drv.CreateCopy(
"tmp/tw_15.tif", ds_in, options=["PROFILE=BASELINE"]
)
ds_in = None
ds = None
ds = gdal.Open("tmp/tw_15.tif")
md = ds.GetMetadata()
assert "test" in md, "Metadata absent from .aux.xml file."
md = ds.GetRasterBand(1).GetMetadata()
assert "testBand" in md, "Metadata absent from .aux.xml file."
ds = None
gdal.Unlink("tmp/tw_15.tif.aux.xml")
ds = gdal.Open("tmp/tw_15.tif")
assert ds.GetGeoTransform() == (
0.0,
1.0,
0.0,
0.0,
0.0,
1.0,
), "Got wrong geotransform, profile ignored?"
md = ds.GetMetadata()
assert "test" not in md, "Metadata written to BASELINE file."
md = ds.GetRasterBand(1).GetMetadata()
assert "testBand" not in md, "Metadata written to BASELINE file."
ds = None
gdaltest.tiff_drv.Delete("tmp/tw_15.tif")
###############################################################################
# Test that we can restrict metadata and georeferencing in the output
# file using the PROFILE creation option with Create()
def test_tiff_write_16():
ds_in = gdal.Open("data/byte.vrt")
ds = gdaltest.tiff_drv.Create(
"tmp/tw_16.tif", 20, 20, gdal.GDT_Byte, options=["PROFILE=BASELINE"]
)
ds.SetMetadata({"test": "testvalue"})
ds.GetRasterBand(1).SetMetadata({"testBand": "testvalueBand"})
srs = osr.SpatialReference()
srs.ImportFromEPSG(4326)
ds.SetSpatialRef(srs)
ds.SetGeoTransform((10, 5, 0, 30, 0, -5))
data = ds_in.ReadRaster(0, 0, 20, 20)
ds.WriteRaster(0, 0, 20, 20, data)
ds_in = None
ds = None
# Check first from PAM
assert gdal.VSIStatL("tmp/tw_16.tif.aux.xml") is not None
ds = gdal.Open("tmp/tw_16.tif")
assert ds.GetGeoTransform() == (10, 5, 0, 30, 0, -5)
assert ds.GetSpatialRef() is not None
assert ds.GetSpatialRef().GetAuthorityCode(None) == "4326"
md = ds.GetMetadata()
assert "test" in md, "Metadata absent from .aux.xml file."
md = ds.GetRasterBand(1).GetMetadata()
assert "testBand" in md, "Metadata absent from .aux.xml file."
ds = None
gdal.Unlink("tmp/tw_16.tif.aux.xml")
ds = gdal.Open("tmp/tw_16.tif")
assert ds.GetGeoTransform() == (
0.0,
1.0,
0.0,
0.0,
0.0,
1.0,
), "Got wrong geotransform, profile ignored?"
assert ds.GetSpatialRef() is None
md = ds.GetMetadata()
assert "test" not in md, "Metadata written to BASELINE file."
md = ds.GetRasterBand(1).GetMetadata()
assert "testBand" not in md, "Metadata written to BASELINE file."
ds = None
gdaltest.tiff_drv.Delete("tmp/tw_16.tif")
###############################################################################
# Test writing a TIFF with an RPC tag.
def test_tiff_write_17():
# Translate RPC controlled data to GeoTIFF.
ds_in = gdal.Open("data/rpc.vrt")
rpc_md = ds_in.GetMetadata("RPC")
tmpfilename = "/vsimem/tiff_write_17.tif"
ds = gdaltest.tiff_drv.CreateCopy(tmpfilename, ds_in)
ds_in = None
ds = None
# Ensure there is no .aux.xml file which might hold the RPC.
assert not gdal.VSIStatL(
tmpfilename + ".aux.xml"
), "unexpectedly found.aux.xml file"
# confirm there is no .rpb file created by default.
assert not gdal.VSIStatL(tmpfilename + ".RPB"), "unexpectedly found .RPB file"
# confirm there is no _rpc.txt file created by default.
assert not gdal.VSIStatL(
tmpfilename + "_RPC.TXT"
), "unexpectedly found _RPC.TXT file"
# Open the dataset, and confirm the RPC data is still intact.
ds = gdal.Open(tmpfilename)
assert gdaltest.rpcs_equal(ds.GetMetadata("RPC"), rpc_md)
ds = None
# Modify the RPC
modified_rpc = copy.copy(rpc_md)
modified_rpc["LINE_OFF"] = "123456"
ds = gdal.Open(tmpfilename, gdal.GA_Update)
ds.SetMetadata(modified_rpc, "RPC")
ds = None
ds = gdal.Open(tmpfilename)
assert gdaltest.rpcs_equal(ds.GetMetadata("RPC"), modified_rpc)
ds = None
# Unset the RPC
ds = gdal.Open(tmpfilename, gdal.GA_Update)
ds.SetMetadata(None, "RPC")
ds = None
ds = gdal.Open(tmpfilename)
assert not ds.GetMetadata("RPC"), "got RPC, but was not expected"
ds = None
gdaltest.tiff_drv.Delete(tmpfilename)
###############################################################################
# Test that above test still work with the optimization in the GDAL_DISABLE_READDIR_ON_OPEN
# case (#3996)
def test_tiff_write_17_disable_readdir():
with gdal.config_option("GDAL_DISABLE_READDIR_ON_OPEN", "TRUE"):
ret = test_tiff_write_17()
return ret
###############################################################################
# Test writing a TIFF with an RPB file and IMD file.
def test_tiff_write_18():
# Translate RPC controlled data to GeoTIFF.
ds_in = gdal.Open("data/rpc.vrt")
rpc_md = ds_in.GetMetadata("RPC")
gdaltest.tiff_drv.CreateCopy("tmp/tw_18.tif", ds_in, options=["PROFILE=BASELINE"])
# Ensure there is no .aux.xml file which might hold the RPC.
assert not gdal.VSIStatL(
"tmp/tm_18.tif.aux.xml"
), "unexpectedly found tm_18.tif.aux.xml file"
# confirm there is an .rpb and .imd file.
assert gdal.VSIStatL("tmp/tw_18.RPB") is not None, "missing .RPB file."
assert gdal.VSIStatL("tmp/tw_18.IMD") is not None, "missing .IMD file."
# confirm there is no _rpc.txt file created by default.
assert not gdal.VSIStatL("tmp/tw_18_RPC.TXT"), "unexpectedly found _RPC.TXT file"
# Open the dataset, and confirm the RPC/IMD data is still intact.
ds = gdal.Open("tmp/tw_18.tif")
assert gdaltest.rpcs_equal(ds.GetMetadata("RPC"), rpc_md)
imd_md = ds.GetMetadata("IMD")
assert (
imd_md["version"] == '"R"'
and imd_md["numColumns"] == "30324"
and imd_md["IMAGE_1.sunEl"] == "39.7"
), "IMD contents wrong?"
ds = None
# Test deferred loading with GetMetadataItem()
ds = gdal.Open("tmp/tw_18.tif")
assert (
ds.GetMetadataItem("LINE_OFF", "RPC") == "16201"
), "wrong value for GetMetadataItem('LINE_OFF', 'RPC')"
assert (
ds.GetMetadataItem("version", "IMD") == '"R"'
), "wrong value for GetMetadataItem('version', 'IMD')"
ds = None
gdaltest.tiff_drv.Delete("tmp/tw_18.tif")
# Confirm IMD and RPC files are cleaned up. If not likely the
# file list functionality is not working properly.
assert not gdal.VSIStatL("tmp/tw_18.RPB"), "RPB did not get cleaned up."
assert not gdal.VSIStatL("tmp/tw_18.IMD"), "IMD did not get cleaned up."
# Remove the RPC
gdaltest.tiff_drv.CreateCopy("tmp/tw_18.tif", ds_in, options=["PROFILE=BASELINE"])
ds = gdal.Open("tmp/tw_18.tif", gdal.GA_Update)
ds.SetMetadata(None, "RPC")
ds = None
assert not os.path.exists("tmp/tw_18.RPB"), "RPB did not get removed"
gdaltest.tiff_drv.Delete("tmp/tw_18.tif")
###############################################################################
# Test writing a IMD files with space in values
def test_tiff_write_imd_with_space_in_values():
ds = gdal.GetDriverByName("GTiff").Create("/vsimem/out.tif", 1, 1)
ds.SetMetadataItem("foo.key", "value with space", "IMD")
ds.SetMetadataItem("foo.key2", 'value with " double quote', "IMD")
ds.SetMetadataItem("foo.key3", "value with ' single quote", "IMD")
ds.SetMetadataItem("foo.key4", """value with " double and ' single quote""", "IMD")
ds.SetMetadataItem("foo.key5", "value_with_;", "IMD")
ds.SetMetadataItem("foo.key6", "regular_value", "IMD")
ds = None
f = gdal.VSIFOpenL("/vsimem/out.IMD", "rb")
assert f
data = gdal.VSIFReadL(1, 1000, f)
gdal.VSIFCloseL(f)
gdal.GetDriverByName("GTiff").Delete("/vsimem/out.tif")
assert (
data
== b'BEGIN_GROUP = foo\n\tkey = "value with space";\n\tkey2 = \'value with " double quote\';\n\tkey3 = "value with \' single quote";\n\tkey4 = "value with \'\' double and \' single quote";\n\tkey5 = "value_with_;";\n\tkey6 = regular_value;\nEND_GROUP = foo\nEND;\n'
)
###############################################################################
# Test that above test still work with the optimization in the GDAL_DISABLE_READDIR_ON_OPEN
# case (#3996)
def test_tiff_write_18_disable_readdir():
with gdal.config_option("GDAL_DISABLE_READDIR_ON_OPEN", "TRUE"):
ret = test_tiff_write_18()
return ret
###############################################################################
# Test writing a TIFF with an _RPC.TXT
def test_tiff_write_rpc_txt():
# Translate RPC controlled data to GeoTIFF.
ds_in = gdal.Open("data/rpc.vrt")
# Remove IMD before creating the TIFF to avoid creating an .IMD
# since .IMD + _RPC.TXT is an odd combination
# If the .IMD is found, we don't try reading _RPC.TXT
ds_in_without_imd = gdal.GetDriverByName("VRT").CreateCopy("", ds_in)
ds_in_without_imd.SetMetadata(None, "IMD")
rpc_md = ds_in.GetMetadata("RPC")
ds = gdaltest.tiff_drv.CreateCopy(
"tmp/tiff_write_rpc_txt.tif",
ds_in_without_imd,
options=["PROFILE=BASELINE", "RPCTXT=YES"],
)
assert gdal.GetLastErrorMsg() == ""
ds_in = None
ds = None
# Ensure there is no .aux.xml file which might hold the RPC.
try:
os.remove("tmp/tiff_write_rpc_txt.tif.aux.xml")
except OSError:
pass
# confirm there is no .RPB file created by default.
assert not os.path.exists("tmp/tiff_write_rpc_txt.RPB")
assert os.path.exists("tmp/tiff_write_rpc_txt_RPC.TXT")
# Open the dataset, and confirm the RPC data is still intact.
ds = gdal.Open("tmp/tiff_write_rpc_txt.tif")
assert gdaltest.rpcs_equal(ds.GetMetadata("RPC"), rpc_md)
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_rpc_txt.tif")
# Confirm _RPC.TXT file is cleaned up. If not likely the
# file list functionality is not working properly.
assert not os.path.exists("tmp/tiff_write_rpc_txt_RPC.TXT")
###############################################################################
# Test writing a TIFF with an RPC in .aux.xml
def test_tiff_write_rpc_in_pam():
ds_in = gdal.Open("data/rpc.vrt")
rpc_md = ds_in.GetMetadata("RPC")
ds = gdaltest.tiff_drv.CreateCopy(
"tmp/tiff_write_rpc_in_pam.tif", ds_in, options=["PROFILE=BASELINE", "RPB=NO"]
)
ds_in = None
ds = None
# Ensure there is a .aux.xml file which might hold the RPC.
try:
os.stat("tmp/tiff_write_rpc_in_pam.tif.aux.xml")
except OSError:
pytest.fail("missing .aux.xml file.")
# confirm there is no .RPB file created.
assert not os.path.exists("tmp/tiff_write_rpc_txt.RPB")
# Open the dataset, and confirm the RPC data is still intact.
ds = gdal.Open("tmp/tiff_write_rpc_in_pam.tif")
assert gdaltest.rpcs_equal(ds.GetMetadata("RPC"), rpc_md)
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_rpc_in_pam.tif")
###############################################################################
# Test the write of a pixel-interleaved image with NBITS = 7
def test_tiff_write_19():
src_ds = gdal.Open("data/contig_strip.tif")
new_ds = gdaltest.tiff_drv.CreateCopy(
"tmp/contig_strip_7.tif", src_ds, options=["NBITS=7", "INTERLEAVE=PIXEL"]
)
new_ds = None
# hopefully it's closed now!
new_ds = gdal.Open("tmp/contig_strip_7.tif")
assert (
new_ds.GetRasterBand(1).Checksum() == src_ds.GetRasterBand(1).Checksum()
and new_ds.GetRasterBand(2).Checksum() == src_ds.GetRasterBand(2).Checksum()
and new_ds.GetRasterBand(3).Checksum() == src_ds.GetRasterBand(3).Checksum()
), "Didn't get expected checksum on reopened file"
new_ds = None
src_ds = None
gdaltest.tiff_drv.Delete("tmp/contig_strip_7.tif")
###############################################################################
# Test write and read of some TIFF tags
# Also test unsetting those tags (#5619)
def test_tiff_write_20():
new_ds = gdaltest.tiff_drv.Create("tmp/tags.tif", 1, 1, 1)
values = [
("TIFFTAG_DOCUMENTNAME", "document_name"),
("TIFFTAG_IMAGEDESCRIPTION", "image_description"),
("TIFFTAG_SOFTWARE", "software"),
("TIFFTAG_DATETIME", "2009/01/01 13:01:08"),
# TODO: artitst?
("TIFFTAG_ARTIST", "artitst"),
("TIFFTAG_HOSTCOMPUTER", "host_computer"),
("TIFFTAG_COPYRIGHT", "copyright"),
("TIFFTAG_XRESOLUTION", "100"),
("TIFFTAG_YRESOLUTION", "101"),
("TIFFTAG_RESOLUTIONUNIT", "2 (pixels/inch)"),
("TIFFTAG_MINSAMPLEVALUE", "1"),
("TIFFTAG_MAXSAMPLEVALUE", "2"),
]
new_ds.SetMetadata(dict(values))
new_ds = None
# hopefully it's closed now!
assert not os.path.exists("tmp/tags.tif.aux.xml")
new_ds = gdal.Open("tmp/tags.tif")
md = new_ds.GetMetadata()
for item in values:
assert item[0] in md, "Could not find tag %s" % (item[0])
assert md[item[0]] == item[1], "For tag %s, got %s, expected %s" % (
item[0],
md[item[0]],
item[1],
)
new_ds = None
# Test just unsetting once, but leaving other unchanged
ds = gdal.Open("tmp/tags.tif", gdal.GA_Update)
ds.SetMetadataItem("TIFFTAG_SOFTWARE", None)
ds = None
assert not os.path.exists("tmp/tags.tif.aux.xml")
ds = gdal.Open("tmp/tags.tif")
assert (
ds.GetMetadataItem("TIFFTAG_SOFTWARE") is None
), "expected unset TIFFTAG_SOFTWARE but got %s" % ds.GetMetadataItem(
"TIFFTAG_SOFTWARE"
)
assert (
ds.GetMetadataItem("TIFFTAG_DOCUMENTNAME") is not None
), "expected set TIFFTAG_DOCUMENTNAME but got None"
ds = None
# Test unsetting all the remaining items
ds = gdal.Open("tmp/tags.tif", gdal.GA_Update)
ds.SetMetadata({})
ds = None
ds = gdal.Open("tmp/tags.tif")
got_md = ds.GetMetadata()
ds = None
assert got_md == {}, "expected empty metadata list, but got some"
gdaltest.tiff_drv.Delete("tmp/tags.tif")
###############################################################################
# Test RGBA images with TIFFTAG_EXTRASAMPLES=EXTRASAMPLE_ASSOCALPHA
def test_tiff_write_21():
src_ds = gdal.Open("data/stefan_full_rgba.tif")
new_ds = gdaltest.tiff_drv.CreateCopy("tmp/stefan_full_rgba.tif", src_ds)
new_ds = None
new_ds = gdal.Open("tmp/stefan_full_rgba.tif")
assert new_ds.RasterCount == 4
for i in range(4):
assert (
new_ds.GetRasterBand(i + 1).GetRasterColorInterpretation()
== src_ds.GetRasterBand(i + 1).GetRasterColorInterpretation()
)
assert (
new_ds.GetRasterBand(i + 1).Checksum()
== src_ds.GetRasterBand(i + 1).Checksum()
)
new_ds = None
src_ds = None
gdaltest.tiff_drv.Delete("tmp/stefan_full_rgba.tif")
###############################################################################
# Test RGBA images with TIFFTAG_EXTRASAMPLES=EXTRASAMPLE_UNSPECIFIED
def test_tiff_write_22():
src_ds = gdal.Open("data/stefan_full_rgba_photometric_rgb.tif")
new_ds = gdaltest.tiff_drv.CreateCopy(
"tmp/stefan_full_rgba_photometric_rgb.tif", src_ds, options=["PHOTOMETRIC=RGB"]
)
new_ds = None
new_ds = gdal.Open("tmp/stefan_full_rgba_photometric_rgb.tif")
assert new_ds.RasterCount == 4
for i in range(4):
assert (
new_ds.GetRasterBand(i + 1).GetRasterColorInterpretation()
== src_ds.GetRasterBand(i + 1).GetRasterColorInterpretation()
)
assert (
new_ds.GetRasterBand(i + 1).Checksum()
== src_ds.GetRasterBand(i + 1).Checksum()
)
new_ds = None
src_ds = None
gdaltest.tiff_drv.Delete("tmp/stefan_full_rgba_photometric_rgb.tif")
###############################################################################
# Test grey+alpha images with ALPHA=YES
def test_tiff_write_23():
src_ds = gdal.Open("data/stefan_full_greyalpha.tif")
new_ds = gdaltest.tiff_drv.CreateCopy(
"tmp/stefan_full_greyalpha.tif", src_ds, options=["ALPHA=YES"]
)
new_ds = None
new_ds = gdal.Open("tmp/stefan_full_greyalpha.tif")
assert new_ds.RasterCount == 2
for i in range(2):
assert (
new_ds.GetRasterBand(i + 1).GetRasterColorInterpretation()
== src_ds.GetRasterBand(i + 1).GetRasterColorInterpretation()
)
assert (
new_ds.GetRasterBand(i + 1).Checksum()
== src_ds.GetRasterBand(i + 1).Checksum()
)
new_ds = None
src_ds = None
gdaltest.tiff_drv.Delete("tmp/stefan_full_greyalpha.tif")
###############################################################################
# Test grey+alpha images without ALPHA=YES
def test_tiff_write_24():
src_ds = gdal.Open("data/stefan_full_greyalpha.tif")
new_ds = gdaltest.tiff_drv.CreateCopy("tmp/stefan_full_greyunspecified.tif", src_ds)
new_ds = None
new_ds = gdal.Open("tmp/stefan_full_greyunspecified.tif")
assert new_ds.RasterCount == 2
for i in range(2):
assert (
new_ds.GetRasterBand(i + 1).GetRasterColorInterpretation()
== src_ds.GetRasterBand(i + 1).GetRasterColorInterpretation()
)
assert (
new_ds.GetRasterBand(i + 1).Checksum()
== src_ds.GetRasterBand(i + 1).Checksum()
)
new_ds = None
src_ds = None
gdaltest.tiff_drv.Delete("tmp/stefan_full_greyunspecified.tif")
###############################################################################
# Read a CIELAB image to test the RGBA image TIFF interface
def test_tiff_write_25():
src_ds = gdal.Open("data/cielab.tif")
assert src_ds.RasterCount == 4
assert src_ds.GetRasterBand(1).Checksum() == 6
assert src_ds.GetRasterBand(2).Checksum() == 3
assert src_ds.GetRasterBand(3).Checksum() == 0
assert src_ds.GetRasterBand(4).Checksum() == 3
assert src_ds.GetRasterBand(1).GetRasterColorInterpretation() == gdal.GCI_RedBand
assert src_ds.GetRasterBand(2).GetRasterColorInterpretation() == gdal.GCI_GreenBand
assert src_ds.GetRasterBand(3).GetRasterColorInterpretation() == gdal.GCI_BlueBand
assert src_ds.GetRasterBand(4).GetRasterColorInterpretation() == gdal.GCI_AlphaBand
src_ds = None
###############################################################################
# Test color table in a 8 bit image
def test_tiff_write_26():
ds = gdaltest.tiff_drv.Create("tmp/ct8.tif", 1, 1, 1, gdal.GDT_Byte)
ct = gdal.ColorTable()
ct.SetColorEntry(0, (255, 255, 255, 255))
ct.SetColorEntry(1, (255, 255, 0, 255))
ct.SetColorEntry(2, (255, 0, 255, 255))
ct.SetColorEntry(3, (0, 255, 255, 255))
ds.GetRasterBand(1).SetRasterColorTable(ct)
ct = None
ds = None
ds = gdal.Open("tmp/ct8.tif")
ct = ds.GetRasterBand(1).GetRasterColorTable()
assert (
ct.GetCount() == 256
and ct.GetColorEntry(0) == (255, 255, 255, 255)
and ct.GetColorEntry(1) == (255, 255, 0, 255)
and ct.GetColorEntry(2) == (255, 0, 255, 255)
and ct.GetColorEntry(3) == (0, 255, 255, 255)
), "Wrong color table entry."
ct = None
ds = None
gdaltest.tiff_drv.Delete("tmp/ct8.tif")
###############################################################################
# Test color table in a 16 bit image
def test_tiff_write_27():
ds = gdaltest.tiff_drv.Create("tmp/ct16.tif", 1, 1, 1, gdal.GDT_UInt16)
ct = gdal.ColorTable()
ct.SetColorEntry(0, (255, 255, 255, 255))
ct.SetColorEntry(1, (255, 255, 0, 255))
ct.SetColorEntry(2, (255, 0, 255, 255))
ct.SetColorEntry(3, (0, 255, 255, 255))
ds.GetRasterBand(1).SetRasterColorTable(ct)
ct = None
ds = None
ds = gdal.Open("tmp/ct16.tif")
new_ds = gdaltest.tiff_drv.CreateCopy("tmp/ct16_copy.tif", ds)
del new_ds
ds = None
ds = gdal.Open("tmp/ct16_copy.tif")
ct = ds.GetRasterBand(1).GetRasterColorTable()
assert (
ct.GetCount() == 65536
and ct.GetColorEntry(0) == (255, 255, 255, 255)
and ct.GetColorEntry(1) == (255, 255, 0, 255)
and ct.GetColorEntry(2) == (255, 0, 255, 255)
and ct.GetColorEntry(3) == (0, 255, 255, 255)
), "Wrong color table entry."
ct = None
ds = None
gdaltest.tiff_drv.Delete("tmp/ct16.tif")
gdaltest.tiff_drv.Delete("tmp/ct16_copy.tif")
###############################################################################
# Test SetRasterColorInterpretation on a 2 channel image
def test_tiff_write_28():
ds = gdaltest.tiff_drv.Create("tmp/greyalpha.tif", 1, 1, 2)
assert ds.GetRasterBand(2).GetRasterColorInterpretation() == gdal.GCI_Undefined
ds.GetRasterBand(2).SetRasterColorInterpretation(gdal.GCI_AlphaBand)
assert ds.GetRasterBand(2).GetRasterColorInterpretation() == gdal.GCI_AlphaBand
ds = None
ds = gdal.Open("tmp/greyalpha.tif")
assert ds.GetRasterBand(2).GetRasterColorInterpretation() == gdal.GCI_AlphaBand
ds = None
gdaltest.tiff_drv.Delete("tmp/greyalpha.tif")
###############################################################################
# Test SetRasterColorInterpretation on a 4 channel image
def test_tiff_write_29():
# When creating a 4 channel image with PHOTOMETRIC=RGB,
# TIFFTAG_EXTRASAMPLES=EXTRASAMPLE_UNSPECIFIED
ds = gdaltest.tiff_drv.Create(
"/vsimem/rgba.tif", 1, 1, 4, options=["PHOTOMETRIC=RGB"]
)
assert ds.GetMetadataItem("TIFFTAG_EXTRASAMPLES", "_DEBUG_") == "0"
assert ds.GetRasterBand(4).GetRasterColorInterpretation() == gdal.GCI_Undefined
# Now turn on alpha
ds.GetRasterBand(4).SetRasterColorInterpretation(gdal.GCI_AlphaBand)
assert ds.GetRasterBand(4).GetRasterColorInterpretation() == gdal.GCI_AlphaBand
assert ds.GetMetadataItem("TIFFTAG_EXTRASAMPLES", "_DEBUG_") == "2"
ds = None
assert gdal.VSIStatL("/vsimem/rgba.tif.aux.xml") is None
ds = gdal.Open("/vsimem/rgba.tif")
assert ds.GetMetadataItem("TIFFTAG_EXTRASAMPLES", "_DEBUG_") == "2"
assert ds.GetRasterBand(4).GetRasterColorInterpretation() == gdal.GCI_AlphaBand
# Test cancelling alpha
gdaltest.tiff_drv.CreateCopy("/vsimem/rgb_no_alpha.tif", ds, options=["ALPHA=NO"])
ds = None
assert gdal.VSIStatL("/vsimem/rgb_no_alpha.tif.aux.xml") is None
ds = gdal.Open("/vsimem/rgb_no_alpha.tif")
assert ds.GetMetadataItem("TIFFTAG_EXTRASAMPLES", "_DEBUG_") == "0"
assert ds.GetRasterBand(4).GetRasterColorInterpretation() == gdal.GCI_Undefined
# Test re-adding alpha
gdaltest.tiff_drv.CreateCopy(
"/vsimem/rgb_added_alpha.tif", ds, options=["ALPHA=YES"]
)
ds = None
assert gdal.VSIStatL("/vsimem/rgb_added_alpha.tif.aux.xml") is None
ds = gdal.Open("/vsimem/rgb_added_alpha.tif")
assert ds.GetMetadataItem("TIFFTAG_EXTRASAMPLES", "_DEBUG_") == "2"
assert ds.GetRasterBand(4).GetRasterColorInterpretation() == gdal.GCI_AlphaBand
ds = None
gdaltest.tiff_drv.Delete("/vsimem/rgba.tif")
gdaltest.tiff_drv.Delete("/vsimem/rgb_no_alpha.tif")
gdaltest.tiff_drv.Delete("/vsimem/rgb_added_alpha.tif")
###############################################################################
# Create a BigTIFF image with BigTIFF=YES
def test_tiff_write_30():
ds = gdaltest.tiff_drv.Create("tmp/bigtiff.tif", 1, 1, 1, options=["BigTIFF=YES"])
ds = None
ds = gdal.Open("tmp/bigtiff.tif")
assert ds is not None
ds = None
fileobj = open("tmp/bigtiff.tif", mode="rb")
binvalues = struct.unpack("B" * 4, fileobj.read(4))
fileobj.close()
gdaltest.tiff_drv.Delete("tmp/bigtiff.tif")
# Check BigTIFF signature
assert not (
(binvalues[2] != 0x2B or binvalues[3] != 0)
and (binvalues[3] != 0x2B or binvalues[2] != 0)
)
###############################################################################
# Create a BigTIFF image implicitly (more than 4Gb).
def test_tiff_write_31():
ds = gdaltest.tiff_drv.Create(
"tmp/bigtiff.tif", 100000, 100000, 1, options=["SPARSE_OK=TRUE"]
)
ds = None
ds = gdal.Open("tmp/bigtiff.tif")
assert ds is not None
ds = None
fileobj = open("tmp/bigtiff.tif", mode="rb")
binvalues = struct.unpack("B" * 4, fileobj.read(4))
fileobj.close()
gdaltest.tiff_drv.Delete("tmp/bigtiff.tif")
# Check BigTIFF signature
assert not (
(binvalues[2] != 0x2B or binvalues[3] != 0)
and (binvalues[3] != 0x2B or binvalues[2] != 0)
)
###############################################################################
# Create a rotated image
def test_tiff_write_32():
ds_in = gdal.Open("data/byte.vrt")
# Test creation
ds = gdaltest.tiff_drv.Create("tmp/byte_rotated.tif", 20, 20, gdal.GDT_Byte)
gt = (10, 3.53553390593, 3.53553390593, 30, 3.53553390593, -3.53553390593)
ds.SetGeoTransform(gt)
data = ds_in.ReadRaster(0, 0, 20, 20)
ds.WriteRaster(0, 0, 20, 20, data)
ds_in = None
# Test copy
new_ds = gdaltest.tiff_drv.CreateCopy("tmp/byte_rotated_copy.tif", ds)
del new_ds
# Check copy
ds = gdal.Open("tmp/byte_rotated_copy.tif")
new_gt = ds.GetGeoTransform()
for i in range(6):
if new_gt[i] != pytest.approx(gt[i], abs=1e-5):
print("")
print(("old = ", gt))
print(("new = ", new_gt))
pytest.fail("Geotransform differs.")
ds = None
gdaltest.tiff_drv.Delete("tmp/byte_rotated.tif")
gdaltest.tiff_drv.Delete("tmp/byte_rotated_copy.tif")
###############################################################################
# Test that metadata is written in .aux.xml file in GeoTIFF profile with CreateCopy
# (BASELINE is tested by tiff_write_15)
def test_tiff_write_33():
ds_in = gdal.Open("data/byte.vrt")
ds = gdaltest.tiff_drv.CreateCopy(
"tmp/tw_33.tif", ds_in, options=["PROFILE=GeoTIFF"]
)
ds_in = None
ds = None
ds = gdal.Open("tmp/tw_33.tif")
md = ds.GetMetadata()
assert "test" in md, "Metadata absent from .aux.xml file."
md = ds.GetRasterBand(1).GetMetadata()
assert "testBand" in md, "Metadata absent from .aux.xml file."
ds = None
try:
os.remove("tmp/tw_33.tif.aux.xml")
except OSError:
try:
os.stat("tmp/tw_33.tif.aux.xml")
except OSError:
pytest.fail("No .aux.xml file.")
ds = gdal.Open("tmp/tw_33.tif")
md = ds.GetMetadata()
assert "test" not in md, "Metadata written to GeoTIFF file."
md = ds.GetRasterBand(1).GetMetadata()
assert "testBand" not in md, "Metadata written to GeoTIFF file."
ds = None
gdaltest.tiff_drv.Delete("tmp/tw_33.tif")
###############################################################################
# Test that metadata is written in .aux.xml file in GeoTIFF profile with Create
# (BASELINE is tested by tiff_write_16)
def test_tiff_write_34():
ds = gdaltest.tiff_drv.Create(
"tmp/tw_34.tif", 1, 1, gdal.GDT_Byte, options=["PROFILE=GeoTIFF"]
)
ds.SetMetadata({"test": "testvalue"})
ds.GetRasterBand(1).SetMetadata({"testBand": "testvalueBand"})
ds = None
ds = gdal.Open("tmp/tw_34.tif")
md = ds.GetMetadata()
assert "test" in md, "Metadata absent from .aux.xml file."
md = ds.GetRasterBand(1).GetMetadata()
assert "testBand" in md, "Metadata absent from .aux.xml file."
ds = None
try:
os.remove("tmp/tw_34.tif.aux.xml")
except OSError:
try:
os.stat("tmp/tw_34.tif.aux.xml")
except OSError:
pytest.fail("No .aux.xml file.")
ds = gdal.Open("tmp/tw_34.tif")
md = ds.GetMetadata()
assert "test" not in md, "Metadata written to GeoTIFF file."
md = ds.GetRasterBand(1).GetMetadata()
assert "testBand" not in md, "Metadata written to GeoTIFF file."
ds = None
gdaltest.tiff_drv.Delete("tmp/tw_34.tif")
###############################################################################
# Test big metadata (that was used to consider too big to fit into the GDALGeotiff tag
# before GDAL 3.4.2)
def test_tiff_write_35():
big_string = "a" * 12345678
ds = gdaltest.tiff_drv.Create("tmp/tw_35.tif", 1, 1, gdal.GDT_Byte)
md = {}
md["test"] = big_string
ds.SetMetadata(md)
ds = None
assert not os.path.exists("tmp/tw_35.tif.aux.xml")
ds = gdal.Open("tmp/tw_35.tif")
assert ds.GetMetadataItem("test") == big_string
ds = None
gdaltest.tiff_drv.Delete("tmp/tw_35.tif")
###############################################################################
# Generic functions for the 8 following tests
def tiff_write_big_odd_bits(vrtfilename, tmpfilename, nbits, interleaving):
ds_in = gdal.Open(vrtfilename)
ds = gdaltest.tiff_drv.CreateCopy(
tmpfilename,
ds_in,
options=["NBITS=" + str(nbits), "INTERLEAVE=" + interleaving],
)
ds_in = None
ds = None
ds = gdal.Open(tmpfilename)
bnd = ds.GetRasterBand(1)
cs = bnd.Checksum()
assert cs == 4672, "Didn't get expected checksum on band 1"
md = bnd.GetMetadata("IMAGE_STRUCTURE")
assert md["NBITS"] == str(nbits), "Didn't get expected NBITS value"
bnd = ds.GetRasterBand(2)
assert bnd.Checksum() == 4672, "Didn't get expected checksum on band 2"
bnd = ds.GetRasterBand(3)
assert bnd.Checksum() == 4672, "Didn't get expected checksum on band 3"
bnd = None
md = ds.GetMetadata("IMAGE_STRUCTURE")
assert md["INTERLEAVE"] == interleaving, "Didn't get expected interleaving"
ds = None
gdaltest.tiff_drv.Delete(tmpfilename)
###############################################################################
# Test copy with NBITS=9, INTERLEAVE=PIXEL
def test_tiff_write_36():
return tiff_write_big_odd_bits("data/uint16_3band.vrt", "tmp/tw_36.tif", 9, "PIXEL")
###############################################################################
# Test copy with NBITS=9, INTERLEAVE=BAND
def test_tiff_write_37():
return tiff_write_big_odd_bits("data/uint16_3band.vrt", "tmp/tw_37.tif", 9, "BAND")
###############################################################################
# Test copy with NBITS=12, INTERLEAVE=PIXEL
def test_tiff_write_38():
return tiff_write_big_odd_bits(
"data/uint16_3band.vrt", "tmp/tw_38.tif", 12, "PIXEL"
)
###############################################################################
# Test copy with NBITS=12, INTERLEAVE=BAND
def test_tiff_write_39():
return tiff_write_big_odd_bits("data/uint16_3band.vrt", "tmp/tw_39.tif", 12, "BAND")
###############################################################################
# Test copy with NBITS=17, INTERLEAVE=PIXEL
def test_tiff_write_40():
return tiff_write_big_odd_bits("data/uint32_3band.vrt", "tmp/tw_40tif", 17, "PIXEL")
###############################################################################
# Test copy with NBITS=17, INTERLEAVE=BAND
def test_tiff_write_41():
return tiff_write_big_odd_bits("data/uint32_3band.vrt", "tmp/tw_41.tif", 17, "BAND")
###############################################################################
# Test copy with NBITS=24, INTERLEAVE=PIXEL
def test_tiff_write_42():
return tiff_write_big_odd_bits(
"data/uint32_3band.vrt", "tmp/tw_42.tif", 24, "PIXEL"
)
###############################################################################
# Test copy with NBITS=24, INTERLEAVE=BAND
def test_tiff_write_43():
return tiff_write_big_odd_bits("data/uint32_3band.vrt", "tmp/tw_43.tif", 24, "BAND")
###############################################################################
# Test create with NBITS=9 and preservation through CreateCopy of NBITS
def test_tiff_write_44():
ds = gdaltest.tiff_drv.Create(
"tmp/tw_44.tif", 1, 1, 1, gdal.GDT_UInt16, options=["NBITS=9"]
)
ds = None
ds = gdal.Open("tmp/tw_44.tif")
bnd = ds.GetRasterBand(1)
md = bnd.GetMetadata("IMAGE_STRUCTURE")
bnd = None
assert md["NBITS"] == "9", "Didn't get expected NBITS value"
ds2 = gdaltest.tiff_drv.CreateCopy("tmp/tw_44_copy.tif", ds)
ds2 = None
ds2 = gdal.Open("tmp/tw_44_copy.tif")
bnd = ds2.GetRasterBand(1)
md = bnd.GetMetadata("IMAGE_STRUCTURE")
bnd = None
assert md["NBITS"] == "9", "Didn't get expected NBITS value"
ds = None
ds2 = None
gdaltest.tiff_drv.Delete("tmp/tw_44.tif")
gdaltest.tiff_drv.Delete("tmp/tw_44_copy.tif")
###############################################################################
# Test create with NBITS=17 and preservation through CreateCopy of NBITS
def test_tiff_write_45():
ds = gdaltest.tiff_drv.Create(
"tmp/tw_45.tif", 1, 1, 1, gdal.GDT_UInt32, options=["NBITS=17"]
)
ds = None
ds = gdal.Open("tmp/tw_45.tif")
bnd = ds.GetRasterBand(1)
md = bnd.GetMetadata("IMAGE_STRUCTURE")
bnd = None
assert md["NBITS"] == "17", "Didn't get expected NBITS value"
ds2 = gdaltest.tiff_drv.CreateCopy("tmp/tw_45_copy.tif", ds)
ds2 = None
ds2 = gdal.Open("tmp/tw_45_copy.tif")
bnd = ds2.GetRasterBand(1)
md = bnd.GetMetadata("IMAGE_STRUCTURE")
bnd = None
assert md["NBITS"] == "17", "Didn't get expected NBITS value"
ds = None
ds2 = None
gdaltest.tiff_drv.Delete("tmp/tw_45.tif")
gdaltest.tiff_drv.Delete("tmp/tw_45_copy.tif")
###############################################################################
# Test correct round-tripping of ReadBlock/WriteBlock
def test_tiff_write_46():
with gdaltest.SetCacheMax(0):
ds = gdaltest.tiff_drv.Create(
"tmp/tiff_write_46_1.tif", 10, 10, 1, options=["NBITS=1"]
)
ds.GetRasterBand(1).Fill(0)
ds2 = gdaltest.tiff_drv.Create(
"tmp/tiff_write_46_2.tif", 10, 10, 1, options=["NBITS=1"]
)
ds2.GetRasterBand(1).Fill(1)
ones = ds2.ReadRaster(0, 0, 10, 1)
# Load the working block
data = ds.ReadRaster(0, 0, 10, 1)
# Write the working bloc
ds.WriteRaster(0, 0, 10, 1, ones)
# This will discard the cached block for ds
ds3 = gdaltest.tiff_drv.Create("tmp/tiff_write_46_3.tif", 10, 10, 1)
ds3.GetRasterBand(1).Fill(1)
# Load the working block again
data = ds.ReadRaster(0, 0, 10, 1)
# We expect (1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
got = struct.unpack("B" * 10, data)
for g in got:
assert g == 1, got
ds = None
ds2 = None
ds3 = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_46_1.tif")
gdaltest.tiff_drv.Delete("tmp/tiff_write_46_2.tif")
gdaltest.tiff_drv.Delete("tmp/tiff_write_46_3.tif")
###############################################################################
# Test #2457
def test_tiff_write_47():
with gdaltest.SetCacheMax(0):
ret = test_tiff_write_3()
return ret
###############################################################################
# Test #2457 with nYOff of RasterIO not aligned on the block height
def test_tiff_write_48():
with gdaltest.SetCacheMax(0):
src_ds = gdal.Open("data/utmsmall.tif")
new_ds = gdal.GetDriverByName("GTiff").Create(
"tmp/tiff_write_48.tif",
100,
100,
1,
options=["TILED=YES", "BLOCKXSIZE=96", "BLOCKYSIZE=96"],
)
data = src_ds.ReadRaster(0, 0, 100, 1)
data2 = src_ds.ReadRaster(0, 1, 100, 99)
new_ds.WriteRaster(0, 1, 100, 99, data2)
new_ds.WriteRaster(0, 0, 100, 1, data)
new_ds = None
new_ds = None
new_ds = gdal.Open("tmp/tiff_write_48.tif")
assert new_ds.GetRasterBand(1).Checksum() == 50054, "Didn't get expected checksum "
new_ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_48.tif")
###############################################################################
# Test copying a CMYK TIFF into another CMYK TIFF
def test_tiff_write_49():
# We open the source as RAW to get the CMYK bands
src_ds = gdal.Open("GTIFF_RAW:data/rgbsmall_cmyk.tif")
new_ds = gdal.GetDriverByName("GTiff").CreateCopy(
"tmp/tiff_write_49.tif", src_ds, options=["PHOTOMETRIC=CMYK"]
)
# At this point, for the purpose of the copy, the dataset will have been opened as RAW
assert (
new_ds.GetRasterBand(1).GetRasterColorInterpretation() == gdal.GCI_CyanBand
), "Wrong color interpretation."
new_ds = None
new_ds = gdal.Open("GTIFF_RAW:tmp/tiff_write_49.tif")
for i in range(4):
assert (
new_ds.GetRasterBand(i + 1).Checksum()
== src_ds.GetRasterBand(i + 1).Checksum()
), "Didn't get expected checksum "
src_ds = None
new_ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_49.tif")
###############################################################################
# Test creating a CMYK TIFF from another CMYK TIFF
def test_tiff_write_50():
# We open the source as RAW to get the CMYK bands
src_ds = gdal.Open("GTIFF_RAW:data/rgbsmall_cmyk.tif")
new_ds = gdal.GetDriverByName("GTiff").Create(
"tmp/tiff_write_50.tif",
src_ds.RasterXSize,
src_ds.RasterYSize,
4,
options=["PHOTOMETRIC=CMYK"],
)
for i in range(4):
data = src_ds.GetRasterBand(i + 1).ReadRaster(
0, 0, src_ds.RasterXSize, src_ds.RasterYSize
)
new_ds.GetRasterBand(i + 1).WriteRaster(
0, 0, src_ds.RasterXSize, src_ds.RasterYSize, data
)
assert (
new_ds.GetRasterBand(1).GetRasterColorInterpretation() == gdal.GCI_CyanBand
), "Wrong color interpretation."
new_ds = None
new_ds = gdal.Open("GTIFF_RAW:tmp/tiff_write_50.tif")
for i in range(4):
assert (
new_ds.GetRasterBand(i + 1).Checksum()
== src_ds.GetRasterBand(i + 1).Checksum()
), "Didn't get expected checksum "
src_ds = None
new_ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_50.tif")
###############################################################################
# Test proper clearing of existing GeoTIFF tags when updating the projection.
# http://trac.osgeo.org/gdal/ticket/2546
def test_tiff_write_51():
shutil.copyfile("data/utmsmall.tif", "tmp/tiff_write_51.tif")
ds = gdal.Open("tmp/tiff_write_51.tif", gdal.GA_Update)
srs = osr.SpatialReference()
srs.SetFromUserInput("EPSG:32601")
ds.SetProjection(srs.ExportToWkt())
ds = None
ds = gdal.Open("tmp/tiff_write_51.tif")
wkt = ds.GetProjection()
ds = None
# Create a new GeoTIFF file with same projection
ds = gdaltest.tiff_drv.Create("tmp/tiff_write_51_ref.tif", 1, 1, 1)
ds.SetProjection(srs.ExportToWkt())
ds = None
# Read it back as the reference WKT
ds = gdal.Open("tmp/tiff_write_51_ref.tif")
expected_wkt = ds.GetProjection()
ds = None
assert (
wkt.find("NAD") == -1 and wkt.find("North Am") == -1
), "It appears the NAD27 datum was not properly cleared."
assert (
wkt == expected_wkt and wkt.find("WGS 84 / UTM zone 1N") != -1
), "coordinate system does not exactly match."
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_51.tif")
gdaltest.tiff_drv.Delete("tmp/tiff_write_51_ref.tif")
###############################################################################
# Test the ability to update a paletted TIFF files color table.
def test_tiff_write_52():
shutil.copyfile("data/test_average_palette.tif", "tmp/tiff_write_52.tif")
test_ct_data = [(255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 255, 0)]
test_ct = gdal.ColorTable()
for i, data in enumerate(test_ct_data):
test_ct.SetColorEntry(i, data)
ds = gdal.Open("tmp/tiff_write_52.tif", gdal.GA_Update)
ds.GetRasterBand(1).SetRasterColorTable(test_ct)
ds = None
ds = gdal.Open("tmp/tiff_write_52.tif")
ct = ds.GetRasterBand(1).GetRasterColorTable()
assert ct.GetColorEntry(0) == (255, 0, 0, 255), "Did not get expected color 0."
ct = None
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_52.tif")
###############################################################################
# Test the ability to create a paletted image and then update later.
def test_tiff_write_53():
test_ct_data = [(255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 255, 0)]
test_ct = gdal.ColorTable()
for i, data in enumerate(test_ct_data):
test_ct.SetColorEntry(i, data)
ds = gdaltest.tiff_drv.Create(
"tmp/tiff_write_53.tif", 30, 50, 1, options=["PHOTOMETRIC=PALETTE"]
)
ds.GetRasterBand(1).Fill(10)
ds = None
ds = gdal.Open("tmp/tiff_write_53.tif", gdal.GA_Update)
ds.GetRasterBand(1).SetRasterColorTable(test_ct)
ds = None
ds = gdal.Open("tmp/tiff_write_53.tif")
ct = ds.GetRasterBand(1).GetRasterColorTable()
assert ct.GetColorEntry(0) == (255, 0, 0, 255), "Did not get expected color 0."
ct = None
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_53.tif")
###############################################################################
# Same as before except we create an overview before reopening the file and
# adding the color table
def test_tiff_write_53_bis():
test_ct_data = [(255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 255, 0)]
test_ct = gdal.ColorTable()
for i, data in enumerate(test_ct_data):
test_ct.SetColorEntry(i, data)
ds = gdaltest.tiff_drv.Create(
"tmp/tiff_write_53_bis.tif", 30, 50, 1, options=["PHOTOMETRIC=PALETTE"]
)
ds.GetRasterBand(1).Fill(10)
ds.BuildOverviews("NONE", overviewlist=[2])
ds = None
ds = gdal.Open("tmp/tiff_write_53_bis.tif", gdal.GA_Update)
ds.GetRasterBand(1).SetRasterColorTable(test_ct)
ds = None
ds = gdal.Open("tmp/tiff_write_53_bis.tif")
ct = ds.GetRasterBand(1).GetRasterColorTable()
assert ct.GetColorEntry(0) == (255, 0, 0, 255), "Did not get expected color 0."
ct = None
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_53_bis.tif")
###############################################################################
# Test the ability to create a JPEG compressed TIFF, with PHOTOMETRIC=YCBCR
# and write data into it without closing it and re-opening it (#2645)
@pytest.mark.require_creation_option("GTiff", "JPEG")
def test_tiff_write_54():
ds = gdaltest.tiff_drv.Create(
"tmp/tiff_write_54.tif",
256,
256,
3,
options=["TILED=YES", "COMPRESS=JPEG", "PHOTOMETRIC=YCBCR"],
)
ds.GetRasterBand(1).Fill(255)
ds.FlushCache()
ds = None
ds = gdal.Open("tmp/tiff_write_54.tif")
cs = ds.GetRasterBand(1).Checksum()
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_54.tif")
assert cs != 0, "did not get expected checksum"
###############################################################################
# Test creating and reading an equirectangular file with all parameters (#2706)
def test_tiff_write_55():
ds = gdaltest.tiff_drv.Create("tmp/tiff_write_55.tif", 256, 256, 1)
srs_expected = 'PROJCS["Equirectangular Mars",GEOGCS["GCS_Mars",DATUM["unknown",SPHEROID["unnamed",3394813.85797594,0]],PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]]],PROJECTION["Equirectangular"],PARAMETER["latitude_of_origin",-2],PARAMETER["central_meridian",184.412994384766],PARAMETER["standard_parallel_1",-15],PARAMETER["false_easting",0],PARAMETER["false_northing",0],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["Easting",EAST],AXIS["Northing",NORTH]]'
ds.SetProjection(srs_expected)
ds.SetGeoTransform((100, 1, 0, 200, 0, -1))
ds = None
ds = gdal.Open("tmp/tiff_write_55.tif")
srs = ds.GetProjectionRef()
ds = None
assert (
srs == srs_expected
), "failed to preserve Equirectangular projection as expected, old libgeotiff?"
gdaltest.tiff_drv.Delete("tmp/tiff_write_55.tif")
###############################################################################
# Test clearing the colormap from an existing paletted TIFF file.
def test_tiff_write_56():
test_ct_data = [(255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 255, 0)]
test_ct = gdal.ColorTable()
for i, data in enumerate(test_ct_data):
test_ct.SetColorEntry(i, data)
ds = gdaltest.tiff_drv.Create(
"tmp/tiff_write_56.tif", 30, 50, 1, options=["PHOTOMETRIC=PALETTE"]
)
ds.GetRasterBand(1).Fill(10)
ds = None
test_ct = gdal.ColorTable()
ds = gdal.Open("tmp/tiff_write_56.tif", gdal.GA_Update)
ds.GetRasterBand(1).SetRasterColorTable(test_ct)
ds = None
ds = gdal.Open("tmp/tiff_write_56.tif")
ct = ds.GetRasterBand(1).GetRasterColorTable()
assert ct is None, "color table seemingly not cleared."
ct = None
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_56.tif")
###############################################################################
# Test replacing normal norm up georef with rotated georef (#2625)
def test_tiff_write_57():
# copy a file to tmp dir to modify.
open("tmp/tiff57.tif", "wb").write(open("data/byte.tif", "rb").read())
# open and set a non-northup geotransform.
ds = gdal.Open("tmp/tiff57.tif", gdal.GA_Update)
ds.SetGeoTransform([100, 1, 3, 200, 3, 1])
ds = None
ds = gdal.Open("tmp/tiff57.tif")
gt = ds.GetGeoTransform()
ds = None
assert gt == (
100,
1,
3,
200,
3,
1,
), "did not get expected geotransform, perhaps unset is not working?"
gdaltest.tiff_drv.Delete("tmp/tiff57.tif")
###############################################################################
# Test writing partial end strips (#2748)
def test_tiff_write_58():
md = gdaltest.tiff_drv.GetMetadata()
for compression in ("NONE", "JPEG", "LZW", "DEFLATE", "PACKBITS"):
if md["DMD_CREATIONOPTIONLIST"].find(compression) != -1:
ds = gdaltest.tiff_drv.Create(
"tmp/tiff_write_58.tif", 4, 4000, 1, options=["COMPRESS=" + compression]
)
ds.GetRasterBand(1).Fill(255)
ds = None
ds = gdal.Open("tmp/tiff_write_58.tif")
assert ds.GetRasterBand(1).Checksum() == 65241, "wrong checksum"
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_58.tif")
else:
print(("Skipping compression method %s" % compression))
###############################################################################
# Test fix for #2759
def test_tiff_write_59():
for nbands in (1, 2):
for nbits in (1, 8, 9, 12, 16, 17, 24, 32):
if nbits <= 8:
gdal_type = gdal.GDT_Byte
ctype = "B"
elif nbits <= 16:
gdal_type = gdal.GDT_UInt16
ctype = "h"
else:
gdal_type = gdal.GDT_UInt32
ctype = "i"
ds = gdaltest.tiff_drv.Create(
"tmp/tiff_write_59.tif",
10,
10,
nbands,
gdal_type,
options=["NBITS=%d" % nbits],
)
ds.GetRasterBand(1).Fill(1)
ds = None
ds = gdal.Open("tmp/tiff_write_59.tif", gdal.GA_Update)
data = struct.pack(ctype * 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
ds.GetRasterBand(1).WriteRaster(0, 0, 10, 1, data)
ds = None
ds = gdal.Open("tmp/tiff_write_59.tif")
data = ds.GetRasterBand(1).ReadRaster(0, 0, 10, 1)
# We expect zeros
got = struct.unpack(ctype * 10, data)
for g in got:
assert g == 0, (nbands, nbits)
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_59.tif")
###############################################################################
# Test fix for #2760
def test_tiff_write_60():
tuples = [
("TFW=YES", "tmp/tiff_write_60.tfw"),
("WORLDFILE=YES", "tmp/tiff_write_60.wld"),
]
for options_tuple in tuples:
# Create case
with gdaltest.error_handler():
ds = gdaltest.tiff_drv.Create(
"tmp/tiff_write_60.tif",
10,
10,
options=[options_tuple[0], "PROFILE=BASELINE"],
)
gt = (0.0, 1.0, 0.0, 50.0, 0.0, -1.0)
ds.SetGeoTransform(gt)
ds = None
with gdaltest.error_handler():
ds = gdal.Open("tmp/tiff_write_60.tif")
assert ds.GetGeoTransform() == gt, "case1: %s != %s" % (
ds.GetGeoTransform(),
gt,
)
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_60.tif")
assert not os.path.exists(options_tuple[1])
# CreateCopy case
src_ds = gdal.Open("data/byte.tif")
with gdaltest.error_handler():
ds = gdaltest.tiff_drv.CreateCopy(
"tmp/tiff_write_60.tif",
src_ds,
options=[options_tuple[0], "PROFILE=BASELINE"],
)
gt = (0.0, 1.0, 0.0, 50.0, 0.0, -1.0)
ds.SetGeoTransform(gt)
ds = None
gdal.Unlink("tmp/tiff_write_60.tif.aux.xml")
ds = gdal.Open("tmp/tiff_write_60.tif")
assert ds.GetGeoTransform() == gt, "case2: %s != %s" % (
ds.GetGeoTransform(),
gt,
)
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_60.tif")
assert not os.path.exists(options_tuple[1])
###############################################################################
# Test BigTIFF=IF_NEEDED creation option
def test_tiff_write_61():
ds = gdaltest.tiff_drv.Create(
"tmp/bigtiff.tif",
50000,
50000,
1,
options=["BIGTIFF=IF_NEEDED", "SPARSE_OK=TRUE"],
)
ds = None
ds = gdal.Open("tmp/bigtiff.tif")
assert ds is not None
ds = None
fileobj = open("tmp/bigtiff.tif", mode="rb")
binvalues = struct.unpack("B" * 4, fileobj.read(4))
fileobj.close()
gdaltest.tiff_drv.Delete("tmp/bigtiff.tif")
# Check classical TIFF signature
assert not (
(binvalues[2] != 0x2A or binvalues[3] != 0)
and (binvalues[3] != 0x2A or binvalues[2] != 0)
)
###############################################################################
# Test BigTIFF=IF_SAFER creation option
def test_tiff_write_62():
ds = gdaltest.tiff_drv.Create(
"tmp/bigtiff.tif",
50000,
50000,
1,
options=["BIGTIFF=IF_SAFER", "SPARSE_OK=TRUE"],
)
ds = None
ds = gdal.Open("tmp/bigtiff.tif")
assert ds is not None
ds = None
fileobj = open("tmp/bigtiff.tif", mode="rb")
binvalues = struct.unpack("B" * 4, fileobj.read(4))
fileobj.close()
gdaltest.tiff_drv.Delete("tmp/bigtiff.tif")
# Check BigTIFF signature
assert not (
(binvalues[2] != 0x2B or binvalues[3] != 0)
and (binvalues[3] != 0x2B or binvalues[2] != 0)
)
###############################################################################
# Test BigTIFF=NO creation option when creating a BigTIFF file would be required
def test_tiff_write_63():
with gdaltest.error_handler():
ds = gdaltest.tiff_drv.Create(
"tmp/bigtiff.tif", 150000, 150000, 1, options=["BIGTIFF=NO"]
)
if ds is None:
return
pytest.fail()
###############################################################################
# Test returned projection in WKT format for a WGS84 GeoTIFF (#2787)
def test_tiff_write_64():
ds = gdaltest.tiff_drv.Create("tmp/tiff_write_64.tif", 1, 1, 1)
srs = osr.SpatialReference()
srs.SetFromUserInput("WGS84")
srs.SetAxisMappingStrategy(osr.OAMS_TRADITIONAL_GIS_ORDER)
ds.SetSpatialRef(srs)
ds = None
ds = gdal.Open("tmp/tiff_write_64.tif")
got_srs = ds.GetSpatialRef()
assert got_srs.IsSame(srs)
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_64.tif")
###############################################################################
# Verify that we can write XML metadata.
def test_tiff_write_65():
ds = gdaltest.tiff_drv.Create("tmp/tiff_write_65.tif", 10, 10)
doc = '<doc><test xml:attr="abc"/></doc>'
ds.SetMetadata([doc], "xml:test")
ds = None
ds = gdal.Open("tmp/tiff_write_65.tif")
md = ds.GetMetadata("xml:test")
ds = None
assert len(md) == 1 and md[0] == doc, "did not get xml back clean"
gdaltest.tiff_drv.Delete("tmp/tiff_write_65.tif")
###############################################################################
# Verify that we can write and read a band-interleaved GeoTIFF with 65535 bands (#2838)
def test_tiff_write_66():
if gdal.GetConfigOption("SKIP_MEM_INTENSIVE_TEST") is not None:
pytest.skip()
ds = gdaltest.tiff_drv.Create(
"tmp/tiff_write_66.tif", 1, 1, 65535, options=["INTERLEAVE=BAND"]
)
ds = None
ds = gdal.Open("tmp/tiff_write_66.tif")
assert ds.RasterCount == 65535
assert ds.GetRasterBand(1).Checksum() == 0
assert ds.GetRasterBand(65535).Checksum() == 0
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_66.tif")
###############################################################################
# Verify that we can write and read a pixel-interleaved GeoTIFF with 65535 bands (#2838)
def test_tiff_write_67():
if gdal.GetConfigOption("SKIP_MEM_INTENSIVE_TEST") is not None:
pytest.skip()
ds = gdaltest.tiff_drv.Create(
"tmp/tiff_write_67.tif", 1, 1, 65535, options=["INTERLEAVE=PIXEL"]
)
ds = None
ds = gdal.Open("tmp/tiff_write_67.tif")
assert ds.RasterCount == 65535
assert ds.GetRasterBand(1).Checksum() == 0
assert ds.GetRasterBand(65535).Checksum() == 0
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_67.tif")
###############################################################################
# Verify that we can set the color table after a Create() (scenario hit by map.tif in #2820)
def test_tiff_write_68():
ds = gdaltest.tiff_drv.Create(
"tmp/tiff_write_68.tif", 151, 161, options=["COMPRESS=LZW"]
)
ct = gdal.ColorTable()
ct.SetColorEntry(0, (255, 255, 255, 255))
ct.SetColorEntry(1, (255, 255, 0, 255))
ct.SetColorEntry(2, (255, 0, 255, 255))
ct.SetColorEntry(3, (0, 255, 255, 255))
ds.GetRasterBand(1).SetRasterColorTable(ct)
ds.GetRasterBand(1).Fill(255)
ds = None
ds = gdal.Open("tmp/tiff_write_68.tif")
assert ds.GetRasterBand(1).Checksum() != 0
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_68.tif")
###############################################################################
# Verify GTiffRasterBand::NullBlock() when reading empty block without any nodata value set
def test_tiff_write_69():
ds = gdaltest.tiff_drv.Create(
"tmp/tiff_write_69.tif", 32, 32, 1, gdal.GDT_Int16, options=["SPARSE_OK=YES"]
)
ds = None
ds = gdal.Open("tmp/tiff_write_69.tif")
assert ds.GetRasterBand(1).Checksum() == 0
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_69.tif")
###############################################################################
# Verify GTiffRasterBand::NullBlock() when reading empty block with nodata value set
def test_tiff_write_70():
ref_ds = gdaltest.tiff_drv.Create(
"tmp/tiff_write_70_ref.tif", 32, 32, 1, gdal.GDT_Int16
)
ref_ds.GetRasterBand(1).Fill(-32768)
ref_ds = None
ref_ds = gdal.Open("tmp/tiff_write_70_ref.tif")
expected_cs = ref_ds.GetRasterBand(1).Checksum()
ref_ds = None
ds = gdaltest.tiff_drv.Create(
"tmp/tiff_write_70.tif", 32, 32, 1, gdal.GDT_Int16, options=["SPARSE_OK=YES"]
)
ds.GetRasterBand(1).SetNoDataValue(0)
assert (
os.stat("tmp/tiff_write_70.tif").st_size <= 8
), "directory should not be crystallized"
ds = None
ds = gdal.Open("tmp/tiff_write_70.tif", gdal.GA_Update)
ds.GetRasterBand(1).SetNoDataValue(-32768)
ds = None
ds = gdal.Open("tmp/tiff_write_70.tif")
assert ds.GetRasterBand(1).Checksum() == expected_cs, "wrong checksum"
ds = None
ds = gdal.Open("tmp/tiff_write_70.tif", gdal.GA_Update)
assert ds.GetRasterBand(1).DeleteNoDataValue() == 0
assert ds.GetRasterBand(1).GetNoDataValue() is None
ds = None
with pytest.raises(OSError):
os.stat("tmp/tiff_write_70.tif.aux.xml")
ds = gdal.Open("tmp/tiff_write_70.tif")
assert ds.GetRasterBand(1).GetNoDataValue() is None
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_70.tif")
gdaltest.tiff_drv.Delete("tmp/tiff_write_70_ref.tif")
###############################################################################
# Test reading in a real BigTIFF file (on filesystems supporting sparse files)
def test_tiff_write_71():
# Determine if the filesystem supports sparse files (we don't want to create a real 10 GB
# file !
if not gdaltest.filesystem_supports_sparse_files("tmp"):
pytest.skip()
header = open("data/bigtiff_header_extract.tif", "rb").read()
f = open("tmp/tiff_write_71.tif", "wb")
f.write(header)
# Write StripByteCounts tag
# 100,000 in little endian
for _ in range(100000):
f.write(b"\xa0\x86\x01\x00\x00\x00\x00\x00")
# Write StripOffsets tag
offset = 1600252
for _ in range(100000):
f.write(struct.pack("<Q", offset))
offset = offset + 100000
# Write 0x78 as value of pixel (99999, 99999)
f.seek(10001600252 - 1, 0)
f.write(b"\x78")
f.close()
ds = gdal.Open("tmp/tiff_write_71.tif")
data = ds.GetRasterBand(1).ReadRaster(99999, 99999, 1, 1)
assert struct.unpack("b", data)[0] == 0x78
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_71.tif")
###############################################################################
# With CreateCopy(), check that TIFF directory is in the first bytes of the file
# and has not been rewritten later (#3021)
def test_tiff_write_72():
shutil.copyfile("data/byte.tif", "tmp/byte.tif")
ds = gdal.Open("tmp/byte.tif", gdal.GA_Update)
ds.SetMetadata({"TEST_KEY": "TestValue"})
ds = None
for profile in ("GDALGeotiff", "GEOTIFF", "BASELINE"):
src_ds = gdal.Open("tmp/byte.tif")
out_ds = gdaltest.tiff_drv.CreateCopy(
"tmp/tiff_write_72.tif",
src_ds,
options=["ENDIANNESS=LITTLE", "PROFILE=" + profile],
)
del out_ds
src_ds = None
fileobj = open("tmp/tiff_write_72.tif", mode="rb")
fileobj.seek(4)
binvalues = struct.unpack("B" * 4, fileobj.read(4))
fileobj.close()
# Directory should be at offset 8 of the file
assert (
binvalues[0] == 0x08
and binvalues[1] == 0x00
and binvalues[2] == 0x00
and binvalues[3] == 0x00
), ("Failed with profile %s" % profile)
gdaltest.tiff_drv.Delete("tmp/byte.tif")
gdaltest.tiff_drv.Delete("tmp/tiff_write_72.tif")
###############################################################################
# With Create(), check that TIFF directory is in the first bytes of the file
# and has not been rewritten later (#3021)
def test_tiff_write_73():
out_ds = gdaltest.tiff_drv.Create(
"tmp/tiff_write_73.tif", 10, 10, options=["ENDIANNESS=LITTLE"]
)
out_ds.SetGeoTransform([1, 0.01, 0, 1, 0, -0.01])
srs = osr.SpatialReference()
srs.SetFromUserInput("EPSG:32601")
out_ds.SetProjection(srs.ExportToWkt())
out_ds.SetMetadata({"TEST_KEY": "TestValue"})
out_ds.BuildOverviews("NONE", [2])
out_ds.GetRasterBand(1).Fill(255)
out_ds = None
fileobj = open("tmp/tiff_write_73.tif", mode="rb")
fileobj.seek(4)
binvalues = struct.unpack("B" * 4, fileobj.read(4))
fileobj.close()
# Directory should be at offset 8 of the file
assert (
binvalues[0] == 0x08
and binvalues[1] == 0x00
and binvalues[2] == 0x00
and binvalues[3] == 0x00
)
# Re-open the file and modify the pixel content
out_ds = gdal.Open("tmp/tiff_write_73.tif", gdal.GA_Update)
out_ds.GetRasterBand(1).Fill(0)
out_ds = None
fileobj = open("tmp/tiff_write_73.tif", mode="rb")
fileobj.seek(4)
binvalues = struct.unpack("B" * 4, fileobj.read(4))
fileobj.close()
# Directory should be at offset 8 of the file
assert (
binvalues[0] == 0x08
and binvalues[1] == 0x00
and binvalues[2] == 0x00
and binvalues[3] == 0x00
)
gdaltest.tiff_drv.Delete("tmp/tiff_write_73.tif")
###############################################################################
# Verify we can write 12bit jpeg encoded tiff.
@pytest.mark.skipif(
"SKIP_TIFF_JPEG12" in os.environ, reason="Crashes on build-windows-msys2-mingw"
)
@pytest.mark.require_creation_option("GTiff", "JPEG")
def test_tiff_write_74():
with gdal.config_option("CPL_ACCUM_ERROR_MSG", "ON"):
gdal.ErrorReset()
with gdaltest.error_handler():
try:
ds = gdal.Open("data/mandrilmini_12bitjpeg.tif")
ds.GetRasterBand(1).ReadRaster(0, 0, 1, 1)
except Exception:
ds = None
if gdal.GetLastErrorMsg().find("Unsupported JPEG data precision 12") != -1:
pytest.skip("12bit jpeg not available")
for photometric in ("YCBCR", "RGB"):
drv = gdal.GetDriverByName("GTiff")
dst_ds = drv.CreateCopy(
"tmp/test_74.tif",
ds,
options=[
"COMPRESS=JPEG",
"NBITS=12",
"JPEG_QUALITY=95",
"PHOTOMETRIC=" + photometric,
],
)
dst_ds = None
dst_ds = gdal.Open("tmp/test_74.tif")
stats = dst_ds.GetRasterBand(1).GetStatistics(0, 1)
if stats[2] < 2150 or stats[2] > 2180:
print(photometric)
pytest.fail("did not get expected mean for band1.")
try:
compression = dst_ds.GetMetadataItem("COMPRESSION", "IMAGE_STRUCTURE")
except Exception:
md = dst_ds.GetMetadata("IMAGE_STRUCTURE")
compression = md["COMPRESSION"]
if (photometric == "YCBCR" and compression != "YCbCr JPEG") or (
photometric == "RGB" and compression != "JPEG"
):
print(('COMPRESSION="%s"' % compression))
pytest.fail("did not get expected COMPRESSION value")
try:
nbits = dst_ds.GetRasterBand(3).GetMetadataItem("NBITS", "IMAGE_STRUCTURE")
except Exception:
md = dst_ds.GetRasterBand(3).GetMetadata("IMAGE_STRUCTURE")
nbits = md["NBITS"]
if nbits != "12":
print(photometric)
pytest.fail("did not get expected NBITS value")
dst_ds = None
gdaltest.tiff_drv.Delete("tmp/test_74.tif")
###############################################################################
# Verify that FlushCache() alone doesn't cause crash (#3067 )
def test_tiff_write_75():
ds = gdaltest.tiff_drv.Create("tmp/tiff_write_75.tif", 1, 1, 1)
ds.FlushCache()
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_75.tif")
###############################################################################
# Test generating a G4 band to use the TIFFWriteScanline()
def test_tiff_write_76():
src_ds = gdal.Open("data/slim_g4.tif")
compression = src_ds.GetMetadata("IMAGE_STRUCTURE")["COMPRESSION"]
new_ds = gdaltest.tiff_drv.CreateCopy(
"tmp/tiff_write_76.tif",
src_ds,
options=["BLOCKYSIZE=%d" % src_ds.RasterYSize, "COMPRESS=" + compression],
)
new_ds = None
new_ds = gdal.Open("tmp/tiff_write_76.tif")
cs = new_ds.GetRasterBand(1).Checksum()
assert cs == 3322, "Got wrong checksum"
src_ds = None
new_ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_76.tif")
###############################################################################
# Test generating & reading a 8bit all-in-one-strip multiband TIFF (#3904)
def test_tiff_write_77():
src_ds = gdaltest.tiff_drv.Create("tmp/tiff_write_77_src.tif", 1, 5000, 3)
src_ds.GetRasterBand(2).Fill(255)
for interleaving in ("PIXEL", "BAND"):
new_ds = gdaltest.tiff_drv.CreateCopy(
"tmp/tiff_write_77.tif",
src_ds,
options=[
"BLOCKYSIZE=%d" % src_ds.RasterYSize,
"COMPRESS=LZW",
"INTERLEAVE=" + interleaving,
],
)
for attempt in range(2):
# Test reading a few samples to check that random reading works
band_lines = [
(1, 0),
(1, 5),
(1, 3),
(2, 10),
(1, 100),
(2, 1000),
(2, 500),
(1, 500),
(2, 500),
(2, 4999),
(2, 4999),
(3, 4999),
(1, 4999),
]
for band_line in band_lines:
cs = new_ds.GetRasterBand(band_line[0]).Checksum(0, band_line[1], 1, 1)
if band_line[0] == 2:
expected_cs = 255 % 7
else:
expected_cs = 0 % 7
assert cs == expected_cs, "Got wrong checksum"
# Test whole bands
for i in range(3):
cs = new_ds.GetRasterBand(i + 1).Checksum()
expected_cs = src_ds.GetRasterBand(i + 1).Checksum()
assert cs == expected_cs, "Got wrong checksum"
if attempt == 0:
new_ds = None
new_ds = gdal.Open("tmp/tiff_write_77.tif")
new_ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_77.tif")
src_ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_77_src.tif")
###############################################################################
# Test generating & reading a YCbCr JPEG all-in-one-strip multiband TIFF (#3259)
@pytest.mark.require_creation_option("GTiff", "JPEG")
def test_tiff_write_78():
src_ds = gdaltest.tiff_drv.Create("tmp/tiff_write_78_src.tif", 16, 2048, 3)
src_ds.GetRasterBand(2).Fill(255)
new_ds = gdaltest.tiff_drv.CreateCopy(
"tmp/tiff_write_78.tif",
src_ds,
options=[
"BLOCKYSIZE=%d" % src_ds.RasterYSize,
"COMPRESS=JPEG",
"PHOTOMETRIC=YCBCR",
],
)
# Make sure the file is flushed so that we re-read from it rather from cached blocks
new_ds.FlushCache()
# new_ds = None
# new_ds = gdal.Open('tmp/tiff_write_78.tif')
if "GetBlockSize" in dir(gdal.Band):
(_, blocky) = new_ds.GetRasterBand(1).GetBlockSize()
if blocky != 1:
print("")
print(
"using regular band (libtiff <= 3.9.2 or <= 4.0.0beta5, or SplitBand disabled by config option)"
)
# Test reading a few samples to check that random reading works
band_lines = [
(1, 0),
(1, 5),
(1, 3),
(2, 10),
(1, 100),
(2, 1000),
(2, 500),
(1, 500),
(2, 500),
(2, 2047),
(2, 2047),
(3, 2047),
(1, 2047),
]
for band_line in band_lines:
cs = new_ds.GetRasterBand(band_line[0]).Checksum(0, band_line[1], 1, 1)
if band_line[0] == 1:
expected_cs = 0 % 7
elif band_line[0] == 2:
expected_cs = 255 % 7
else:
# We should expect 0, but due to JPEG YCbCr compression & decompression,
# this ends up being 1
expected_cs = 1 % 7
if cs != expected_cs:
print(band_line)
pytest.fail("Got wrong checksum")
# Test whole bands
for i in range(3):
cs = new_ds.GetRasterBand(i + 1).Checksum()
expected_cs = src_ds.GetRasterBand(i + 1).Checksum()
if i == 2:
# We should expect 0, but due to JPEG YCbCr compression & decompression,
# this ends up being 32768
expected_cs = 32768
assert cs == expected_cs, "Got wrong checksum"
new_ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_78.tif")
src_ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_78_src.tif")
###############################################################################
# Test reading & updating GDALMD_AREA_OR_POINT (#3522)
def test_tiff_write_79():
ds = gdaltest.tiff_drv.Create("tmp/tiff_write_79.tif", 1, 1)
srs = osr.SpatialReference()
srs.SetFromUserInput("EPSG:32601")
ds.SetProjection(srs.ExportToWkt())
ds = None
for do_projection_ref in [False, True]:
for check_just_after in [False, True]:
ds = gdal.Open("tmp/tiff_write_79.tif")
if do_projection_ref:
ds.GetProjectionRef()
mdi = ds.GetMetadataItem("AREA_OR_POINT")
assert mdi == "Area", (
"(1) did not get expected value. do_projection_ref = %d, check_just_after = %d"
% (do_projection_ref, check_just_after)
)
ds = None
# Now update to 'Point'
ds = gdal.Open("tmp/tiff_write_79.tif", gdal.GA_Update)
if do_projection_ref:
ds.GetProjectionRef()
ds.SetMetadataItem("AREA_OR_POINT", "Point")
if check_just_after:
mdi = ds.GetMetadataItem("AREA_OR_POINT")
assert mdi == "Point", (
"(3) did not get expected value. do_projection_ref = %d, check_just_after = %d"
% (do_projection_ref, check_just_after)
)
ds = None
assert not os.path.exists("tmp/tiff_write_79.tif.aux.xml")
# Now should get 'Point'
ds = gdal.Open("tmp/tiff_write_79.tif")
if do_projection_ref:
ds.GetProjectionRef()
mdi = ds.GetMetadataItem("AREA_OR_POINT")
assert mdi == "Point", (
"(4) did not get expected value. do_projection_ref = %d, check_just_after = %d"
% (do_projection_ref, check_just_after)
)
ds = None
# Now update back to 'Area' through SetMetadata()
ds = gdal.Open("tmp/tiff_write_79.tif", gdal.GA_Update)
if do_projection_ref:
ds.GetProjectionRef()
md = {}
md["AREA_OR_POINT"] = "Area"
ds.SetMetadata(md)
if check_just_after:
mdi = ds.GetMetadataItem("AREA_OR_POINT")
assert mdi == "Area", (
"(5) did not get expected value. do_projection_ref = %d, check_just_after = %d"
% (do_projection_ref, check_just_after)
)
ds = None
# Now should get 'Area'
ds = gdal.Open("tmp/tiff_write_79.tif")
if do_projection_ref:
ds.GetProjectionRef()
mdi = ds.GetMetadataItem("AREA_OR_POINT")
assert mdi == "Area", "(6) did not get expected value"
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_79.tif")
###############################################################################
# Test SetOffset() & SetScale()
def test_tiff_write_80():
# First part : test storing and retrieving scale & offsets from internal metadata
ds = gdaltest.tiff_drv.Create("tmp/tiff_write_80.tif", 1, 1)
ds.GetRasterBand(1).SetScale(100)
ds.GetRasterBand(1).SetOffset(1000)
ds = None
assert not os.path.exists("tmp/tiff_write_80.tif.aux.xml")
ds = gdal.Open("tmp/tiff_write_80.tif")
scale = ds.GetRasterBand(1).GetScale()
offset = ds.GetRasterBand(1).GetOffset()
assert (
scale == 100 and offset == 1000
), "did not get expected values in internal case (1)"
ds = None
# Test CreateCopy()
src_ds = gdal.Open("tmp/tiff_write_80.tif")
ds = gdaltest.tiff_drv.CreateCopy("tmp/tiff_write_80_copy.tif", src_ds)
src_ds = None
ds = None
ds = gdal.Open("tmp/tiff_write_80_copy.tif")
scale = ds.GetRasterBand(1).GetScale()
offset = ds.GetRasterBand(1).GetOffset()
assert scale == 100 and offset == 1000, "did not get expected values in copy"
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_80_copy.tif")
# Second part : test unsetting scale & offsets from internal metadata
ds = gdal.Open("tmp/tiff_write_80.tif", gdal.GA_Update)
ds.GetRasterBand(1).SetScale(1)
ds.GetRasterBand(1).SetOffset(0)
ds = None
ds = gdal.Open("tmp/tiff_write_80.tif")
scale = ds.GetRasterBand(1).GetScale()
offset = ds.GetRasterBand(1).GetOffset()
assert not scale
assert not offset
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_80.tif")
# Third part : test storing and retrieving scale & offsets from PAM metadata
ds = gdaltest.tiff_drv.Create("tmp/tiff_write_80_bis.tif", 1, 1)
assert (
ds.GetRasterBand(1).GetScale() is None
and ds.GetRasterBand(1).GetOffset() is None
), "expected None values"
ds = None
ds = gdal.Open("tmp/tiff_write_80_bis.tif")
ds.GetRasterBand(1).SetScale(-100)
ds.GetRasterBand(1).SetOffset(-1000)
ds = None
try:
# check that it *goes* to PAM
os.stat("tmp/tiff_write_80_bis.tif.aux.xml")
except OSError:
pytest.fail("did not go to PAM as expected")
ds = gdal.Open("tmp/tiff_write_80_bis.tif")
scale = ds.GetRasterBand(1).GetScale()
offset = ds.GetRasterBand(1).GetOffset()
assert (
scale == -100 and offset == -1000
), "did not get expected values in PAM case (1)"
ds = None
# Fourth part : test unsetting scale & offsets from PAM metadata
ds = gdal.Open("tmp/tiff_write_80_bis.tif")
ds.GetRasterBand(1).SetScale(1)
ds.GetRasterBand(1).SetOffset(0)
ds = None
assert not os.path.exists("tmp/tiff_write_80_bis.tif.aux.xml")
ds = gdal.Open("tmp/tiff_write_80_bis.tif")
scale = ds.GetRasterBand(1).GetScale()
offset = ds.GetRasterBand(1).GetOffset()
assert not scale
assert not offset
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_80_bis.tif")
###############################################################################
# Test retrieving GCP from PAM
def test_tiff_write_81():
shutil.copyfile("data/byte.tif", "tmp/tiff_write_81.tif")
f = open("tmp/tiff_write_81.tif.aux.xml", "wt")
f.write(
"""
<PAMDataset>
<GCPList Projection="PROJCS[&quot;NAD27 / UTM zone 11N&quot;,GEOGCS[&quot;NAD27&quot;,DATUM[&quot;North_American_Datum_1927&quot;,SPHEROID[&quot;Clarke 1866&quot;,6378206.4,294.9786982139006,AUTHORITY[&quot;EPSG&quot;,&quot;7008&quot;]],AUTHORITY[&quot;EPSG&quot;,&quot;6267&quot;]],PRIMEM[&quot;Greenwich&quot;,0],UNIT[&quot;degree&quot;,0.0174532925199433],AUTHORITY[&quot;EPSG&quot;,&quot;4267&quot;]],PROJECTION[&quot;Transverse_Mercator&quot;],PARAMETER[&quot;latitude_of_origin&quot;,0],PARAMETER[&quot;central_meridian&quot;,-117],PARAMETER[&quot;scale_factor&quot;,0.9996],PARAMETER[&quot;false_easting&quot;,500000],PARAMETER[&quot;false_northing&quot;,0],UNIT[&quot;metre&quot;,1,AUTHORITY[&quot;EPSG&quot;,&quot;9001&quot;]],AUTHORITY[&quot;EPSG&quot;,&quot;26711&quot;]]">
<GCP Id="" Pixel="0.0000" Line="0.0000" X="4.407200000000E+05" Y="3.751320000000E+06"/>
<GCP Id="" Pixel="100.0000" Line="0.0000" X="4.467200000000E+05" Y="3.751320000000E+06"/>
<GCP Id="" Pixel="0.0000" Line="100.0000" X="4.407200000000E+05" Y="3.745320000000E+06"/>
<GCP Id="" Pixel="100.0000" Line="100.0000" X="4.467200000000E+05" Y="3.745320000000E+06"/>
</GCPList>
</PAMDataset>"""
)
f.close()
ds = gdal.Open("tmp/tiff_write_81.tif")
assert (
ds.GetGCPProjection().find('AUTHORITY["EPSG","26711"]') != -1
), "GCP Projection not set properly."
gcps = ds.GetGCPs()
assert len(gcps) == 4, "GCP count wrong."
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_81.tif")
###############################################################################
# Test writing & reading a signedbyte 8 bit geotiff
def test_tiff_write_82():
src_ds = gdal.Open("data/byte.tif")
with gdaltest.error_handler():
ds = gdaltest.tiff_drv.CreateCopy(
"tmp/tiff_write_82.tif", src_ds, options=["PIXELTYPE=SIGNEDBYTE"]
)
src_ds = None
ds = None
ds = gdal.Open("tmp/tiff_write_82.tif")
assert ds.GetRasterBand(1).DataType == gdal.GDT_Int8
assert ds.GetRasterBand(1).ComputeRasterMinMax() == (-124, 123)
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_82.tif")
###############################################################################
# Test writing & reading an indexed GeoTIFF with an extra transparency band (#3547)
def test_tiff_write_83():
# Test Create() method
ds = gdaltest.tiff_drv.Create("tmp/tiff_write_83.tif", 1, 1, 2)
ct = gdal.ColorTable()
ct.SetColorEntry(127, (255, 255, 255, 255))
ds.GetRasterBand(1).SetRasterColorTable(ct)
ds.GetRasterBand(1).Fill(127)
ds.GetRasterBand(2).Fill(255)
ds = None
# Test CreateCopy() method
src_ds = gdal.Open("tmp/tiff_write_83.tif")
ds = gdaltest.tiff_drv.CreateCopy("tmp/tiff_write_83_2.tif", src_ds)
src_ds = None
ds = None
ds = gdal.Open("tmp/tiff_write_83_2.tif")
ct2 = ds.GetRasterBand(1).GetRasterColorTable()
assert ct2.GetColorEntry(127) == (
255,
255,
255,
255,
), "did not get expected color table"
ct2 = None
cs1 = ds.GetRasterBand(1).Checksum()
assert cs1 == 127 % 7, "did not get expected checksum for band 1"
cs2 = ds.GetRasterBand(2).Checksum()
assert cs2 == 255 % 7, "did not get expected checksum for band 2"
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_83.tif")
gdaltest.tiff_drv.Delete("tmp/tiff_write_83_2.tif")
###############################################################################
# Test propagation of non-standard JPEG quality when the current directory
# changes in the midst of encoding of tiles (#3539)
@pytest.mark.require_creation_option("GTiff", "JPEG")
def test_tiff_write_84():
with gdaltest.SetCacheMax(0):
ds = gdal.GetDriverByName("GTiff").Create("tmp/tiff_write_84.tif", 128, 128, 3)
ds = None
try:
os.remove("tmp/tiff_write_84.tif.ovr")
except OSError:
pass
ds = gdal.Open("tmp/tiff_write_84.tif")
with gdal.config_options(
{"COMPRESS_OVERVIEW": "JPEG", "JPEG_QUALITY_OVERVIEW": "90"}
):
ds.BuildOverviews("NEAREST", overviewlist=[2])
cs = ds.GetRasterBand(2).GetOverview(0).Checksum()
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_84.tif")
assert cs == 0, "did not get expected checksum"
###############################################################################
# Test SetUnitType()
def test_tiff_write_85():
# First part : test storing and retrieving unittype from internal metadata
ds = gdaltest.tiff_drv.Create("tmp/tiff_write_85.tif", 1, 1)
ds.GetRasterBand(1).SetUnitType("ft")
ds = None
assert not os.path.exists("tmp/tiff_write_85.tif.aux.xml")
ds = gdal.Open("tmp/tiff_write_85.tif")
unittype = ds.GetRasterBand(1).GetUnitType()
assert unittype == "ft", "did not get expected values in internal case (1)"
ds = None
# Test CreateCopy()
src_ds = gdal.Open("tmp/tiff_write_85.tif")
ds = gdaltest.tiff_drv.CreateCopy("tmp/tiff_write_85_copy.tif", src_ds)
src_ds = None
ds = None
ds = gdal.Open("tmp/tiff_write_85_copy.tif")
unittype = ds.GetRasterBand(1).GetUnitType()
assert unittype == "ft", "did not get expected values in copy"
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_85_copy.tif")
# Second part : test unsetting unittype from internal metadata
ds = gdal.Open("tmp/tiff_write_85.tif", gdal.GA_Update)
ds.GetRasterBand(1).SetUnitType(None)
ds = None
ds = gdal.Open("tmp/tiff_write_85.tif")
unittype = ds.GetRasterBand(1).GetUnitType()
assert unittype == "", "did not get expected values in internal case (2)"
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_85.tif")
# Third part : test storing and retrieving unittype from PAM metadata
ds = gdaltest.tiff_drv.Create("tmp/tiff_write_85_bis.tif", 1, 1)
assert not ds.GetRasterBand(1).GetUnitType(), "expected None values"
ds = None
ds = gdal.Open("tmp/tiff_write_85_bis.tif")
ds.GetRasterBand(1).SetUnitType("ft")
ds = None
try:
# check that it *goes* to PAM
os.stat("tmp/tiff_write_85_bis.tif.aux.xml")
except OSError:
pytest.fail("did not go to PAM as expected")
ds = gdal.Open("tmp/tiff_write_85_bis.tif")
unittype = ds.GetRasterBand(1).GetUnitType()
assert unittype == "ft", "did not get expected values in PAM case (1)"
ds = None
# Fourth part : test unsetting unittype from PAM metadata
ds = gdal.Open("tmp/tiff_write_85_bis.tif")
ds.GetRasterBand(1).SetUnitType(None)
ds = None
assert not os.path.exists("tmp/tiff_write_85_bis.tif.aux.xml")
ds = gdal.Open("tmp/tiff_write_85_bis.tif")
unittype = ds.GetRasterBand(1).GetUnitType()
assert unittype == "", "did not get expected values in PAM case (2)"
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_85_bis.tif")
###############################################################################
# Test special handling of xml:ESRI domain. When the ESRI_XML_PAM config
# option is set we want to write this to PAM, not into the geotiff itself.
# This is a special option so that ArcGIS 10 written geotiffs will still work
# properly with earlier versions of ArcGIS, requested by ESRI.
def test_tiff_write_86():
with gdal.config_option("ESRI_XML_PAM", "YES"):
ds = gdaltest.tiff_drv.Create(
"tmp/tiff_write_86.tif", 100, 100, 1, gdal.GDT_Byte
)
ds.SetMetadata(["<abc></abc>"], "xml:ESRI")
ds.SetMetadataItem("BaseTest", "Value")
ds = None
# Is the xml:ESRI data available?
ds = gdal.Open("tmp/tiff_write_86.tif")
assert ds.GetMetadata("xml:ESRI") == [
"<abc />\n"
], "did not get expected xml:ESRI metadata."
if ds.GetMetadataItem("BaseTest") != "Value":
gdaltest.post_value("missing metadata(1)")
pytest.fail()
ds = None
# After removing the pam file is it gone, but the conventional
# metadata still available?
os.rename(
"tmp/tiff_write_86.tif.aux.xml", "tmp/tiff_write_86.tif.aux.xml.hidden"
)
ds = gdal.Open("tmp/tiff_write_86.tif")
assert ds.GetMetadata("xml:ESRI") is None, "unexpectedly got xml:ESRI metadata"
if ds.GetMetadataItem("BaseTest") != "Value":
gdaltest.post_value("missing metadata(2)")
pytest.fail()
ds = None
# now confirm that CreateCopy also preserves things similarly.
os.rename(
"tmp/tiff_write_86.tif.aux.xml.hidden", "tmp/tiff_write_86.tif.aux.xml"
)
ds_src = gdal.Open("tmp/tiff_write_86.tif")
ds = gdaltest.tiff_drv.CreateCopy("tmp/tiff_write_86_cc.tif", ds_src)
ds_src = None
ds = None
# Is the xml:ESRI data available?
ds = gdal.Open("tmp/tiff_write_86_cc.tif")
assert ds.GetMetadata("xml:ESRI") == [
"<abc />\n"
], "did not get expected xml:ESRI metadata (cc)."
if ds.GetMetadataItem("BaseTest") != "Value":
gdaltest.post_value("missing metadata(1cc)")
pytest.fail()
ds = None
# After removing the pam file is it gone, but the conventional
# metadata still available?
os.remove("tmp/tiff_write_86_cc.tif.aux.xml")
ds = gdal.Open("tmp/tiff_write_86_cc.tif")
assert (
ds.GetMetadata("xml:ESRI") is None
), "unexpectedly got xml:ESRI metadata(2)"
if ds.GetMetadataItem("BaseTest") != "Value":
gdaltest.post_value("missing metadata(2cc)")
pytest.fail()
ds = None
# Cleanup
gdaltest.tiff_drv.Delete("tmp/tiff_write_86.tif")
gdaltest.tiff_drv.Delete("tmp/tiff_write_86_cc.tif")
###############################################################################
# Test COPY_SRC_OVERVIEWS creation option
def test_tiff_write_87():
gdal.Translate(
"tmp/tiff_write_87_src.tif", "data/utmsmall.tif", options="-a_nodata 0"
)
src_ds = gdal.Open("tmp/tiff_write_87_src.tif", gdal.GA_Update)
src_ds.BuildOverviews("NEAR", overviewlist=[2, 4])
expected_cs1 = src_ds.GetRasterBand(1).GetOverview(0).Checksum()
expected_cs2 = src_ds.GetRasterBand(1).GetOverview(1).Checksum()
ds = gdaltest.tiff_drv.CreateCopy(
"tmp/tiff_write_87_dst.tif",
src_ds,
options=["COPY_SRC_OVERVIEWS=YES", "ENDIANNESS=LITTLE"],
)
ds = None
src_ds = None
ds = gdal.Open("tmp/tiff_write_87_dst.tif")
cs1 = ds.GetRasterBand(1).GetOverview(0).Checksum()
cs2 = ds.GetRasterBand(1).GetOverview(1).Checksum()
nodata_ovr_0 = ds.GetRasterBand(1).GetOverview(0).GetNoDataValue()
nodata_ovr_1 = ds.GetRasterBand(1).GetOverview(1).GetNoDataValue()
ifd_main = int(ds.GetRasterBand(1).GetMetadataItem("IFD_OFFSET", "TIFF"))
ifd_ovr_0 = int(
ds.GetRasterBand(1).GetOverview(0).GetMetadataItem("IFD_OFFSET", "TIFF")
)
ifd_ovr_1 = int(
ds.GetRasterBand(1).GetOverview(1).GetMetadataItem("IFD_OFFSET", "TIFF")
)
data_ovr_1 = int(
ds.GetRasterBand(1).GetOverview(1).GetMetadataItem("BLOCK_OFFSET_0_0", "TIFF")
)
data_ovr_0 = int(
ds.GetRasterBand(1).GetOverview(0).GetMetadataItem("BLOCK_OFFSET_0_0", "TIFF")
)
data_main = int(ds.GetRasterBand(1).GetMetadataItem("BLOCK_OFFSET_0_0", "TIFF"))
size_main = int(ds.GetRasterBand(1).GetMetadataItem("BLOCK_SIZE_0_0", "TIFF"))
with open("tmp/tiff_write_87_dst.tif", "rb") as f:
f.seek(data_main - 4)
size_from_header = struct.unpack("<I", f.read(4))[0]
assert size_main == size_from_header
f.seek(data_main + size_main - 4)
last_bytes = f.read(4)
last_bytes_repeated = f.read(4)
assert last_bytes == last_bytes_repeated
ds = None
_check_cog("tmp/tiff_write_87_dst.tif", check_tiled=False, full_check=True)
gdaltest.tiff_drv.Delete("tmp/tiff_write_87_src.tif")
gdaltest.tiff_drv.Delete("tmp/tiff_write_87_dst.tif")
# Check checksums
assert cs1 == expected_cs1 and cs2 == expected_cs2, "did not get expected checksums"
assert nodata_ovr_0 == 0 and nodata_ovr_1 == 0, "did not get expected nodata values"
assert ifd_main == 8 or (
ifd_main < ifd_ovr_0
and ifd_ovr_0 < ifd_ovr_1
and ifd_ovr_1 < data_ovr_1
and data_ovr_1 < data_ovr_0
and data_ovr_0 < data_main
)
###############################################################################
# Test that COPY_SRC_OVERVIEWS creation option has an influence
# on BIGTIFF creation
def test_tiff_write_88():
# The file would be > 4.2 GB without SPARSE_OK
src_ds = gdaltest.tiff_drv.Create(
"tmp/tiff_write_88_src.tif",
60000,
60000,
1,
options=["TILED=YES", "SPARSE_OK=YES"],
)
src_ds.BuildOverviews("NONE", overviewlist=[2, 4])
# Just write one data block so that we can truncate it
data = src_ds.GetRasterBand(1).GetOverview(1).ReadRaster(0, 0, 128, 128)
src_ds.GetRasterBand(1).GetOverview(1).WriteRaster(0, 0, 128, 128, data)
src_ds = None
# Truncate the file to cause an I/O error on reading
# so that the CreateCopy() aborts quickly
f = open("tmp/tiff_write_88_src.tif", "rb")
f.seek(0, 2)
length = f.tell()
f.seek(0, 0)
data = f.read(length - 1)
f.close()
f = open("tmp/tiff_write_88_src.tif", "wb")
f.write(data)
f.close()
src_ds = gdal.Open("tmp/tiff_write_88_src.tif")
# for testing only. We need to keep the file to check it was a bigtiff
# we don't want free space to be an issue here
with gdal.config_options(
{"GTIFF_DELETE_ON_ERROR": "NO", "CHECK_DISK_FREE_SPACE": "NO"}
), gdaltest.error_handler():
ds = gdaltest.tiff_drv.CreateCopy(
"tmp/tiff_write_88_dst.tif",
src_ds,
options=["TILED=YES", "COPY_SRC_OVERVIEWS=YES", "ENDIANNESS=LITTLE"],
)
del ds
src_ds = None
f = open("tmp/tiff_write_88_dst.tif", "rb")
data = f.read(8)
f.close()
os.remove("tmp/tiff_write_88_src.tif")
os.remove("tmp/tiff_write_88_dst.tif")
ar = struct.unpack("B" * 8, data)
assert ar[2] == 43, "not a BIGTIFF file"
assert (
ar[4] == 8 and ar[5] == 0 and ar[6] == 0 and ar[7] == 0
), "first IFD is not at offset 8"
###############################################################################
# Test JPEG_QUALITY propagation while creating a (default compressed) mask band
@pytest.mark.require_creation_option("GTiff", "JPEG")
def test_tiff_write_89():
last_size = 0
for quality in [90, 75, 30]:
src_ds = gdal.Open("../gdrivers/data/utm.tif")
ds = gdal.GetDriverByName("GTiff").Create(
"tmp/tiff_write_89.tif",
1024,
1024,
3,
options=["COMPRESS=JPEG", "PHOTOMETRIC=YCBCR", "JPEG_QUALITY=%d" % quality],
)
with gdal.config_option("GDAL_TIFF_INTERNAL_MASK", "YES"):
ds.CreateMaskBand(gdal.GMF_PER_DATASET)
data = src_ds.GetRasterBand(1).ReadRaster(0, 0, 512, 512, 1024, 1024)
ds.GetRasterBand(1).WriteRaster(0, 0, 1024, 1024, data)
ds.GetRasterBand(2).WriteRaster(0, 0, 1024, 1024, data)
ds.GetRasterBand(3).WriteRaster(0, 0, 1024, 1024, data)
ds.GetRasterBand(1).GetMaskBand().Fill(255)
src_ds = None
ds = None
# older versions of python don't have SEEK_END, add if missing.
try:
os.SEEK_END
except AttributeError:
os.SEEK_END = 2
f = open("tmp/tiff_write_89.tif", "rb")
f.seek(0, os.SEEK_END)
size = f.tell()
f.close()
# print('quality = %d, size = %d' % (quality, size))
if quality != 90:
assert size < last_size, "did not get decreasing file sizes"
last_size = size
gdaltest.tiff_drv.Delete("tmp/tiff_write_89.tif")
###############################################################################
# Test JPEG_QUALITY propagation/override while creating (internal) overviews
@pytest.mark.require_creation_option("GTiff", "JPEG")
def test_tiff_write_90():
checksums = {}
qualities = [90, 75, 75]
for i, quality in enumerate(qualities):
src_ds = gdal.Open("../gdrivers/data/utm.tif")
fname = "tmp/tiff_write_90_%d" % i
ds = gdal.GetDriverByName("GTiff").Create(
fname,
1024,
1024,
3,
options=["COMPRESS=JPEG", "PHOTOMETRIC=YCBCR", "JPEG_QUALITY=%d" % quality],
)
data = src_ds.GetRasterBand(1).ReadRaster(0, 0, 512, 512, 1024, 1024)
ds.GetRasterBand(1).WriteRaster(0, 0, 1024, 1024, data)
ds.GetRasterBand(2).WriteRaster(0, 0, 1024, 1024, data)
ds.GetRasterBand(3).WriteRaster(0, 0, 1024, 1024, data)
if i == 2:
quality = 30
with gdaltest.config_option("JPEG_QUALITY_OVERVIEW", "%d" % quality):
ds.BuildOverviews("AVERAGE", overviewlist=[2, 4])
src_ds = None
ds = None
ds = gdal.Open(fname)
checksums[i] = [
ds.GetRasterBand(1).Checksum(),
ds.GetRasterBand(1).GetOverview(0).Checksum(),
ds.GetRasterBand(1).GetOverview(1).Checksum(),
]
ds = None
gdaltest.tiff_drv.Delete(fname)
assert checksums[0][0] != checksums[1][0]
assert checksums[0][1] != checksums[1][1]
assert checksums[0][2] != checksums[1][2]
assert checksums[0][0] != checksums[2][0]
assert checksums[0][1] != checksums[2][1]
assert checksums[0][2] != checksums[2][2]
assert checksums[1][0] == checksums[2][0]
assert checksums[1][1] != checksums[2][1]
assert checksums[1][2] != checksums[2][2]
###############################################################################
# Test WEBP_LEVEL propagation and overriding while creating overviews
# on a newly created dataset
@pytest.mark.parametrize("external_ovr", [True, False])
@pytest.mark.require_creation_option("GTiff", "WEBP")
def test_tiff_write_90_webp(external_ovr):
checksums = {}
qualities = [90, 75, 75]
for i, quality in enumerate(qualities):
src_ds = gdal.Open("../gdrivers/data/utm.tif")
fname = "tmp/tiff_write_90_webp_%d" % i
ds = gdal.GetDriverByName("GTiff").Create(
fname, 512, 512, 3, options=["COMPRESS=WEBP", "WEBP_LEVEL=%d" % quality]
)
data = src_ds.GetRasterBand(1).ReadRaster()
ds.GetRasterBand(1).WriteRaster(0, 0, 512, 512, data)
ds.GetRasterBand(2).WriteRaster(0, 0, 512, 512, data)
ds.GetRasterBand(3).WriteRaster(0, 0, 512, 512, data)
if i == 2:
quality = 30
options = {}
if external_ovr:
ds = None
ds = gdal.Open(fname)
options["COMPRESS_OVERVIEW"] = "WEBP"
options["WEBP_LEVEL_OVERVIEW"] = "%d" % quality
with gdaltest.config_options(options):
ds.BuildOverviews("AVERAGE", overviewlist=[2, 4])
src_ds = None
ds = None
ds = gdal.Open(fname)
checksums[i] = [
ds.GetRasterBand(1).Checksum(),
ds.GetRasterBand(1).GetOverview(0).Checksum(),
ds.GetRasterBand(1).GetOverview(1).Checksum(),
]
ds = None
gdaltest.tiff_drv.Delete(fname)
assert checksums[0][0] != checksums[1][0]
assert checksums[0][1] != checksums[1][1]
assert checksums[0][2] != checksums[1][2]
assert checksums[0][0] != checksums[2][0]
assert checksums[0][1] != checksums[2][1]
assert checksums[0][2] != checksums[2][2]
assert checksums[1][0] == checksums[2][0]
assert checksums[1][1] != checksums[2][1]
assert checksums[1][2] != checksums[2][2]
###############################################################################
# Test WEBP_LOSSLESS propagation and overriding while creating overviews
# on a newly created dataset
@pytest.mark.parametrize("external_ovr", [True, False])
@pytest.mark.require_creation_option("GTiff", "WEBP")
def test_tiff_write_90_webp_lossless(external_ovr):
checksums = {}
for i in range(2):
src_ds = gdal.Open("../gdrivers/data/utm.tif")
fname = "tmp/tiff_write_90_webp_lossless_%d" % i
ds = gdaltest.tiff_drv.Create(fname, 512, 512, 3, options=["COMPRESS=WEBP"])
data = src_ds.GetRasterBand(1).ReadRaster()
ds.GetRasterBand(1).WriteRaster(0, 0, 512, 512, data)
ds.GetRasterBand(2).WriteRaster(0, 0, 512, 512, data)
ds.GetRasterBand(3).WriteRaster(0, 0, 512, 512, data)
options = {}
if external_ovr:
ds = None
ds = gdal.Open(fname)
options["COMPRESS_OVERVIEW"] = "WEBP"
if i == 1:
options["WEBP_LOSSLESS_OVERVIEW"] = "YES"
with gdaltest.config_options(options):
ds.BuildOverviews("AVERAGE", overviewlist=[2])
src_ds = None
ds = None
ds = gdal.Open(fname)
checksums[i] = [
ds.GetRasterBand(1).Checksum(),
ds.GetRasterBand(1).GetOverview(0).Checksum(),
]
ds = None
gdaltest.tiff_drv.Delete(fname)
assert checksums[0][0] == checksums[1][0]
assert checksums[0][1] != checksums[1][1]
###############################################################################
# Test JPEG_QUALITY propagation while creating (internal) overviews after re-opening
@pytest.mark.require_creation_option("GTiff", "JPEG")
def test_tiff_write_91():
checksums = {}
for quality in [90, 75, 30]:
src_ds = gdal.Open("../gdrivers/data/utm.tif")
ds = gdal.GetDriverByName("GTiff").Create(
"tmp/tiff_write_91.tif",
1024,
1024,
3,
options=["COMPRESS=JPEG", "PHOTOMETRIC=YCBCR", "JPEG_QUALITY=%d" % quality],
)
data = src_ds.GetRasterBand(1).ReadRaster(0, 0, 512, 512, 1024, 1024)
ds.GetRasterBand(1).WriteRaster(0, 0, 1024, 1024, data)
ds.GetRasterBand(2).WriteRaster(0, 0, 1024, 1024, data)
ds.GetRasterBand(3).WriteRaster(0, 0, 1024, 1024, data)
ds = None
ds = gdal.Open("tmp/tiff_write_91.tif", gdal.GA_Update)
with gdal.config_option("JPEG_QUALITY_OVERVIEW", "%d" % quality):
ds.BuildOverviews("NEAR", overviewlist=[2, 4])
src_ds = None
ds = None
ds = gdal.Open("tmp/tiff_write_91.tif")
checksums[quality] = [
ds.GetRasterBand(1).Checksum(),
ds.GetRasterBand(1).GetOverview(0).Checksum(),
ds.GetRasterBand(1).GetOverview(1).Checksum(),
]
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_91.tif")
assert checksums[75][0] != checksums[90][0]
assert checksums[75][1] != checksums[90][1]
assert checksums[75][2] != checksums[90][2]
assert checksums[75][0] != checksums[30][0]
assert checksums[75][1] != checksums[30][1]
assert checksums[75][2] != checksums[30][2]
assert checksums[90][0] != checksums[30][0]
assert checksums[90][1] != checksums[30][1]
assert checksums[90][2] != checksums[30][2]
###############################################################################
# Test WEBP_LEVEL_OVERVIEW while creating (internal) overviews after re-opening
@pytest.mark.require_creation_option("GTiff", "WEBP")
def test_tiff_write_91_webp():
checksums = {}
for quality in [90, 75, 30]:
src_ds = gdal.Open("../gdrivers/data/utm.tif")
fname = "tmp/tiff_write_91_webp_%d" % quality
ds = gdal.GetDriverByName("GTiff").Create(
fname, 1024, 1024, 3, options=["COMPRESS=WEBP"]
)
data = src_ds.GetRasterBand(1).ReadRaster(0, 0, 512, 512, 1024, 1024)
ds.GetRasterBand(1).WriteRaster(0, 0, 1024, 1024, data)
ds.GetRasterBand(2).WriteRaster(0, 0, 1024, 1024, data)
ds.GetRasterBand(3).WriteRaster(0, 0, 1024, 1024, data)
ds = None
src_ds = None
ds = gdal.Open(fname, gdal.GA_Update)
with gdaltest.config_option("WEBP_LEVEL_OVERVIEW", "%d" % quality):
ds.BuildOverviews("AVERAGE", overviewlist=[2, 4])
ds = None
ds = gdal.Open(fname)
checksums[quality] = [
ds.GetRasterBand(1).Checksum(),
ds.GetRasterBand(1).GetOverview(0).Checksum(),
ds.GetRasterBand(1).GetOverview(1).Checksum(),
]
ds = None
gdaltest.tiff_drv.Delete(fname)
assert checksums[75][0] == checksums[90][0]
assert checksums[75][1] != checksums[90][1]
assert checksums[75][2] != checksums[90][2]
assert checksums[75][0] == checksums[30][0]
assert checksums[75][1] != checksums[30][1]
assert checksums[75][2] != checksums[30][2]
assert checksums[90][0] == checksums[30][0]
assert checksums[90][1] != checksums[30][1]
assert checksums[90][2] != checksums[30][2]
###############################################################################
# Test the effect of JPEG_QUALITY_OVERVIEW while creating (internal) overviews after re-opening
# This will test that we correctly guess the quality of the main dataset
@pytest.mark.require_creation_option("GTiff", "JPEG")
def test_tiff_write_92():
last_size = 0
quality = 30
for jpeg_quality_overview in [False, 30, 40]:
src_ds = gdal.Open("../gdrivers/data/utm.tif")
ds = gdal.GetDriverByName("GTiff").Create(
"tmp/tiff_write_92.tif",
1024,
1024,
3,
options=["COMPRESS=JPEG", "PHOTOMETRIC=YCBCR", "JPEG_QUALITY=%d" % quality],
)
data = src_ds.GetRasterBand(1).ReadRaster(0, 0, 512, 512, 1024, 1024)
ds.GetRasterBand(1).WriteRaster(0, 0, 1024, 1024, data)
ds.GetRasterBand(2).WriteRaster(0, 0, 1024, 1024, data)
ds.GetRasterBand(3).WriteRaster(0, 0, 1024, 1024, data)
ds = None
ds = gdal.Open("tmp/tiff_write_92.tif", gdal.GA_Update)
assert ds.GetMetadataItem("JPEG_QUALITY", "IMAGE_STRUCTURE") == str(quality)
if jpeg_quality_overview is not False:
gdal.SetConfigOption("JPEG_QUALITY_OVERVIEW", "%d" % jpeg_quality_overview)
ds.BuildOverviews("NEAR", overviewlist=[2, 4])
gdal.SetConfigOption("JPEG_QUALITY_OVERVIEW", None)
src_ds = None
ds = None
f = open("tmp/tiff_write_92.tif", "rb")
f.seek(0, os.SEEK_END)
size = f.tell()
f.close()
# print('quality = %d, size = %d' % (quality, size))
if jpeg_quality_overview == 30:
assert size == last_size, "did not get equal file sizes"
elif jpeg_quality_overview == 40:
assert size > last_size, "did not get growing file sizes"
last_size = size
gdaltest.tiff_drv.Delete("tmp/tiff_write_92.tif")
###############################################################################
# Test JPEG_QUALITY_OVERVIEW propagation while creating external overviews
@pytest.mark.require_creation_option("GTiff", "JPEG")
def test_tiff_write_93():
src_ds = gdal.Open("../gdrivers/data/utm.tif")
ds = gdal.GetDriverByName("GTiff").Create(
"tmp/tiff_write_93.tif",
1024,
1024,
3,
options=["COMPRESS=JPEG", "PHOTOMETRIC=YCBCR"],
)
data = src_ds.GetRasterBand(1).ReadRaster(0, 0, 512, 512, 1024, 1024)
ds.GetRasterBand(1).WriteRaster(0, 0, 1024, 1024, data)
ds.GetRasterBand(2).WriteRaster(0, 0, 1024, 1024, data)
ds.GetRasterBand(3).WriteRaster(0, 0, 1024, 1024, data)
ds = None
src_ds = None
last_size = 0
for quality in [90, 75, 30]:
try:
os.remove("tmp/tiff_write_93.tif.ovr")
except OSError:
pass
ds = gdal.Open("tmp/tiff_write_93.tif")
with gdal.config_options(
{
"COMPRESS_OVERVIEW": "JPEG",
"JPEG_QUALITY_OVERVIEW": "%d" % quality,
"PHOTOMETRIC_OVERVIEW": "YCBCR",
}
):
ds.BuildOverviews("NEAR", overviewlist=[2, 4])
ds = None
f = open("tmp/tiff_write_93.tif.ovr", "rb")
f.seek(0, os.SEEK_END)
size = f.tell()
f.close()
# print('quality = %d, size = %d' % (quality, size))
if quality != 90:
assert size < last_size, "did not get decreasing file sizes"
assert not (
quality == 30 and size >= 83000
), "file larger than expected. should be about 69100. perhaps jpeg quality is not well propagated"
last_size = size
gdaltest.tiff_drv.Delete("tmp/tiff_write_93.tif")
###############################################################################
# Test CreateCopy() of a dataset with a mask into a JPEG compressed dataset
# and check JPEG_QUALITY propagation without warning
@pytest.mark.require_creation_option("GTiff", "JPEG")
def test_tiff_write_94():
src_ds = gdal.GetDriverByName("GTiff").Create(
"tmp/tiff_write_94_src.tif", 1024, 1024, 3
)
with gdal.config_option("GDAL_TIFF_INTERNAL_MASK", "YES"):
src_ds.CreateMaskBand(gdal.GMF_PER_DATASET)
src_ds.GetRasterBand(1).GetMaskBand().WriteRaster(0, 0, 1, 1, "\xff", 1, 1)
with gdal.config_option("GDAL_TIFF_INTERNAL_MASK", "YES"):
ds = gdal.GetDriverByName("GTiff").CreateCopy(
"tmp/tiff_write_94_dst.tif",
src_ds,
options=["COMPRESS=JPEG", "PHOTOMETRIC=YCBCR", "JPEG_QUALITY=30"],
)
src_ds = None
ds = None
ds = gdal.Open("tmp/tiff_write_94_dst.tif")
cs = ds.GetRasterBand(1).GetMaskBand().Checksum()
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_94_src.tif")
gdaltest.tiff_drv.Delete("tmp/tiff_write_94_dst.tif")
assert cs == 3, "wrong checksum"
###############################################################################
# Test that COPY_SRC_OVERVIEWS deal well with rounding issues when computing
# overview levels from the overview size
def test_tiff_write_95():
src_ds = gdaltest.tiff_drv.Create(
"tmp/tiff_write_95_src.tif", 7171, 6083, options=["SPARSE_OK=YES"]
)
src_ds.BuildOverviews("NONE", overviewlist=[2, 4, 8, 16, 32, 64])
with gdal.config_option("GTIFF_DONT_WRITE_BLOCKS", "YES"):
ds = gdaltest.tiff_drv.CreateCopy(
"tmp/tiff_write_95_dst.tif", src_ds, options=["COPY_SRC_OVERVIEWS=YES"]
)
ok = ds is not None
ds = None
src_ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_95_src.tif")
gdaltest.tiff_drv.Delete("tmp/tiff_write_95_dst.tif")
assert ok
###############################################################################
# Test that COPY_SRC_OVERVIEWS combined with GDAL_TIFF_INTERNAL_MASK=YES work well
def test_tiff_write_96(other_options=[], nbands=1, nbits=8):
with gdal.config_option("GDAL_TIFF_INTERNAL_MASK", "YES"):
src_ds = gdaltest.tiff_drv.Create(
"tmp/tiff_write_96_src.tif",
100,
100,
nbands,
options=["NBITS=" + str(nbits)],
)
src_ds.GetRasterBand(1).Fill(255 if nbits == 8 else 127)
src_ds.CreateMaskBand(gdal.GMF_PER_DATASET)
src_ds.GetRasterBand(1).GetMaskBand().WriteRaster(25, 25, 50, 50, b"\xff", 1, 1)
src_ds.BuildOverviews("NEAR", overviewlist=[2, 4])
expected_cs = src_ds.GetRasterBand(1).Checksum()
expected_cs_mask = src_ds.GetRasterBand(1).GetMaskBand().Checksum()
expected_cs_ovr_1 = src_ds.GetRasterBand(1).GetOverview(0).Checksum()
expected_cs_ovr_mask_1 = (
src_ds.GetRasterBand(1).GetOverview(0).GetMaskBand().Checksum()
)
expected_cs_ovr_2 = src_ds.GetRasterBand(1).GetOverview(1).Checksum()
expected_cs_ovr_mask_2 = (
src_ds.GetRasterBand(1).GetOverview(1).GetMaskBand().Checksum()
)
ds = gdaltest.tiff_drv.CreateCopy(
"tmp/tiff_write_96_dst.tif",
src_ds,
options=["COPY_SRC_OVERVIEWS=YES"]
+ other_options
+ ["NBITS=" + str(nbits)],
)
ds = None
src_ds = None
ds = gdal.Open("tmp/tiff_write_96_dst.tif")
cs = ds.GetRasterBand(1).Checksum()
cs_mask = ds.GetRasterBand(1).GetMaskBand().Checksum()
cs_ovr_1 = ds.GetRasterBand(1).GetOverview(0).Checksum()
cs_ovr_mask_1 = ds.GetRasterBand(1).GetOverview(0).GetMaskBand().Checksum()
cs_ovr_2 = ds.GetRasterBand(1).GetOverview(1).Checksum()
cs_ovr_mask_2 = ds.GetRasterBand(1).GetOverview(1).GetMaskBand().Checksum()
assert ds.GetMetadataItem("HAS_USED_READ_ENCODED_API", "_DEBUG_") == "1"
ds = None
assert [
expected_cs,
expected_cs_mask,
expected_cs_ovr_1,
expected_cs_ovr_mask_1,
expected_cs_ovr_2,
expected_cs_ovr_mask_2,
] == [
cs,
cs_mask,
cs_ovr_1,
cs_ovr_mask_1,
cs_ovr_2,
cs_ovr_mask_2,
], "did not get expected checksums"
if check_libtiff_internal_or_at_least(4, 0, 11):
with gdaltest.config_option("GTIFF_HAS_OPTIMIZED_READ_MULTI_RANGE", "YES"):
ds = gdal.Open("tmp/tiff_write_96_dst.tif")
cs = ds.GetRasterBand(1).Checksum()
cs_mask = ds.GetRasterBand(1).GetMaskBand().Checksum()
cs_ovr_1 = ds.GetRasterBand(1).GetOverview(0).Checksum()
cs_ovr_mask_1 = ds.GetRasterBand(1).GetOverview(0).GetMaskBand().Checksum()
cs_ovr_2 = ds.GetRasterBand(1).GetOverview(1).Checksum()
cs_ovr_mask_2 = ds.GetRasterBand(1).GetOverview(1).GetMaskBand().Checksum()
assert [
expected_cs,
expected_cs_mask,
expected_cs_ovr_1,
expected_cs_ovr_mask_1,
expected_cs_ovr_2,
expected_cs_ovr_mask_2,
] == [
cs,
cs_mask,
cs_ovr_1,
cs_ovr_mask_1,
cs_ovr_2,
cs_ovr_mask_2,
], "did not get expected checksums"
assert ds.GetMetadataItem("HAS_USED_READ_ENCODED_API", "_DEBUG_") == "0"
ds = None
_check_cog("tmp/tiff_write_96_dst.tif", check_tiled=False, full_check=True)
gdaltest.tiff_drv.Delete("tmp/tiff_write_96_src.tif")
gdaltest.tiff_drv.Delete("tmp/tiff_write_96_dst.tif")
def test_tiff_write_96_tiled_threads_nbits7_nbands1():
return test_tiff_write_96(
["TILED=YES", "BLOCKXSIZE=16", "BLOCKYSIZE=32", "NUM_THREADS=ALL_CPUS"],
nbands=1,
nbits=7,
)
def test_tiff_write_96_tiled_threads_nbits7_nbands2():
return test_tiff_write_96(
[
"BIGTIFF=YES",
"TILED=YES",
"BLOCKXSIZE=16",
"BLOCKYSIZE=32",
"NUM_THREADS=ALL_CPUS",
],
nbands=2,
nbits=7,
)
###############################################################################
# Test that strile arrays are written after the IFD
def test_tiff_write_ifd_offsets():
if not check_libtiff_internal_or_at_least(4, 0, 11):
pytest.skip()
src_ds = gdal.GetDriverByName("MEM").Create("", 100, 100)
src_ds.CreateMaskBand(gdal.GMF_PER_DATASET)
src_ds.BuildOverviews("NEAR", overviewlist=[2, 4])
filename = "/vsimem/test_tiff_write_ifd_offsets.tif"
with gdaltest.config_option("GDAL_TIFF_INTERNAL_MASK", "YES"):
ds = gdal.GetDriverByName("GTiff").CreateCopy(
filename,
src_ds,
options=["COPY_SRC_OVERVIEWS=YES", "TILED=YES", "COMPRESS=LZW"],
)
val0_ref = int(ds.GetRasterBand(1).GetMetadataItem("IFD_OFFSET", "TIFF"))
val1_ref = int(
ds.GetRasterBand(1).GetMaskBand().GetMetadataItem("IFD_OFFSET", "TIFF")
)
val2_ref = int(
ds.GetRasterBand(1).GetOverview(0).GetMetadataItem("IFD_OFFSET", "TIFF")
)
val3_ref = int(
ds.GetRasterBand(1).GetOverview(1).GetMetadataItem("IFD_OFFSET", "TIFF")
)
val4_ref = int(
ds.GetRasterBand(1)
.GetOverview(0)
.GetMaskBand()
.GetMetadataItem("IFD_OFFSET", "TIFF")
)
val5_ref = int(
ds.GetRasterBand(1)
.GetOverview(1)
.GetMaskBand()
.GetMetadataItem("IFD_OFFSET", "TIFF")
)
ds = None
assert val0_ref < val1_ref
assert val1_ref < val2_ref
assert val2_ref < val3_ref
assert val3_ref < val4_ref
assert val4_ref < val5_ref
assert val5_ref < 1100
# Retry with larger file
src_ds = gdal.GetDriverByName("MEM").Create("", 4096, 4096)
src_ds.CreateMaskBand(gdal.GMF_PER_DATASET)
src_ds.BuildOverviews("NEAR", overviewlist=[2, 4])
with gdaltest.config_option("GDAL_TIFF_INTERNAL_MASK", "YES"):
ds = gdal.GetDriverByName("GTiff").CreateCopy(
filename,
src_ds,
options=["COPY_SRC_OVERVIEWS=YES", "TILED=YES", "COMPRESS=LZW"],
)
val0 = int(ds.GetRasterBand(1).GetMetadataItem("IFD_OFFSET", "TIFF"))
val1 = int(ds.GetRasterBand(1).GetMaskBand().GetMetadataItem("IFD_OFFSET", "TIFF"))
val2 = int(ds.GetRasterBand(1).GetOverview(0).GetMetadataItem("IFD_OFFSET", "TIFF"))
val3 = int(ds.GetRasterBand(1).GetOverview(1).GetMetadataItem("IFD_OFFSET", "TIFF"))
val4 = int(
ds.GetRasterBand(1)
.GetOverview(0)
.GetMaskBand()
.GetMetadataItem("IFD_OFFSET", "TIFF")
)
val5 = int(
ds.GetRasterBand(1)
.GetOverview(1)
.GetMaskBand()
.GetMetadataItem("IFD_OFFSET", "TIFF")
)
ds = None
# Test rewriting but without changing strile size
ds = gdal.Open(filename, gdal.GA_Update)
ds.GetRasterBand(1).Fill(0)
ds = None
assert gdal.GetLastErrorMsg() == ""
f = gdal.VSIFOpenL(filename, "rb")
data = gdal.VSIFReadL(1, 1000, f).decode("LATIN1")
gdal.VSIFCloseL(f)
assert "KNOWN_INCOMPATIBLE_EDITION=NO\n " in data
# Test rewriting with changing strile size
ds = gdal.Open(filename, gdal.GA_Update)
ds.GetRasterBand(1).WriteRaster(0, 0, 1, 1, "x")
ds = None
assert gdal.GetLastErrorMsg() != ""
f = gdal.VSIFOpenL(filename, "rb")
data = gdal.VSIFReadL(1, 1000, f).decode("LATIN1")
gdal.VSIFCloseL(f)
assert "KNOWN_INCOMPATIBLE_EDITION=YES\n" in data
gdal.GetDriverByName("GTiff").Delete(filename)
assert (val0_ref, val1_ref, val2_ref, val3_ref, val4_ref, val5_ref) == (
val0,
val1,
val2,
val3,
val4,
val5,
)
###############################################################################
# Create a simple file by copying from an existing one - PixelIsPoint
def test_tiff_write_97():
with gdal.config_option("GTIFF_POINT_GEO_IGNORE", "FALSE"):
src_ds = gdal.Open("data/byte_point.tif")
new_ds = gdaltest.tiff_drv.CreateCopy("tmp/test_97.tif", src_ds)
gt = new_ds.GetGeoTransform()
md = new_ds.GetMetadataItem("AREA_OR_POINT")
new_ds = None
gt_expected = (440690.0, 60.0, 0.0, 3751350.0, 0.0, -60.0)
assert gt == gt_expected, "did not get expected geotransform"
assert md == "Point", "did not get expected AREA_OR_POINT value"
gdaltest.tiff_drv.Delete("tmp/test_97.tif")
# Again, but ignoring PixelIsPoint
with gdal.config_option("GTIFF_POINT_GEO_IGNORE", "TRUE"):
new_ds = gdaltest.tiff_drv.CreateCopy("tmp/test_97_2.tif", src_ds)
gt = new_ds.GetGeoTransform()
md = new_ds.GetMetadataItem("AREA_OR_POINT")
new_ds = None
src_ds = None
gt_expected = (440690.0, 60.0, 0.0, 3751350.0, 0.0, -60.0)
assert (
gt == gt_expected
), "did not get expected geotransform when ignoring PixelIsPoint"
assert md == "Point", "did not get expected AREA_OR_POINT value"
# read back this file with pixelispoint behavior enabled.
new_ds = gdal.Open("tmp/test_97_2.tif")
gt = new_ds.GetGeoTransform()
md = new_ds.GetMetadataItem("AREA_OR_POINT")
new_ds = None
gt_expected = (440660.0, 60.0, 0.0, 3751380.0, 0.0, -60.0)
assert (
gt == gt_expected
), "did not get expected geotransform when ignoring PixelIsPoint (2)"
assert md == "Point", "did not get expected AREA_OR_POINT value"
gdaltest.tiff_drv.Delete("tmp/test_97_2.tif")
###############################################################################
# Create a rotated geotiff file (uses a geomatrix) with - PixelIsPoint
def test_tiff_write_98():
with gdaltest.config_option("GTIFF_POINT_GEO_IGNORE", "FALSE"):
src_ds = gdal.Open("data/geomatrix.tif")
with gdaltest.config_option("GTIFF_POINT_GEO_IGNORE", "TRUE"):
new_ds = gdaltest.tiff_drv.CreateCopy("tmp/test_98.tif", src_ds)
gt = new_ds.GetGeoTransform()
md = new_ds.GetMetadataItem("AREA_OR_POINT")
new_ds = None
src_ds = None
gt_expected = (1841001.75, 1.5, -5.0, 1144003.25, -5.0, -1.5)
assert gt == gt_expected, "did not get expected geotransform"
assert md == "Point", "did not get expected AREA_OR_POINT value"
with gdaltest.config_option("GTIFF_POINT_GEO_IGNORE", "FALSE"):
new_ds = gdal.Open("tmp/test_98.tif")
gt = new_ds.GetGeoTransform()
md = new_ds.GetMetadataItem("AREA_OR_POINT")
new_ds = None
src_ds = None
gt_expected = (1841003.5, 1.5, -5.0, 1144006.5, -5.0, -1.5)
assert gt == gt_expected, "did not get expected geotransform (2)"
assert md == "Point", "did not get expected AREA_OR_POINT value"
gdaltest.tiff_drv.Delete("tmp/test_98.tif")
###############################################################################
# Create a rotated geotiff file (uses a geomatrix) with - PixelIsPoint
def test_tiff_write_tiepoints_pixelispoint():
tmpfilename = "/vsimem/test_tiff_write_tiepoints_pixelispoint.tif"
gdal.Translate(tmpfilename, "data/byte_gcp_pixelispoint.tif")
ds = gdal.Open(tmpfilename)
assert ds.GetMetadataItem("AREA_OR_POINT") == "Point"
assert ds.GetGCPCount() == 4
gcp = ds.GetGCPs()[0]
assert (
gcp.GCPPixel == pytest.approx(0.5, abs=1e-5)
and gcp.GCPLine == pytest.approx(0.5, abs=1e-5)
and gcp.GCPX == pytest.approx(-180, abs=1e-5)
and gcp.GCPY == pytest.approx(90, abs=1e-5)
and gcp.GCPZ == pytest.approx(0, abs=1e-5)
)
with gdaltest.config_option("GTIFF_POINT_GEO_IGNORE", "YES"):
gdal.Translate(tmpfilename, "data/byte_gcp_pixelispoint.tif")
ds = gdal.Open(tmpfilename)
assert ds.GetMetadataItem("AREA_OR_POINT") == "Point"
assert ds.GetGCPCount() == 4
gcp = ds.GetGCPs()[0]
assert (
gcp.GCPPixel == pytest.approx(0, abs=1e-5)
and gcp.GCPLine == pytest.approx(0, abs=1e-5)
and gcp.GCPX == pytest.approx(-180, abs=1e-5)
and gcp.GCPY == pytest.approx(90, abs=1e-5)
and gcp.GCPZ == pytest.approx(0, abs=1e-5)
)
gdal.Unlink(tmpfilename)
###############################################################################
# Create copy into a RGB JPEG-IN-TIFF (#3887)
@pytest.mark.require_creation_option("GTiff", "JPEG")
def test_tiff_write_99():
src_ds = gdal.Open("data/rgbsmall.tif")
new_ds = gdaltest.tiff_drv.CreateCopy(
"tmp/test_99.tif", src_ds, options=["COMPRESS=JPEG"]
)
del new_ds
src_ds = None
ds = gdal.Open("tmp/test_99.tif")
cs1 = ds.GetRasterBand(1).Checksum()
cs2 = ds.GetRasterBand(2).Checksum()
cs3 = ds.GetRasterBand(3).Checksum()
ds = None
gdaltest.tiff_drv.Delete("tmp/test_99.tif")
assert (cs1, cs2, cs3) == (21629, 21651, 21371), "%d,%d,%d" % (cs1, cs2, cs3)
###############################################################################
# Create copy into a 2 band JPEG-IN-TIFF (#3887)
@pytest.mark.require_creation_option("GTiff", "JPEG")
def test_tiff_write_100():
src_ds = gdaltest.tiff_drv.Create("/vsimem/test_100_src.tif", 16, 16, 2)
src_ds.GetRasterBand(1).Fill(255)
new_ds = gdaltest.tiff_drv.CreateCopy(
"/vsimem/test_100_dst.tif", src_ds, options=["COMPRESS=JPEG"]
)
del new_ds
src_ds = None
ds = gdal.Open("/vsimem/test_100_dst.tif")
cs1 = ds.GetRasterBand(1).Checksum()
cs2 = ds.GetRasterBand(2).Checksum()
ds = None
gdaltest.tiff_drv.Delete("/vsimem/test_100_src.tif")
gdaltest.tiff_drv.Delete("/vsimem/test_100_dst.tif")
assert (cs1, cs2) == (3118, 0), "%d,%d" % (cs1, cs2)
###############################################################################
# Test CHUNKY_STRIP_READ_SUPPORT (#3894)
# We use random data so the compressed files are big enough to need partial
# reloading. tiff_write_78 doesn't produce enough big data to trigger this...
@pytest.mark.slow()
def test_tiff_write_101():
md = gdaltest.tiff_drv.GetMetadata()
if sys.platform.startswith("linux"):
# Much faster to use /dev/urandom than python random generator !
f = open("/dev/urandom", "rb")
rand_array = f.read(10 * 1024 * 1024)
f.close()
else:
import random
rand_array = b"".join(
struct.pack("B", random.randint(0, 255)) for _ in range(10 * 1024 * 1024)
)
f = open("tmp/tiff_write_101.bin", "wb")
f.write(rand_array)
f.close()
f = open("tmp/tiff_write_101.hdr", "wb")
f.write(
"""ENVI
samples = 2500
lines = 4000
bands = 1
header offset = 0
file type = ENVI Standard
data type = 1
interleave = bsq
byte order = 0
map info = {UTM, 1, 1, 440720.000000, 3751320.000000, 60.000000, 60.000000, 11, North}
band names = {
Band 1}""".encode(
"ascii"
)
)
f.close()
src_ds = gdal.Open("tmp/tiff_write_101.bin")
expected_cs = src_ds.GetRasterBand(1).Checksum()
for compression_method in ["DEFLATE", "LZW", "JPEG", "PACKBITS", "LZMA"]:
if md["DMD_CREATIONOPTIONLIST"].find(compression_method) == -1:
continue
ds = gdaltest.tiff_drv.CreateCopy(
"tmp/tiff_write_101.tif",
src_ds,
options=[
"COMPRESS=" + compression_method,
"BLOCKXSIZE=2500",
"BLOCKYSIZE=4000",
],
)
ds = None
ds = gdal.Open("tmp/tiff_write_101.tif")
gdal.ErrorReset()
cs = ds.GetRasterBand(1).Checksum()
error_msg = gdal.GetLastErrorMsg()
ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_101.tif")
if error_msg != "":
src_ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_101.bin")
pytest.fail()
if compression_method != "JPEG" and cs != expected_cs:
src_ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_101.bin")
pytest.fail(
"for compression method %s, got %d instead of %d"
% (compression_method, cs, expected_cs)
)
src_ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_101.bin")
###############################################################################
# Test writing and reading back COMPD_CS
def test_tiff_write_102():
if int(gdal.GetDriverByName("GTiff").GetMetadataItem("LIBGEOTIFF")) < 1600:
pytest.skip("requires libgeotiff >= 1.6")
ds = gdaltest.tiff_drv.Create("/vsimem/tiff_write_102.tif", 1, 1)
sr = osr.SpatialReference()
sr.ImportFromEPSG(7401)
name = sr.GetAttrValue("COMPD_CS")
wkt = sr.ExportToWkt()
ds.SetProjection(wkt)
ds = None
ds = gdal.Open("/vsimem/tiff_write_102.tif")
wkt1 = ds.GetProjectionRef()
ds = None
with gdaltest.config_option("GTIFF_REPORT_COMPD_CS", "NO"):
ds = gdal.Open("/vsimem/tiff_write_102.tif")
wkt2 = ds.GetProjectionRef()
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_102.tif")
assert wkt1.startswith("COMPD_CS"), "expected COMPD_CS, but got something else"
assert not wkt2.startswith("COMPD_CS"), "got COMPD_CS, but did not expected it"
sr2 = osr.SpatialReference()
sr2.SetFromUserInput(wkt1)
got_name = sr2.GetAttrValue("COMPD_CS")
assert got_name == name, wkt2
###############################################################################
# Test -co COPY_SRC_OVERVIEWS=YES on a multiband source with external overviews (#3938)
def test_tiff_write_103():
import test_cli_utilities
if test_cli_utilities.get_gdaladdo_path() is None:
pytest.skip()
gdal.Translate(
"tmp/tiff_write_103_src.tif", "data/rgbsmall.tif", options="-outsize 260 260"
)
gdaltest.runexternal(
test_cli_utilities.get_gdaladdo_path() + " -ro tmp/tiff_write_103_src.tif 2"
)
gdal.Translate(
"tmp/tiff_write_103_dst.tif",
"tmp/tiff_write_103_src.tif",
options="-co COPY_SRC_OVERVIEWS=YES",
)
src_ds = gdal.Open("tmp/tiff_write_103_src.tif")
dst_ds = gdal.Open("tmp/tiff_write_103_dst.tif")
src_cs = src_ds.GetRasterBand(1).GetOverview(0).Checksum()
dst_cs = dst_ds.GetRasterBand(1).GetOverview(0).Checksum()
src_ds = None
dst_ds = None
gdaltest.tiff_drv.Delete("tmp/tiff_write_103_src.tif")
gdaltest.tiff_drv.Delete("tmp/tiff_write_103_dst.tif")
assert src_cs == dst_cs, "did not get expected checksum"
###############################################################################
# Confirm as best we can that we can write geotiff files with detailed
# projection parameters with the correct linear units set. (#3901)
def test_tiff_write_104():
src_ds = gdal.Open("data/spaf27_correct.tif")
dst_ds = gdaltest.tiff_drv.CreateCopy("tmp/test_104.tif", src_ds)
src_ds = None
del dst_ds
ds = gdal.Open("tmp/test_104.tif")
wkt = ds.GetProjectionRef()
ds = None
srs = osr.SpatialReference(wkt)
fe = srs.GetProjParm(osr.SRS_PP_FALSE_EASTING)
assert fe == pytest.approx(
2000000.0, abs=0.001
), "did not get expected false easting"
gdaltest.tiff_drv.Delete("tmp/test_104.tif")
###############################################################################
# Confirm as best we can that we can write geotiff files with detailed
# projection parameters with the correct linear units set. (#3901)
def test_tiff_write_105():
shutil.copyfile("data/bug4468.tif", "tmp/bug4468.tif")
# Update a pixel and close again.
ds = gdal.Open("tmp/bug4468.tif", gdal.GA_Update)
data = ds.ReadRaster(0, 0, 1, 1)
ds.WriteRaster(0, 0, 1, 1, data)
ds = None
# Now check if the image is still intact.
ds = gdal.Open("tmp/bug4468.tif")
cs = ds.GetRasterBand(1).Checksum()
assert cs == 2923, "Did not get expected checksum, got %d." % cs
ds = None
gdaltest.tiff_drv.Delete("tmp/bug4468.tif")
###############################################################################
# Test the direct copy mechanism of JPEG source
@pytest.mark.require_creation_option("GTiff", "JPEG")
@pytest.mark.require_driver("JPEG")
@pytest.mark.parametrize(
"filename,options,check_cs",
[
("../gdrivers/data/jpeg/byte_with_xmp.jpg", None, True),
(
"../gdrivers/data/jpeg/byte_with_xmp.jpg",
["COMPRESS=JPEG", "BLOCKYSIZE=8"],
True,
),
(
"../gdrivers/data/jpeg/byte_with_xmp.jpg",
["COMPRESS=JPEG", "BLOCKYSIZE=20"],
True,
),
(
"../gdrivers/data/jpeg/byte_with_xmp.jpg",
["COMPRESS=JPEG", "TILED=YES", "BLOCKYSIZE=16", "BLOCKXSIZE=16"],
True,
),
# Strip organization of YCbCr does *NOT* give exact pixels w.r.t. original image
("../gdrivers/data/jpeg/albania.jpg", None, False),
# Whole copy of YCbCr *DOES* give exact pixels w.r.t. original image
(
"../gdrivers/data/jpeg/albania.jpg",
["COMPRESS=JPEG", "BLOCKYSIZE=260"],
False,
),
(
"../gdrivers/data/jpeg/albania.jpg",
["COMPRESS=JPEG", "BLOCKYSIZE=260", "INTERLEAVE=PIXEL"],
True,
),
(
"../gdrivers/data/jpeg/albania.jpg",
["COMPRESS=JPEG", "BLOCKYSIZE=260", "INTERLEAVE=BAND"],
False,
),
# Tiled organization of YCbCr does *NOT* give exact pixels w.r.t. original image
("../gdrivers/data/jpeg/albania.jpg", ["COMPRESS=JPEG", "TILED=YES"], False),
# The source is a JPEG in RGB colorspace (usually it is YCbCr).
(
"../gdrivers/data/jpeg/rgbsmall_rgb.jpg",
["COMPRESS=JPEG", "BLOCKYSIZE=8"],
True,
),
],
)
def test_tiff_write_direct_copy_jpeg(filename, options, check_cs):
if options is None:
options = ["COMPRESS=JPEG"]
src_ds = gdal.Open(filename)
nbands = src_ds.RasterCount
src_cs = []
for i in range(nbands):
src_cs.append(src_ds.GetRasterBand(i + 1).Checksum())
out_ds = gdaltest.tiff_drv.CreateCopy(
"/vsimem/tiff_write_106.tif", src_ds, options=options
)
out_ds = None
out_ds = gdal.Open("/vsimem/tiff_write_106.tif")
cs = []
for i in range(nbands):
cs.append(out_ds.GetRasterBand(i + 1).Checksum())
out_ds = None
gdal.Unlink("/vsimem/tiff_write_106.tif")
if check_cs:
for i in range(nbands):
assert cs[i] == src_cs[i], "did not get expected checksum"
else:
for i in range(nbands):
assert cs[i] != 0, "did not get expected checksum"
###############################################################################
# Test CreateCopy() interruption
def test_tiff_write_114():
tst = gdaltest.GDALTest("GTiff", "byte.tif", 1, 4672)
return tst.testCreateCopy(vsimem=1, interrupt_during_copy=True)
###############################################################################
# Test writing a pixel interleaved RGBA JPEG-compressed TIFF
@pytest.mark.require_creation_option("GTiff", "JPEG")
def test_tiff_write_115():
tmpfilename = "/vsimem/tiff_write_115.tif"
src_ds = gdal.Open("data/stefan_full_rgba.tif")
ds = gdaltest.tiff_drv.CreateCopy(tmpfilename, src_ds, options=["COMPRESS=JPEG"])
assert ds is not None
ds = None
src_ds = None
f = gdal.VSIFOpenL(tmpfilename + ".aux.xml", "rb")
if f is not None:
gdal.VSIFCloseL(f)
gdal.Unlink(tmpfilename)
pytest.fail()
ds = gdal.Open(tmpfilename)
md = ds.GetMetadata("IMAGE_STRUCTURE")
if md["INTERLEAVE"] != "PIXEL":
ds = None
gdal.Unlink(tmpfilename)
pytest.fail()
expected_cs = [16404, 62700, 37913, 14174]
for i in range(4):
cs = ds.GetRasterBand(i + 1).Checksum()
if cs != expected_cs[i]:
ds = None
gdal.Unlink(tmpfilename)
pytest.fail()
if (
ds.GetRasterBand(i + 1).GetRasterColorInterpretation()
!= gdal.GCI_RedBand + i
):
ds = None
gdal.Unlink(tmpfilename)
pytest.fail()
ds = None
gdal.Unlink(tmpfilename)
###############################################################################
# Test writing a band interleaved RGBA JPEG-compressed TIFF
@pytest.mark.require_creation_option("GTiff", "JPEG")
def test_tiff_write_116():
tmpfilename = "/vsimem/tiff_write_116.tif"
src_ds = gdal.Open("data/stefan_full_rgba.tif")
ds = gdaltest.tiff_drv.CreateCopy(
tmpfilename, src_ds, options=["COMPRESS=JPEG", "INTERLEAVE=BAND"]
)
assert ds is not None
ds = None
src_ds = None
f = gdal.VSIFOpenL(tmpfilename + ".aux.xml", "rb")
if f is not None:
gdal.VSIFCloseL(f)
gdal.Unlink(tmpfilename)
pytest.fail()
ds = gdal.Open(tmpfilename)
md = ds.GetMetadata("IMAGE_STRUCTURE")
if md["INTERLEAVE"] != "BAND":
ds = None
gdal.Unlink(tmpfilename)
pytest.fail()
expected_cs = [16404, 62700, 37913, 14174]
for i in range(4):
cs = ds.GetRasterBand(i + 1).Checksum()
if cs != expected_cs[i]:
ds = None
gdal.Unlink(tmpfilename)
pytest.fail()
if (
ds.GetRasterBand(i + 1).GetRasterColorInterpretation()
!= gdal.GCI_RedBand + i
):
ds = None
gdal.Unlink(tmpfilename)
pytest.fail()
ds = None
gdal.Unlink(tmpfilename)
###############################################################################
# Test bugfix for ticket #4771 (rewriting of a deflate compressed tile, libtiff bug)
def test_tiff_write_117():
# This fail with a libtiff 4.x older than 2012-08-13
md = gdaltest.tiff_drv.GetMetadata()
if md["LIBTIFF"] != "INTERNAL":
pytest.skip()
import random
# so that we have always the same random :-)
random.seed(0)
ds = gdal.GetDriverByName("GTiff").Create(
"/vsimem/tiff_write_117.tif",
512,
256,
2,
options=["COMPRESS=DEFLATE", "TILED=YES"],
)
# Write first tile so that its byte count of that tile is 2048 (a multiple of 1024)
adjust = 1254
data = "0" * (65536 - adjust) + "".join(
[("%c" % random.randint(0, 255)) for _ in range(adjust)]
)
ds.GetRasterBand(1).WriteRaster(0, 0, 256, 256, data)
# Second tile will be implicitly written at closing, or we could write
# any content
ds = None
ds = gdal.Open("/vsimem/tiff_write_117.tif", gdal.GA_Update)
# Will adjust tif_rawdatasize to TIFFroundup_64((uint64)size, 1024) = TIFFroundup_64(2048, 1024) = 2048
ds.GetRasterBand(1).ReadRaster(0, 0, 256, 256)
# The new bytecount will be greater than 2048
data = "".join([("%c" % random.randint(0, 255)) for _ in range(256 * 256)])
ds.GetRasterBand(1).WriteRaster(0, 0, 256, 256, data)
# Make sure that data is written now
ds.FlushCache()
# Oops, without fix, the second tile will have been overwritten and an error will be emitted
data = ds.GetRasterBand(1).ReadRaster(256, 0, 256, 256)
ds = None
gdal.Unlink("/vsimem/tiff_write_117.tif")
assert (
data is not None
), "if GDAL is configured with external libtiff 4.x, it can fail if it is older than 4.0.3. With internal libtiff, should not fail"
###############################################################################
# Test bugfix for ticket gh #4538 (rewriting of a deflate compressed tile, libtiff bug)
def test_tiff_write_rewrite_in_place_issue_gh_4538():
# This fail with libtiff <= 4.3.0
md = gdaltest.tiff_drv.GetMetadata()
if md["LIBTIFF"] != "INTERNAL":
pytest.skip()
# Defeats the logic that fixed test_tiff_write_117
import array
filename = "/vsimem/tmp.tif"
ds = gdal.GetDriverByName("GTiff").Create(
filename,
144 * 2,
128,
1,
options=["TILED=YES", "COMPRESS=PACKBITS", "BLOCKXSIZE=144", "BLOCKYSIZE=128"],
)
x = ((144 * 128) // 2) - 645
ds.GetRasterBand(1).WriteRaster(
0,
0,
144,
128,
b"\x00" * x + array.array("B", [i % 255 for i in range(144 * 128 - x)]),
)
block1_data = b"\x00" * (x + 8) + array.array(
"B", [i % 255 for i in range(144 * 128 - (x + 8))]
)
ds.GetRasterBand(1).WriteRaster(144, 0, 144, 128, block1_data)
ds = None
ds = gdal.Open(filename, gdal.GA_Update)
ds.GetRasterBand(1).ReadRaster(144, 0, 144, 128)
block0_data = array.array("B", [i % 255 for i in range(144 * 128)])
ds.GetRasterBand(1).WriteRaster(0, 0, 144, 128, block0_data)
ds = None
ds = gdal.Open(filename)
assert ds.GetRasterBand(1).ReadRaster(0, 0, 144, 128) == block0_data
assert ds.GetRasterBand(1).ReadRaster(144, 0, 144, 128) == block1_data
ds = None
gdal.Unlink(filename)
###############################################################################
# Test bugfix for ticket #4816
def test_tiff_write_118():
ds = gdal.GetDriverByName("GTiff").Create("/vsimem/tiff_write_118.tif", 1, 1)
# Should be rejected in a non-XML domain
ds.SetMetadata("bla", "foo")
ds = None
ds = gdal.Open("/vsimem/tiff_write_118.tif")
md = ds.GetMetadata("foo")
ds = None
gdal.Unlink("/vsimem/tiff_write_118.tif")
assert not md
###############################################################################
# Test bugfix for ticket #4816
def test_tiff_write_119():
ds = gdal.GetDriverByName("GTiff").Create("/vsimem/tiff_write_119.tif", 1, 1)
ds.SetMetadata("foo=bar", "foo")
ds = None
ds = gdal.Open("/vsimem/tiff_write_119.tif")
md = ds.GetMetadata("foo")
ds = None
gdal.Unlink("/vsimem/tiff_write_119.tif")
assert md["foo"] == "bar"
###############################################################################
# Test bugfix for ticket #4816
def test_tiff_write_120():
ds = gdal.GetDriverByName("GTiff").Create("/vsimem/tiff_write_120.tif", 1, 1)
ds.SetMetadata("<foo/>", "xml:foo")
ds = None
ds = gdal.Open("/vsimem/tiff_write_120.tif")
md = ds.GetMetadata("xml:foo")
ds = None
gdal.Unlink("/vsimem/tiff_write_120.tif")
assert len(md) == 1
assert md[0] == "<foo/>"
###############################################################################
# Test error cases of COPY_SRC_OVERVIEWS creation option
def test_tiff_write_121():
# Test when the overview band is NULL
src_ds = gdal.Open(
"""<VRTDataset rasterXSize="20" rasterYSize="20">
<VRTRasterBand dataType="Byte" band="1">
<SimpleSource>
<SourceFilename relativeToVRT="1">data/byte.tif</SourceFilename>
<SourceBand>1</SourceBand>
</SimpleSource>
<Overview>
<SourceFilename relativeToVRT="0">non_existing</SourceFilename>
<SourceBand>1</SourceBand>
</Overview>
</VRTRasterBand>
</VRTDataset>"""
)
with gdaltest.error_handler():
ds = gdaltest.tiff_drv.CreateCopy(
"/vsimem/tiff_write_121.tif", src_ds, options=["COPY_SRC_OVERVIEWS=YES"]
)
assert ds is None
src_ds = None
# Test when the overview count isn't the same on all base bands
src_ds = gdal.Open(
"""<VRTDataset rasterXSize="20" rasterYSize="20">
<VRTRasterBand dataType="Byte" band="1">
<SimpleSource>
<SourceFilename relativeToVRT="1">data/byte.tif</SourceFilename>
<SourceBand>1</SourceBand>
</SimpleSource>
<Overview>
<SourceFilename relativeToVRT="1">data/byte.tif</SourceFilename>
<SourceBand>1</SourceBand>
</Overview>
</VRTRasterBand>
<VRTRasterBand dataType="Byte" band="2">
<SimpleSource>
<SourceFilename relativeToVRT="1">data/byte.tif</SourceFilename>
<SourceBand>1</SourceBand>
</SimpleSource>
</VRTRasterBand>
</VRTDataset>"""
)
with gdaltest.error_handler():
ds = gdaltest.tiff_drv.CreateCopy(
"/vsimem/tiff_write_121.tif", src_ds, options=["COPY_SRC_OVERVIEWS=YES"]
)
assert ds is None
src_ds = None
# Test when the overview bands of same level have not the same dimensions
src_ds = gdal.Open(
"""<VRTDataset rasterXSize="20" rasterYSize="20">
<VRTRasterBand dataType="Byte" band="1">
<SimpleSource>
<SourceFilename relativeToVRT="1">data/byte.tif</SourceFilename>
<SourceBand>1</SourceBand>
</SimpleSource>
<Overview>
<SourceFilename relativeToVRT="1">data/byte.tif</SourceFilename>
<SourceBand>1</SourceBand>
</Overview>
</VRTRasterBand>
<VRTRasterBand dataType="Byte" band="2">
<SimpleSource>
<SourceFilename relativeToVRT="1">data/byte.tif</SourceFilename>
<SourceBand>1</SourceBand>
</SimpleSource>
<Overview>
<SourceFilename relativeToVRT="0">data/rgbsmall.tif</SourceFilename>
<SourceBand>1</SourceBand>
</Overview>
</VRTRasterBand>
</VRTDataset>"""
)
with gdaltest.error_handler():
ds = gdaltest.tiff_drv.CreateCopy(
"/vsimem/tiff_write_121.tif", src_ds, options=["COPY_SRC_OVERVIEWS=YES"]
)
assert ds is None
src_ds = None
###############################################################################
# Test write and read of some TIFFTAG_RESOLUTIONUNIT tags where '*'/'' is
# specified (gdalwarp conflicts)
# Expected to fail (properly) with older libtiff versions (<=3.8.2 for sure)
def test_tiff_write_122():
new_ds = gdaltest.tiff_drv.Create("tmp/tags122.tif", 1, 1, 1)
new_ds.SetMetadata(
{
"TIFFTAG_RESOLUTIONUNIT": "*",
}
)
new_ds = None
# hopefully it's closed now!
new_ds = gdal.Open("tmp/tags122.tif")
md = new_ds.GetMetadata()
if "TIFFTAG_RESOLUTIONUNIT" not in md:
pytest.fail("Couldn't find tag TIFFTAG_RESOLUTIONUNIT")
elif md["TIFFTAG_RESOLUTIONUNIT"] != "1 (unitless)":
pytest.fail(
"Got unexpected tag TIFFTAG_RESOLUTIONUNIT='%s' (expected ='1 (unitless)')"
% md["TIFFTAG_RESOLUTIONUNIT"]
)
new_ds = None
gdaltest.tiff_drv.Delete("tmp/tags122.tif")
###############################################################################
# Test implicit photometric interpretation
def test_tiff_write_123():
src_ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_123_src.tif", 1, 1, 5, gdal.GDT_Int16
)
src_ds.GetRasterBand(2).SetColorInterpretation(gdal.GCI_GreenBand)
src_ds.GetRasterBand(5).SetColorInterpretation(gdal.GCI_AlphaBand)
src_ds.GetRasterBand(3).SetColorInterpretation(gdal.GCI_BlueBand)
src_ds.GetRasterBand(1).SetColorInterpretation(gdal.GCI_RedBand)
src_ds = None
statBuf = gdal.VSIStatL(
"/vsimem/tiff_write_123_src.tif.aux.xml",
gdal.VSI_STAT_EXISTS_FLAG | gdal.VSI_STAT_NATURE_FLAG | gdal.VSI_STAT_SIZE_FLAG,
)
assert statBuf is None, "did not expect PAM file"
src_ds = gdal.Open("/vsimem/tiff_write_123_src.tif")
assert (
src_ds.GetMetadataItem("TIFFTAG_GDAL_METADATA", "_DEBUG_") is None
), "did not expect a TIFFTAG_GDAL_METADATA tag"
assert src_ds.GetMetadataItem("TIFFTAG_PHOTOMETRIC", "_DEBUG_") == "2"
assert src_ds.GetRasterBand(1).GetColorInterpretation() == gdal.GCI_RedBand
assert src_ds.GetRasterBand(4).GetColorInterpretation() == gdal.GCI_Undefined
assert src_ds.GetRasterBand(5).GetColorInterpretation() == gdal.GCI_AlphaBand
assert src_ds.GetMetadataItem("TIFFTAG_EXTRASAMPLES", "_DEBUG_") == "0,2"
new_ds = gdaltest.tiff_drv.CreateCopy("/vsimem/tiff_write_123.tif", src_ds)
del new_ds
statBuf = gdal.VSIStatL(
"/vsimem/tiff_write_123.tif.aux.xml",
gdal.VSI_STAT_EXISTS_FLAG | gdal.VSI_STAT_NATURE_FLAG | gdal.VSI_STAT_SIZE_FLAG,
)
assert statBuf is None, "did not expect PAM file"
ds = gdal.Open("/vsimem/tiff_write_123.tif")
assert (
ds.GetMetadataItem("TIFFTAG_GDAL_METADATA", "_DEBUG_") is None
), "did not expect a TIFFTAG_GDAL_METADATA tag"
assert ds.GetRasterBand(1).GetColorInterpretation() == gdal.GCI_RedBand
assert src_ds.GetRasterBand(4).GetColorInterpretation() == gdal.GCI_Undefined
assert src_ds.GetRasterBand(5).GetColorInterpretation() == gdal.GCI_AlphaBand
assert ds.GetMetadataItem("TIFFTAG_EXTRASAMPLES", "_DEBUG_") == "0,2"
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_123_src.tif")
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_123.tif")
# From implicit RGB to BGR (with Photometric = MinIsBlack)
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_123_bgr.tif", 1, 1, 3, gdal.GDT_Byte
)
assert ds.GetMetadataItem("TIFFTAG_PHOTOMETRIC", "_DEBUG_") == "2"
assert ds.GetMetadataItem("TIFFTAG_EXTRASAMPLES", "_DEBUG_") is None
ds.GetRasterBand(1).SetColorInterpretation(gdal.GCI_BlueBand)
assert ds.GetRasterBand(1).GetColorInterpretation() == gdal.GCI_BlueBand
ds.GetRasterBand(2).SetColorInterpretation(gdal.GCI_GreenBand)
ds.GetRasterBand(3).SetColorInterpretation(gdal.GCI_RedBand)
ds = None
statBuf = gdal.VSIStatL(
"/vsimem/tiff_write_123_bgr.tif.aux.xml",
gdal.VSI_STAT_EXISTS_FLAG | gdal.VSI_STAT_NATURE_FLAG | gdal.VSI_STAT_SIZE_FLAG,
)
assert statBuf is None, "did not expect a PAM file"
ds = gdal.Open("/vsimem/tiff_write_123_bgr.tif")
assert ds.GetMetadataItem("TIFFTAG_PHOTOMETRIC", "_DEBUG_") == "1"
assert ds.GetMetadataItem("TIFFTAG_EXTRASAMPLES", "_DEBUG_") == "0,0"
assert (
ds.GetMetadataItem("TIFFTAG_GDAL_METADATA", "_DEBUG_") is not None
), "expected a TIFFTAG_GDAL_METADATA tag"
assert ds.GetRasterBand(1).GetColorInterpretation() == gdal.GCI_BlueBand
assert ds.GetRasterBand(2).GetColorInterpretation() == gdal.GCI_GreenBand
assert ds.GetRasterBand(3).GetColorInterpretation() == gdal.GCI_RedBand
ds = None
# Test overriding internal color interpretation with PAM one (read-only mode)
ds = gdal.Open("/vsimem/tiff_write_123_bgr.tif")
ds.GetRasterBand(1).SetColorInterpretation(gdal.GCI_RedBand)
ds = None
statBuf = gdal.VSIStatL(
"/vsimem/tiff_write_123_bgr.tif.aux.xml",
gdal.VSI_STAT_EXISTS_FLAG | gdal.VSI_STAT_NATURE_FLAG | gdal.VSI_STAT_SIZE_FLAG,
)
assert statBuf is not None, "expected a PAM file"
ds = gdal.Open("/vsimem/tiff_write_123_bgr.tif")
assert ds.GetRasterBand(1).GetColorInterpretation() == gdal.GCI_RedBand
assert ds.GetRasterBand(2).GetColorInterpretation() == gdal.GCI_GreenBand
assert ds.GetRasterBand(3).GetColorInterpretation() == gdal.GCI_RedBand
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_123_bgr.tif")
# Create a BGR with PROFILE=BASELINE --> no TIFFTAG_GDAL_METADATA tag, but .aux.xml instead
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_123_bgr.tif", 1, 1, 3, options=["PROFILE=BASELINE"]
)
ds.GetRasterBand(1).SetColorInterpretation(gdal.GCI_BlueBand)
ds.GetRasterBand(2).SetColorInterpretation(gdal.GCI_GreenBand)
ds.GetRasterBand(3).SetColorInterpretation(gdal.GCI_RedBand)
ds = None
statBuf = gdal.VSIStatL(
"/vsimem/tiff_write_123_bgr.tif.aux.xml",
gdal.VSI_STAT_EXISTS_FLAG | gdal.VSI_STAT_NATURE_FLAG | gdal.VSI_STAT_SIZE_FLAG,
)
assert statBuf is not None, "expected a PAM file"
ds = gdal.Open("/vsimem/tiff_write_123_bgr.tif")
assert (
ds.GetMetadataItem("TIFFTAG_GDAL_METADATA", "_DEBUG_") is None
), "did not expect a TIFFTAG_GDAL_METADATA tag"
assert ds.GetRasterBand(1).GetColorInterpretation() == gdal.GCI_BlueBand
assert ds.GetRasterBand(2).GetColorInterpretation() == gdal.GCI_GreenBand
assert ds.GetRasterBand(3).GetColorInterpretation() == gdal.GCI_RedBand
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_123_bgr.tif")
# From implicit RGBA to MINISBLACK
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_123_rgba.tif", 1, 1, 4, gdal.GDT_Byte
)
assert ds.GetMetadataItem("TIFFTAG_PHOTOMETRIC", "_DEBUG_") == "2"
assert ds.GetRasterBand(1).GetColorInterpretation() == gdal.GCI_RedBand
assert ds.GetRasterBand(4).GetColorInterpretation() == gdal.GCI_AlphaBand
assert ds.GetMetadataItem("TIFFTAG_EXTRASAMPLES", "_DEBUG_") == "2"
ds.GetRasterBand(1).SetColorInterpretation(gdal.GCI_Undefined)
assert ds.GetRasterBand(1).GetColorInterpretation() == gdal.GCI_Undefined
assert ds.GetMetadataItem("TIFFTAG_PHOTOMETRIC", "_DEBUG_") == "1"
assert ds.GetMetadataItem("TIFFTAG_EXTRASAMPLES", "_DEBUG_") == "0,0,2"
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_123_rgba.tif")
# From that implicit RGBA to Gray,Undefined,Undefined,Alpha doesn't
# produce PAM file
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_123_guua.tif", 1, 1, 4, gdal.GDT_Byte
)
ds.GetRasterBand(1).SetColorInterpretation(gdal.GCI_GrayIndex)
ds.GetRasterBand(2).SetColorInterpretation(gdal.GCI_Undefined)
ds.GetRasterBand(3).SetColorInterpretation(gdal.GCI_Undefined)
ds.GetRasterBand(4).SetColorInterpretation(gdal.GCI_AlphaBand)
ds = None
statBuf = gdal.VSIStatL(
"/vsimem/tiff_write_123_guua.tif.aux.xml",
gdal.VSI_STAT_EXISTS_FLAG | gdal.VSI_STAT_NATURE_FLAG | gdal.VSI_STAT_SIZE_FLAG,
)
assert statBuf is None, "did not expect PAM file"
ds = gdal.Open("/vsimem/tiff_write_123_guua.tif")
assert (
ds.GetMetadataItem("TIFFTAG_GDAL_METADATA", "_DEBUG_") is None
), "did not expect TIFFTAG_GDAL_METADATA tag"
assert ds.GetRasterBand(1).GetColorInterpretation() == gdal.GCI_GrayIndex
assert ds.GetRasterBand(4).GetColorInterpretation() == gdal.GCI_AlphaBand
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_123_guua.tif")
# Test that CreateCopy() from a RGB UInt16 doesn't generate ExtraSamples
src_ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_123_rgb_src.tif",
1,
1,
3,
gdal.GDT_UInt16,
options=["PHOTOMETRIC=RGB"],
)
ds = gdaltest.tiff_drv.CreateCopy("/vsimem/tiff_write_123_rgb.tif", src_ds)
src_ds = None
assert ds.GetMetadataItem("TIFFTAG_PHOTOMETRIC", "_DEBUG_") == "2"
assert ds.GetMetadataItem("TIFFTAG_EXTRASAMPLES", "_DEBUG_") is None
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_123_rgb_src.tif")
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_123_rgb.tif")
# Test that PHOTOMETRIC=RGB overrides the source color interpretation of the
# first 3 bands
src_ds = gdal.GetDriverByName("MEM").Create("", 1, 1, 3)
gdaltest.tiff_drv.CreateCopy(
"/vsimem/tiff_write_123_rgb.tif", src_ds, options=["PHOTOMETRIC=RGB"]
)
ds = gdal.Open("/vsimem/tiff_write_123_rgb.tif")
assert ds.GetRasterBand(1).GetColorInterpretation() == gdal.GCI_RedBand
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_123_rgb.tif")
src_ds = gdal.GetDriverByName("MEM").Create("", 1, 1, 5)
src_ds.GetRasterBand(5).SetColorInterpretation(gdal.GCI_AlphaBand)
gdaltest.tiff_drv.CreateCopy(
"/vsimem/tiff_write_123_rgbua.tif", src_ds, options=["PHOTOMETRIC=RGB"]
)
ds = gdal.Open("/vsimem/tiff_write_123_rgbua.tif")
assert ds.GetRasterBand(1).GetColorInterpretation() == gdal.GCI_RedBand
assert ds.GetRasterBand(4).GetColorInterpretation() == gdal.GCI_Undefined
assert ds.GetRasterBand(5).GetColorInterpretation() == gdal.GCI_AlphaBand
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_123_rgbua.tif")
# Test updating alpha to undefined
gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_123_rgba_to_undefined.tif",
1,
1,
4,
options=["PHOTOMETRIC=RGB", "ALPHA=YES"],
)
ds = gdal.Open("/vsimem/tiff_write_123_rgba_to_undefined.tif", gdal.GA_Update)
ds.GetRasterBand(4).SetColorInterpretation(gdal.GCI_Undefined)
ds = None
statBuf = gdal.VSIStatL(
"/vsimem/tiff_write_123_rgba_to_undefined.tif.aux.xml",
gdal.VSI_STAT_EXISTS_FLAG | gdal.VSI_STAT_NATURE_FLAG | gdal.VSI_STAT_SIZE_FLAG,
)
assert statBuf is None, "did not expect PAM file"
ds = gdal.Open("/vsimem/tiff_write_123_rgba_to_undefined.tif")
assert ds.GetRasterBand(4).GetColorInterpretation() == gdal.GCI_Undefined
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_123_rgba_to_undefined.tif")
###############################################################################
# Test error cases with palette creation
def test_tiff_write_124():
ds = gdaltest.tiff_drv.Create("/vsimem/tiff_write_124.tif", 1, 1, 3, gdal.GDT_Byte)
with gdaltest.error_handler():
# Test "SetColorTable() can only be called on band 1"
ret = ds.GetRasterBand(2).SetColorTable(gdal.ColorTable())
assert ret != 0
with gdaltest.error_handler():
# Test "SetColorTable() not supported for multi-sample TIFF files"
ret = ds.GetRasterBand(1).SetColorTable(gdal.ColorTable())
assert ret != 0
ds = None
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_124.tif", 1, 1, 1, gdal.GDT_UInt32
)
with gdaltest.error_handler():
# Test "SetColorTable() only supported for Byte or UInt16 bands in TIFF format."
ret = ds.GetRasterBand(1).SetColorTable(gdal.ColorTable())
assert ret != 0
ds = None
with gdaltest.error_handler():
# Test "SetColorTable() only supported for Byte or UInt16 bands in TIFF format."
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_124.tif",
1,
1,
1,
gdal.GDT_UInt32,
options=["PHOTOMETRIC=PALETTE"],
)
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_124.tif")
###############################################################################
# Test out-of-memory conditions with SplitBand and SplitBitmapBand
def test_tiff_write_125():
if gdal.GetConfigOption("SKIP_MEM_INTENSIVE_TEST") is not None:
pytest.skip()
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_125.tif",
2147000000,
5000,
65535,
options=["SPARSE_OK=YES", "BLOCKYSIZE=5000", "COMPRESS=LZW", "BIGTIFF=NO"],
)
ds = None
ds = gdal.Open("/vsimem/tiff_write_125.tif")
# Will not open on 32-bit due to overflow
if ds is not None:
with gdaltest.error_handler():
ds.GetRasterBand(1).ReadBlock(0, 0)
ds = gdal.GetDriverByName("GTiff").Create(
"/vsimem/tiff_write_125.tif",
2147000000,
5000,
1,
options=[
"NBITS=1",
"SPARSE_OK=YES",
"BLOCKYSIZE=5000",
"COMPRESS=LZW",
"BIGTIFF=NO",
],
)
ds = None
ds = gdal.Open("/vsimem/tiff_write_125.tif")
# Will not open on 32-bit due to overflow
if ds is not None:
with gdaltest.error_handler():
ds.GetRasterBand(1).ReadBlock(0, 0)
gdal.Unlink("/vsimem/tiff_write_125.tif")
###############################################################################
# Test implicit JPEG-in-TIFF overviews
@pytest.mark.require_creation_option("GTiff", "JPEG")
@pytest.mark.require_driver("JPEG")
def test_tiff_write_126():
src_ds = gdal.Open("../gdrivers/data/small_world_400pct.vrt")
options_list = [
(
["COMPRESS=JPEG", "PHOTOMETRIC=YCBCR"],
[48788, 56561, 56462],
[61397, 2463, 2454, 2727],
[29605, 33654, 34633],
[10904, 10453, 10361],
),
(
["COMPRESS=JPEG", "PHOTOMETRIC=YCBCR", "JPEGTABLESMODE=0"],
[48788, 56561, 56462],
[61397, 2463, 2454, 2727],
[29605, 33654, 34633],
[10904, 10453, 10361],
),
(
["COMPRESS=JPEG", "PHOTOMETRIC=YCBCR", "TILED=YES"],
[48788, 56561, 56462],
[61397, 2463, 2454, 2727],
[29605, 33654, 34633],
[10904, 10453, 10361],
),
(
["COMPRESS=JPEG", "PHOTOMETRIC=YCBCR", "BLOCKYSIZE=800"],
[48788, 56561, 56462],
[61397, 2463, 2454, 2727],
[29605, 33654, 34633],
[10904, 10453, 10361],
),
(
["COMPRESS=JPEG", "PHOTOMETRIC=YCBCR", "BLOCKYSIZE=64"],
[48788, 56561, 56462],
[61397, 2463, 2454, 2727],
[29605, 33654, 34633],
[10904, 10453, 10361],
),
(
["COMPRESS=JPEG"],
[49887, 58937],
[59311, 2826],
[30829, 34806],
[11664, 58937],
),
(
["COMPRESS=JPEG", "INTERLEAVE=BAND"],
[49887, 58937],
[59311, 2826],
[30829, 34806],
[11664, 58937],
),
(
["COMPRESS=JPEG", "INTERLEAVE=BAND", "TILED=YES"],
[49887, 58937],
[59311, 2826],
[30829, 34806],
[11664, 58937],
),
(
["COMPRESS=JPEG", "INTERLEAVE=BAND", "BLOCKYSIZE=800"],
[49887, 58937],
[59311, 2826],
[30829, 34806],
[11664, 58937],
),
(
["COMPRESS=JPEG", "INTERLEAVE=BAND", "BLOCKYSIZE=32"],
[49887, 58937],
[59311, 2826],
[30829, 34806],
[11664, 58937],
),
(
["COMPRESS=JPEG", "BLOCKYSIZE=8"],
[49887, 58937],
[59311, 2826],
[30829, 34806],
[11664, 58937],
),
]
for (options, cs1, cs2, cs3, cs4) in options_list:
os.environ["JPEGMEM"] = "500M"
ds = gdaltest.tiff_drv.CreateCopy(
"/vsimem/tiff_write_126.tif", src_ds, options=options
)
ds = None
del os.environ["JPEGMEM"]
ds = gdal.Open("/vsimem/tiff_write_126.tif")
# Officially we have 0 public overviews...
assert ds.GetRasterBand(1).GetOverviewCount() == 0, options
# But they do exist...
cs = ds.GetRasterBand(1).GetOverview(0).Checksum()
assert cs in cs1, options
cs = ds.GetRasterBand(2).GetOverview(0).Checksum()
assert cs in cs2, options
cs = ds.GetRasterBand(1).GetOverview(1).Checksum()
assert cs in cs3, options
cs = ds.GetRasterBand(1).GetOverview(2).Checksum()
assert cs in cs4, options
assert ds.GetRasterBand(1).GetOverview(-1) is None, options
assert ds.GetRasterBand(1).GetOverview(3) is None, options
ovr_1_data = (
ds.GetRasterBand(1).GetOverview(1).GetDataset().ReadRaster(0, 0, 400, 200)
)
subsampled_data = ds.ReadRaster(0, 0, 1600, 800, 400, 200)
assert ovr_1_data == subsampled_data, options
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_126.tif")
src_ds = gdal.Open("../gdrivers/data/small_world_400pct_1band.vrt")
options_list = [
(["COMPRESS=JPEG"], [49887, 58937], [30829, 34806], [11664, 58937]),
(
["COMPRESS=JPEG", "TILED=YES"],
[49887, 58937],
[30829, 34806],
[11664, 58937],
),
(
["COMPRESS=JPEG", "BLOCKYSIZE=800"],
[49887, 58937],
[30829, 34806],
[11664, 58937],
),
(
["COMPRESS=JPEG", "BLOCKYSIZE=32"],
[49887, 58937],
[30829, 34806],
[11664, 58937],
),
]
for (options, cs1, cs3, cs4) in options_list:
os.environ["JPEGMEM"] = "500M"
ds = gdaltest.tiff_drv.CreateCopy(
"/vsimem/tiff_write_126.tif", src_ds, options=options
)
ds = None
del os.environ["JPEGMEM"]
ds = gdal.Open("/vsimem/tiff_write_126.tif")
# Officially we have 0 public overviews...
assert ds.GetRasterBand(1).GetOverviewCount() == 0, options
# But they do exist...
cs = ds.GetRasterBand(1).GetOverview(0).Checksum()
assert cs in cs1, options
cs = ds.GetRasterBand(1).GetOverview(1).Checksum()
assert cs in cs3, options
cs = ds.GetRasterBand(1).GetOverview(2).Checksum()
assert cs in cs4, options
ovr_1_data = (
ds.GetRasterBand(1).GetOverview(1).GetDataset().ReadRaster(0, 0, 400, 200)
)
subsampled_data = ds.ReadRaster(0, 0, 1600, 800, 400, 200)
assert ovr_1_data == subsampled_data, options
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_126.tif")
# Test single-strip, opened as split band
src_ds = gdaltest.tiff_drv.Create("/vsimem/tiff_write_126_src.tif", 8, 2001)
src_ds.GetRasterBand(1).Fill(255)
ds = gdaltest.tiff_drv.CreateCopy(
"/vsimem/tiff_write_126.tif",
src_ds,
options=["COMPRESS=JPEG", "BLOCKYSIZE=2001"],
)
src_ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_126_src.tif")
ds = None
ds = gdal.Open("/vsimem/tiff_write_126.tif")
assert ds.GetRasterBand(1).GetBlockSize() == [8, 1]
ovr_ds = ds.GetRasterBand(1).GetOverview(1).GetDataset()
ovr_1_data = ovr_ds.ReadRaster(0, 0, ovr_ds.RasterXSize, ovr_ds.RasterYSize, 1, 1)
subsampled_data = ds.ReadRaster(0, 0, ds.RasterXSize, ds.RasterYSize, 1, 1)
assert ovr_1_data == subsampled_data
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_126.tif")
# We need libtiff 4.0.4 (unreleased at that time)
md = gdaltest.tiff_drv.GetMetadata()
if md["LIBTIFF"] != "INTERNAL":
print("skipping tests that will fail without internal libtiff")
return
# Test with completely sparse file
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_126.tif",
1024,
1024,
options=["COMPRESS=JPEG", "SPARSE_OK=YES"],
)
ds = None
ds = gdal.Open("/vsimem/tiff_write_126.tif")
assert ds.GetRasterBand(1).GetOverview(0) is not None
assert ds.GetRasterBand(1).GetMetadataItem("JPEGTABLES", "TIFF") is not None
assert ds.GetRasterBand(1).GetMetadataItem("BLOCK_OFFSET_0_0", "TIFF") is None
assert ds.GetRasterBand(1).GetMetadataItem("BLOCK_SIZE_0_0", "TIFF") is None
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_126.tif")
# Test with partially sparse file
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_126.tif",
1024,
1024,
3,
options=["COMPRESS=JPEG", "SPARSE_OK=YES", "INTERLEAVE=BAND"],
)
# Fill band 3, but let blocks of band 1 unwritten.
ds.GetRasterBand(3).Fill(0)
ds = None
ds = gdal.Open("/vsimem/tiff_write_126.tif")
cs = ds.GetRasterBand(1).GetOverview(0).Checksum()
assert cs == 0
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_126.tif")
###############################################################################
# Test setting/unsetting metadata in update mode (#5628)
def test_tiff_write_127():
ds = gdaltest.tiff_drv.Create("/vsimem/tiff_write_127.tif", 1, 1)
ds = None
for i in range(2):
ds = gdal.Open("/vsimem/tiff_write_127.tif", gdal.GA_Update)
obj = ds if i == 0 else ds.GetRasterBand(1)
obj.SetMetadata({"key": "value"})
obj = None
ds = None
ds = gdal.Open("/vsimem/tiff_write_127.tif", gdal.GA_Update)
obj = ds if i == 0 else ds.GetRasterBand(1)
if obj.GetMetadataItem("key") != "value":
print(i)
pytest.fail(obj.GetMetadata())
obj.SetMetadata({})
obj = None
ds = None
ds = gdal.Open("/vsimem/tiff_write_127.tif", gdal.GA_Update)
obj = ds if i == 0 else ds.GetRasterBand(1)
assert not obj.GetMetadata(), i
obj.SetMetadataItem("key", "value")
obj = None
ds = None
ds = gdal.Open("/vsimem/tiff_write_127.tif", gdal.GA_Update)
obj = ds if i == 0 else ds.GetRasterBand(1)
assert obj.GetMetadataItem("key") == "value", i
obj.SetMetadataItem("key", None)
obj = None
ds = None
ds = gdal.Open("/vsimem/tiff_write_127.tif", gdal.GA_Update)
obj = ds if i == 0 else ds.GetRasterBand(1)
assert not obj.GetMetadata(), i
obj = None
ds = None
statBuf = gdal.VSIStatL("/vsimem/tiff_write_127.tif.aux.xml")
if statBuf is not None:
print(i)
pytest.fail("unexpected PAM file")
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_127.tif")
###############################################################################
# Test lossless copying of a CMYK JPEG into JPEG-in-TIFF (#5712)
@pytest.mark.require_creation_option("GTiff", "JPEG")
@pytest.mark.require_driver("JPEG")
def test_tiff_write_128():
with gdal.config_option("GDAL_JPEG_TO_RGB", "NO"):
src_ds = gdal.Open("../gdrivers/data/jpeg/rgb_ntf_cmyk.jpg")
# Will received implicitly CMYK photometric interpretation.
with gdal.config_option("GDAL_PAM_ENABLED", "NO"):
ds = gdaltest.tiff_drv.CreateCopy(
"/vsimem/tiff_write_128.tif", src_ds, options=["COMPRESS=JPEG"]
)
ds = None
# We need to reopen in raw to avoig automatic CMYK->RGBA to trigger
ds = gdal.Open("GTIFF_RAW:/vsimem/tiff_write_128.tif")
for i in range(4):
assert (
src_ds.GetRasterBand(i + 1).GetColorInterpretation()
== ds.GetRasterBand(i + 1).GetColorInterpretation()
)
assert (
src_ds.GetRasterBand(i + 1).Checksum() == ds.GetRasterBand(i + 1).Checksum()
)
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_128.tif")
# Try with explicit CMYK photometric interpretation
with gdal.config_option("GDAL_PAM_ENABLED", "NO"):
ds = gdaltest.tiff_drv.CreateCopy(
"/vsimem/tiff_write_128.tif",
src_ds,
options=["COMPRESS=JPEG", "PHOTOMETRIC=CMYK"],
)
ds = None
# We need to reopen in raw to avoig automatic CMYK->RGBA to trigger
ds = gdal.Open("GTIFF_RAW:/vsimem/tiff_write_128.tif")
for i in range(4):
assert (
src_ds.GetRasterBand(i + 1).GetColorInterpretation()
== ds.GetRasterBand(i + 1).GetColorInterpretation()
)
assert (
src_ds.GetRasterBand(i + 1).Checksum() == ds.GetRasterBand(i + 1).Checksum()
)
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_128.tif")
# Try with more neutral colorspace in the case the source JPEG is not really CMYK (yes that happens !)
with gdal.config_option("GDAL_PAM_ENABLED", "NO"):
ds = gdaltest.tiff_drv.CreateCopy(
"/vsimem/tiff_write_128.tif",
src_ds,
options=["COMPRESS=JPEG", "PHOTOMETRIC=MINISBLACK", "PROFILE=BASELINE"],
)
ds = None
# Here we can reopen without GTIFF_RAW trick
ds = gdal.Open("/vsimem/tiff_write_128.tif")
for i in range(4):
# The color interpretation will NOT be CMYK
assert (
src_ds.GetRasterBand(i + 1).GetColorInterpretation()
!= ds.GetRasterBand(i + 1).GetColorInterpretation()
)
assert (
src_ds.GetRasterBand(i + 1).Checksum() == ds.GetRasterBand(i + 1).Checksum()
)
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_128.tif")
###############################################################################
# Check effective guessing of existing JPEG quality
@pytest.mark.require_creation_option("GTiff", "JPEG")
def test_tiff_write_129():
for jpegtablesmode in ["1", "3"]:
for photometric in ["RGB", "YCBCR"]:
cs_ref = 0
for i in range(2):
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_129.tif",
64,
32,
3,
options=[
"COMPRESS=JPEG",
"TILED=YES",
"BLOCKXSIZE=32",
"BLOCKYSIZE=32",
"JPEG_QUALITY=50",
"PHOTOMETRIC=" + photometric,
"JPEGTABLESMODE=" + jpegtablesmode,
],
)
src_ds = gdal.Open("data/rgbsmall.tif")
data = src_ds.ReadRaster(0, 0, 32, 32)
ds.WriteRaster(0, 0, 32, 32, data)
# In second pass, we re-open the dataset
if i == 1:
ds = None
ds = gdal.Open("/vsimem/tiff_write_129.tif", gdal.GA_Update)
ds.WriteRaster(32, 0, 32, 32, data)
ds = None
ds = gdal.Open("/vsimem/tiff_write_129.tif")
with gdaltest.SetCacheMax(0):
cs = ds.GetRasterBand(1).Checksum()
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_129.tif")
if i == 0:
cs_ref = cs
elif cs != cs_ref:
print(photometric)
print(i)
pytest.fail(jpegtablesmode)
###############################################################################
# Test cases where JPEG quality will fail
@pytest.mark.require_creation_option("GTiff", "JPEG")
def test_tiff_write_130():
shutil.copyfile(
"data/byte_jpg_unusual_jpegtable.tif", "tmp/byte_jpg_unusual_jpegtable.tif"
)
ds = gdal.Open("tmp/byte_jpg_unusual_jpegtable.tif", gdal.GA_Update)
assert ds.GetRasterBand(1).Checksum() == 4771
src_ds = gdal.Open("data/byte.tif", gdal.GA_Update)
ds.WriteRaster(0, 0, 20, 20, src_ds.ReadRaster())
src_ds = None
ds = None
ds = gdal.Open("tmp/byte_jpg_unusual_jpegtable.tif")
assert ds.GetRasterBand(1).Checksum() == 4743
ds = None
os.unlink("tmp/byte_jpg_unusual_jpegtable.tif")
shutil.copyfile(
"data/byte_jpg_tablesmodezero.tif", "tmp/byte_jpg_tablesmodezero.tif"
)
ds = gdal.Open("tmp/byte_jpg_tablesmodezero.tif", gdal.GA_Update)
assert ds.GetRasterBand(1).Checksum() == 4743
src_ds = gdal.Open("data/byte.tif", gdal.GA_Update)
ds.WriteRaster(0, 0, 20, 20, src_ds.ReadRaster())
src_ds = None
ds = None
ds = gdal.Open("tmp/byte_jpg_tablesmodezero.tif")
assert ds.GetRasterBand(1).Checksum() == 4743
ds = None
os.unlink("tmp/byte_jpg_tablesmodezero.tif")
###############################################################################
# Test LZMA compression
@pytest.mark.require_creation_option("GTiff", "LZMA")
def test_tiff_write_131(level=1):
filename = "/vsimem/tiff_write_131.tif"
src_ds = gdal.Open("data/byte.tif")
ds = gdaltest.tiff_drv.CreateCopy(
filename, src_ds, options=["COMPRESS=LZMA", "LZMA_PRESET=" + str(level)]
)
assert ds.GetRasterBand(1).Checksum() == 4672
ds = None
# LZMA requires an howful amount of memory even on small files
if gdal.GetLastErrorMsg().find("cannot allocate memory") >= 0:
gdal.Unlink(filename)
pytest.skip()
ds = gdal.Open(filename)
assert ds.GetRasterBand(1).Checksum() == 4672
ds = None
gdal.Unlink(filename)
@pytest.mark.require_creation_option("GTiff", "LZMA")
def test_tiff_write_131_level_9():
return test_tiff_write_131(level=9)
###############################################################################
# Test that PAM metadata is cleared when internal metadata is set (#5807)
def test_tiff_write_132():
for i in range(2):
ds = gdaltest.tiff_drv.Create("/vsimem/tiff_write_132.tif", 1, 1)
ds = None
# Open in read-only
ds = gdal.Open("/vsimem/tiff_write_132.tif")
ds.SetMetadataItem("FOO", "BAR")
ds.GetRasterBand(1).SetMetadataItem("FOO", "BAR")
ds = None
# Check that PAM file exists
assert gdal.VSIStatL("/vsimem/tiff_write_132.tif.aux.xml") is not None
# Open in read-write
ds = gdal.Open("/vsimem/tiff_write_132.tif", gdal.GA_Update)
if i == 0:
ds.SetMetadataItem("FOO", "BAZ")
ds.GetRasterBand(1).SetMetadataItem("FOO", "BAZ")
else:
ds.SetMetadata({"FOO": "BAZ"})
ds.GetRasterBand(1).SetMetadata({"FOO": "BAZ"})
ds = None
# Check that PAM file no longer exists
assert gdal.VSIStatL("/vsimem/tiff_write_132.tif.aux.xml") is None, i
ds = gdal.Open("/vsimem/tiff_write_132.tif")
assert (
ds.GetMetadataItem("FOO") == "BAZ"
and ds.GetRasterBand(1).GetMetadataItem("FOO") == "BAZ"
)
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_132.tif")
###############################################################################
# Test streaming capabilities
def test_tiff_write_133():
src_ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_133.tif", 1024, 1000, 3, options=["STREAMABLE_OUTPUT=YES"]
)
src_ds.SetGeoTransform([1, 2, 0, 3, 0, -2])
srs = osr.SpatialReference()
srs.SetFromUserInput("EPSG:32601")
src_ds.SetProjection(srs.ExportToWkt())
src_ds.SetMetadataItem("FOO", "BAR")
src_ds.GetRasterBand(1).SetNoDataValue(127)
src_ds.GetRasterBand(1).Fill(64)
src_ds.GetRasterBand(2).Fill(127)
src_ds.GetRasterBand(3).Fill(184)
src_ds.FlushCache()
with gdaltest.error_handler():
ret = src_ds.SetProjection(srs.ExportToWkt())
assert ret != 0
with gdaltest.error_handler():
ret = src_ds.SetGeoTransform([1, 2, 0, 3, 0, -4])
assert ret != 0
with gdaltest.error_handler():
ret = src_ds.SetMetadataItem("FOO", "BAZ")
assert ret != 0
with gdaltest.error_handler():
ret = src_ds.SetMetadata({})
assert ret != 0
with gdaltest.error_handler():
ret = src_ds.GetRasterBand(1).SetMetadataItem("FOO", "BAZ")
assert ret != 0
with gdaltest.error_handler():
ret = src_ds.GetRasterBand(1).SetMetadata({})
assert ret != 0
with gdaltest.error_handler():
ret = src_ds.GetRasterBand(1).SetNoDataValue(0)
assert ret != 0
# Pixel interleaved
out_ds = gdaltest.tiff_drv.CreateCopy(
"/vsimem/tiff_write_133_dst.tif",
src_ds,
options=["STREAMABLE_OUTPUT=YES", "BLOCKYSIZE=32"],
)
out_ds = None
with gdal.config_option("TIFF_READ_STREAMING", "YES"):
ds = gdal.Open("/vsimem/tiff_write_133_dst.tif")
assert ds.GetProjectionRef().find("32601") >= 0
assert ds.GetGeoTransform() == (1.0, 2.0, 0.0, 3.0, 0.0, -2.0)
assert ds.GetMetadataItem("FOO") == "BAR"
assert ds.GetMetadataItem("UNORDERED_BLOCKS", "TIFF") is None
with gdaltest.SetCacheMax(0):
for y in range(1000):
got_data = ds.ReadRaster(0, y, 1024, 1)
assert got_data is not None
ds.FlushCache()
for y in range(1000):
with gdaltest.error_handler():
got_data = ds.ReadRaster(0, y, 1024, 1)
assert got_data is None
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_133_dst.tif")
# Tiled
out_ds = gdaltest.tiff_drv.CreateCopy(
"/vsimem/tiff_write_133_dst.tif",
src_ds,
options=["STREAMABLE_OUTPUT=YES", "TILED=YES"],
)
out_ds = None
with gdal.config_option("TIFF_READ_STREAMING", "YES"):
ds = gdal.Open("/vsimem/tiff_write_133_dst.tif")
assert ds.GetProjectionRef().find("32601") >= 0
assert ds.GetGeoTransform() == (1.0, 2.0, 0.0, 3.0, 0.0, -2.0)
assert ds.GetMetadataItem("FOO") == "BAR"
assert ds.GetMetadataItem("UNORDERED_BLOCKS", "TIFF") is None
with gdaltest.SetCacheMax(0):
for yblock in range(int((1000 + 256 - 1) / 256)):
y = 256 * yblock
ysize = 256
if y + ysize > ds.RasterYSize:
ysize = ds.RasterYSize - y
for xblock in range(int((1024 + 256 - 1) / 256)):
x = 256 * xblock
xsize = 256
if x + xsize > ds.RasterXSize:
xsize = ds.RasterXSize - x
got_data = ds.ReadRaster(x, y, xsize, ysize)
assert got_data is not None
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_133_dst.tif")
# Band interleaved
out_ds = gdaltest.tiff_drv.CreateCopy(
"/vsimem/tiff_write_133_dst.tif",
src_ds,
options=["STREAMABLE_OUTPUT=YES", "INTERLEAVE=BAND"],
)
out_ds = None
with gdal.config_option("TIFF_READ_STREAMING", "YES"):
ds = gdal.Open("/vsimem/tiff_write_133_dst.tif")
assert ds.GetMetadataItem("UNORDERED_BLOCKS", "TIFF") is None
with gdaltest.SetCacheMax(0):
for band in range(3):
for y in range(1000):
got_data = ds.GetRasterBand(band + 1).ReadRaster(0, y, 1024, 1)
assert got_data is not None
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_133_dst.tif")
# BIGTIFF
md = gdaltest.tiff_drv.GetMetadata()
if md["DMD_CREATIONOPTIONLIST"].find("BigTIFF") >= 0:
out_ds = gdaltest.tiff_drv.CreateCopy(
"/vsimem/tiff_write_133_dst.tif",
src_ds,
options=["STREAMABLE_OUTPUT=YES", "BIGTIFF=YES"],
)
out_ds = None
with gdal.config_option("TIFF_READ_STREAMING", "YES"):
ds = gdal.Open("/vsimem/tiff_write_133_dst.tif")
assert ds.GetMetadataItem("UNORDERED_BLOCKS", "TIFF") is None
with gdaltest.SetCacheMax(0):
for y in range(1000):
got_data = ds.ReadRaster(0, y, 1024, 1)
assert got_data is not None
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_133_dst.tif")
# Compression not supported
with gdaltest.error_handler():
out_ds = gdaltest.tiff_drv.CreateCopy(
"/vsimem/tiff_write_133_dst.tif",
src_ds,
options=["STREAMABLE_OUTPUT=YES", "COMPRESS=DEFLATE"],
)
assert out_ds is None
# Test writing into a non authorized file
ds = gdaltest.tiff_drv.Create(
"/foo/bar", 1024, 1000, 3, options=["STREAMABLE_OUTPUT=YES", "BLOCKYSIZE=1"]
)
assert ds is None
with gdaltest.error_handler():
out_ds = gdaltest.tiff_drv.CreateCopy(
"/foo/bar", src_ds, options=["STREAMABLE_OUTPUT=YES"]
)
assert out_ds is None
src_ds = None
# Classical TIFF with IFD not at offset 8
with gdal.config_option("TIFF_READ_STREAMING", "YES"), gdaltest.error_handler():
ds = gdal.Open("data/byte.tif")
assert ds is None
# BigTIFF with IFD not at offset 16
if md["DMD_CREATIONOPTIONLIST"].find("BigTIFF") >= 0:
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_133.tif", 1024, 1000, 3, options=["BIGTIFF=YES"]
)
ds.GetRasterBand(1).Fill(0)
ds.FlushCache()
ds.SetGeoTransform([1, 2, 0, 3, 0, -2])
ds = None
with gdal.config_option("TIFF_READ_STREAMING", "YES"), gdaltest.error_handler():
ds = gdal.Open("/vsimem/tiff_write_133.tif")
assert ds is None
# Test reading strips in not increasing order
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_133.tif", 1024, 1000, 3, options=["BLOCKYSIZE=1"]
)
for y in range(1000):
ds.WriteRaster(0, 1000 - y - 1, 1024, 1, "a" * (3 * 1024))
ds.FlushCache()
ds = None
with gdal.config_option("TIFF_READ_STREAMING", "YES"), gdaltest.error_handler():
ds = gdal.Open("/vsimem/tiff_write_133.tif")
assert ds.GetMetadataItem("UNORDERED_BLOCKS", "TIFF") == "YES"
with gdaltest.SetCacheMax(0):
for y in range(1000):
got_data = ds.ReadRaster(0, 1000 - y - 1, 1024, 1)
assert got_data is not None
# Test writing strips in not increasing order in a streamable output
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_133.tif",
1024,
1000,
3,
options=["STREAMABLE_OUTPUT=YES", "BLOCKYSIZE=1"],
)
gdal.ErrorReset()
with gdaltest.error_handler():
ret = ds.WriteRaster(0, 999, 1024, 1, "a" * (3 * 1024))
ds.FlushCache()
assert gdal.GetLastErrorMsg() != ""
ds = None
# Test writing tiles in not increasing order in a streamable output
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_133.tif",
1024,
1000,
3,
options=["STREAMABLE_OUTPUT=YES", "TILED=YES"],
)
gdal.ErrorReset()
with gdaltest.error_handler():
ret = ds.WriteRaster(256, 256, 256, 256, "a" * (3 * 256 * 256))
ds.FlushCache()
assert gdal.GetLastErrorMsg() != ""
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_133.tif")
###############################################################################
# Test DISCARD_LSB
def test_tiff_write_134():
for interleave in ["BAND", "PIXEL"]:
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_134.tif",
1,
1,
3,
options=["DISCARD_LSB=0,1,3", "INTERLEAVE=" + interleave],
)
ds.GetRasterBand(1).Fill(127)
ds.GetRasterBand(2).Fill(127)
ds.GetRasterBand(3).Fill(127)
ds = None
ds = gdal.Open("/vsimem/tiff_write_134.tif")
val1 = struct.unpack("B", ds.GetRasterBand(1).ReadRaster())[0]
val2 = struct.unpack("B", ds.GetRasterBand(2).ReadRaster())[0]
val3 = struct.unpack("B", ds.GetRasterBand(3).ReadRaster())[0]
assert val1 == 127 and val2 == 126 and val3 == 128
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_134.tif")
src_ds = gdaltest.tiff_drv.Create("/vsimem/tiff_write_134_src.tif", 1, 1, 3)
src_ds.GetRasterBand(1).Fill(127)
src_ds.GetRasterBand(2).Fill(127)
src_ds.GetRasterBand(3).Fill(255)
ds = gdaltest.tiff_drv.CreateCopy(
"/vsimem/tiff_write_134.tif", src_ds, options=["DISCARD_LSB=0,1,3"]
)
ds = None
ds = gdal.Open("/vsimem/tiff_write_134.tif")
val1 = struct.unpack("B", ds.GetRasterBand(1).ReadRaster())[0]
val2 = struct.unpack("B", ds.GetRasterBand(2).ReadRaster())[0]
val3 = struct.unpack("B", ds.GetRasterBand(3).ReadRaster())[0]
assert val1 == 127 and val2 == 126 and val3 == 255
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_134_src.tif")
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_134.tif")
for (inval, expected_val) in [
(0, 0),
(1, 0),
(2, 0),
(3, 0),
(4, 8),
(254, 255),
(255, 255),
]:
for interleave in ["BAND", "PIXEL"]:
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_134.tif",
1,
1,
2,
gdal.GDT_Byte,
options=["DISCARD_LSB=3", "INTERLEAVE=" + interleave],
)
ds.GetRasterBand(1).Fill(inval)
ds = None
ds = gdal.Open("/vsimem/tiff_write_134.tif")
val1 = struct.unpack("B", ds.GetRasterBand(1).ReadRaster())[0]
assert val1 == expected_val, (inval, expected_val)
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_134.tif")
for (inval, expected_val) in [
(-32768, -32768),
(-32767, -32768),
(-32764, -32768),
(-8, -8),
(-1, -8), # this truncation is questionable
(0, 0),
(1, 0),
(3, 0),
(4, 8),
(8, 8),
(32766, 32760),
(32767, 32760),
]:
for interleave in ["BAND", "PIXEL"]:
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_134.tif",
1,
1,
2,
gdal.GDT_Int16,
options=["DISCARD_LSB=3", "INTERLEAVE=" + interleave],
)
ds.GetRasterBand(1).Fill(inval)
ds = None
ds = gdal.Open("/vsimem/tiff_write_134.tif")
val1 = struct.unpack("h", ds.GetRasterBand(1).ReadRaster())[0]
assert val1 == expected_val, (inval, expected_val)
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_134.tif")
for (inval, expected_val) in [
(0, 0),
(1, 0),
(3, 0),
(4, 8),
(8, 8),
(65534, 65528),
(65535, 65528),
]:
for interleave in ["BAND", "PIXEL"]:
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_134.tif",
1,
1,
2,
gdal.GDT_UInt16,
options=["DISCARD_LSB=3", "INTERLEAVE=" + interleave],
)
ds.GetRasterBand(1).Fill(inval)
ds = None
ds = gdal.Open("/vsimem/tiff_write_134.tif")
val1 = struct.unpack("H", ds.GetRasterBand(1).ReadRaster())[0]
assert val1 == expected_val, (inval, expected_val)
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_134.tif")
for interleave in ["BAND", "PIXEL"]:
for dt in [
gdal.GDT_Byte,
gdal.GDT_Int16,
gdal.GDT_UInt16,
gdal.GDT_Int32,
gdal.GDT_UInt32,
gdal.GDT_Float32,
gdal.GDT_Float64,
]:
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_134.tif",
1,
1,
3,
dt,
options=["DISCARD_LSB=3", "INTERLEAVE=" + interleave],
)
if dt == gdal.GDT_Int16:
ds.GetRasterBand(1).Fill(-127)
else:
ds.GetRasterBand(1).Fill(127)
ds.GetRasterBand(2).Fill(123)
ds.GetRasterBand(3).Fill(127)
ds = None
ds = gdal.Open("/vsimem/tiff_write_134.tif")
val1 = struct.unpack(
"h", ds.GetRasterBand(1).ReadRaster(0, 0, 1, 1, 1, 1, gdal.GDT_Int16)
)[0]
val2 = struct.unpack(
"h", ds.GetRasterBand(2).ReadRaster(0, 0, 1, 1, 1, 1, gdal.GDT_Int16)
)[0]
val3 = struct.unpack(
"h", ds.GetRasterBand(3).ReadRaster(0, 0, 1, 1, 1, 1, gdal.GDT_Int16)
)[0]
if dt in (gdal.GDT_Float32, gdal.GDT_Float64):
assert val1 == 127 and val2 == 123 and val3 == 127, (
interleave,
dt,
(val1, val2, val3),
)
elif dt == gdal.GDT_Int16:
assert val1 == -128 and val2 == 120 and val3 == 128, (
interleave,
dt,
(val1, val2, val3),
)
else:
assert val1 == 128 and val2 == 120 and val3 == 128, (
interleave,
dt,
(val1, val2, val3),
)
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_134.tif")
# Test with nodata
for interleave in ["BAND", "PIXEL"]:
for dt in [
gdal.GDT_Byte,
gdal.GDT_Int16,
gdal.GDT_UInt16,
gdal.GDT_Int32,
gdal.GDT_UInt32,
gdal.GDT_Float32,
gdal.GDT_Float64,
]:
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_134.tif",
1,
1,
2,
dt,
options=["DISCARD_LSB=3", "INTERLEAVE=" + interleave],
)
ds.GetRasterBand(1).SetNoDataValue(127)
ds.GetRasterBand(1).Fill(127)
ds = None
ds = gdal.Open("/vsimem/tiff_write_134.tif")
val1 = struct.unpack(
"B", ds.GetRasterBand(1).ReadRaster(0, 0, 1, 1, 1, 1, gdal.GDT_Byte)
)[0]
assert val1 == 127, (interleave, dt, val1)
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_134.tif")
# Test with nodata and discarding non-nodata value would result to nodata without correction
for interleave in ["BAND", "PIXEL"]:
for dt in [
gdal.GDT_Byte,
gdal.GDT_Int16,
gdal.GDT_UInt16,
gdal.GDT_Int32,
gdal.GDT_UInt32,
gdal.GDT_Float32,
gdal.GDT_Float64,
]:
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_134.tif",
1,
1,
2,
dt,
options=["DISCARD_LSB=3", "INTERLEAVE=" + interleave],
)
ds.GetRasterBand(1).SetNoDataValue(0)
ds.GetRasterBand(1).Fill(1)
ds = None
ds = gdal.Open("/vsimem/tiff_write_134.tif")
val1 = struct.unpack(
"B", ds.GetRasterBand(1).ReadRaster(0, 0, 1, 1, 1, 1, gdal.GDT_Byte)
)[0]
if dt in (gdal.GDT_Float32, gdal.GDT_Float64):
assert val1 == 1, (interleave, dt, val1)
else:
assert val1 == 8, (interleave, dt, val1)
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_134.tif")
# Test with nodata out of range for integer values
for interleave in ["BAND", "PIXEL"]:
for dt in [
gdal.GDT_Byte,
gdal.GDT_Int16,
gdal.GDT_UInt16,
gdal.GDT_Int32,
gdal.GDT_UInt32,
gdal.GDT_Float32,
gdal.GDT_Float64,
]:
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_134.tif",
1,
1,
2,
dt,
options=["DISCARD_LSB=3", "INTERLEAVE=" + interleave],
)
ds.GetRasterBand(1).SetNoDataValue(127.5)
ds.GetRasterBand(1).Fill(127)
ds = None
ds = gdal.Open("/vsimem/tiff_write_134.tif")
assert ds.GetRasterBand(1).GetNoDataValue() == 127.5
val1 = struct.unpack(
"B", ds.GetRasterBand(1).ReadRaster(0, 0, 1, 1, 1, 1, gdal.GDT_Byte)
)[0]
if dt in (gdal.GDT_Float32, gdal.GDT_Float64):
assert val1 == 127, (interleave, dt, val1)
else:
assert val1 == 128, (interleave, dt, val1)
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_134.tif")
# Test with some non-integer float value
for interleave in ["BAND", "PIXEL"]:
for dt in [gdal.GDT_Float32, gdal.GDT_Float64]:
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_134.tif",
1,
1,
2,
dt,
options=["DISCARD_LSB=3", "INTERLEAVE=" + interleave],
)
ds.GetRasterBand(1).Fill(-0.3)
ds = None
ds = gdal.Open("/vsimem/tiff_write_134.tif")
val1 = struct.unpack(
"d", ds.GetRasterBand(1).ReadRaster(0, 0, 1, 1, 1, 1, gdal.GDT_Float64)
)[0]
assert val1 != -0.3 and abs(val1 - -0.3) < 1e-5, dt
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_134.tif")
# Test with nan
for interleave in ["BAND", "PIXEL"]:
for dt in [gdal.GDT_Float32, gdal.GDT_Float64]:
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_134.tif",
1,
1,
2,
dt,
options=["DISCARD_LSB=3", "INTERLEAVE=" + interleave],
)
ds.GetRasterBand(1).Fill(float("nan"))
ds = None
ds = gdal.Open("/vsimem/tiff_write_134.tif")
val1 = struct.unpack(
"f", ds.GetRasterBand(1).ReadRaster(0, 0, 1, 1, 1, 1, gdal.GDT_Float32)
)[0]
assert math.isnan(val1)
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_134.tif")
# Error cases
gdal.ErrorReset()
with gdaltest.error_handler():
gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_134.tif",
1,
1,
options=["DISCARD_LSB=1", "PHOTOMETRIC=PALETTE"],
)
assert gdal.GetLastErrorMsg() != ""
gdal.ErrorReset()
with gdaltest.error_handler():
# Too many elements
gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_134.tif", 1, 1, options=["DISCARD_LSB=1,2"]
)
assert gdal.GetLastErrorMsg() != ""
gdal.ErrorReset()
with gdaltest.error_handler():
# Too many elements
gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_134.tif", 1, 1, options=["DISCARD_LSB=1", "NBITS=7"]
)
assert gdal.GetLastErrorMsg() != ""
###############################################################################
# Test clearing GCPs (#5945)
def test_tiff_write_135():
# Simple clear
src_ds = gdal.Open("data/gcps.vrt")
ds = gdaltest.tiff_drv.CreateCopy("/vsimem/tiff_write_135.tif", src_ds)
ds = None
ds = gdal.Open("/vsimem/tiff_write_135.tif", gdal.GA_Update)
ds.SetGCPs([], "")
ds = None
ds = gdal.Open("/vsimem/tiff_write_135.tif")
assert not ds.GetGCPs()
assert ds.GetGCPProjection() == ""
ds = None
# Double clear
src_ds = gdal.Open("data/gcps.vrt")
ds = gdaltest.tiff_drv.CreateCopy("/vsimem/tiff_write_135.tif", src_ds)
ds = None
ds = gdal.Open("/vsimem/tiff_write_135.tif", gdal.GA_Update)
ds.SetGCPs([], "")
ds.SetGCPs([], "")
ds = None
ds = gdal.Open("/vsimem/tiff_write_135.tif")
assert not ds.GetGCPs()
assert ds.GetGCPProjection() == ""
ds = None
# Clear + set geotransform and new projection
src_ds = gdal.Open("data/gcps.vrt")
ds = gdaltest.tiff_drv.CreateCopy("/vsimem/tiff_write_135.tif", src_ds)
ds = None
ds = gdal.Open("/vsimem/tiff_write_135.tif", gdal.GA_Update)
ds.SetGCPs([], "")
ds.SetGeoTransform([1, 2, 3, 4, 5, -6])
srs = osr.SpatialReference()
srs.SetFromUserInput("EPSG:32601")
ds.SetProjection(srs.ExportToWkt())
ds = None
ds = gdal.Open("/vsimem/tiff_write_135.tif")
assert not ds.GetGCPs()
assert ds.GetGeoTransform() == (1, 2, 3, 4, 5, -6)
assert ds.GetProjectionRef().find("32601") >= 0
ds = None
gdal.Unlink("/vsimem/tiff_write_135.tif")
###############################################################################
# Test writing a single-strip mono-bit dataset
def test_tiff_write_136():
src_ds = gdaltest.tiff_drv.Create("/vsimem/tiff_write_136_src.tif", 8, 2001)
src_ds.GetRasterBand(1).Fill(1)
expected_cs = src_ds.GetRasterBand(1).Checksum()
ds = gdaltest.tiff_drv.CreateCopy(
"/vsimem/tiff_write_136.tif",
src_ds,
options=["NBITS=1", "COMPRESS=DEFLATE", "BLOCKYSIZE=2001"],
)
src_ds = None
ds = None
ds = gdal.Open("/vsimem/tiff_write_136.tif")
cs = ds.GetRasterBand(1).Checksum()
assert cs == expected_cs
gdal.Unlink("/vsimem/tiff_write_136_src.tif")
gdal.Unlink("/vsimem/tiff_write_136.tif")
gdal.Unlink("/vsimem/tiff_write_136.tif.aux.xml")
###############################################################################
# Test multi-threaded writing
def test_tiff_write_137():
src_ds = gdaltest.tiff_drv.Create("/vsimem/tiff_write_137_src.tif", 4000, 4000)
src_ds.GetRasterBand(1).Fill(1)
data = src_ds.GetRasterBand(1).ReadRaster()
expected_cs = src_ds.GetRasterBand(1).Checksum()
# Test NUM_THREADS as creation option
ds = gdaltest.tiff_drv.CreateCopy(
"/vsimem/tiff_write_137.tif",
src_ds,
options=["BLOCKYSIZE=16", "COMPRESS=DEFLATE", "NUM_THREADS=ALL_CPUS"],
)
src_ds = None
ds = None
ds = gdal.Open("/vsimem/tiff_write_137.tif")
cs = ds.GetRasterBand(1).Checksum()
ds = None
assert cs == expected_cs
# Test NUM_THREADS as creation option with Create()
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_137.tif",
4000,
4000,
1,
options=["BLOCKYSIZE=16", "COMPRESS=DEFLATE", "NUM_THREADS=ALL_CPUS"],
)
ds.GetRasterBand(1).WriteRaster(0, 0, 4000, 4000, data)
ds = None
ds = gdal.Open("/vsimem/tiff_write_137.tif")
cs = ds.GetRasterBand(1).Checksum()
ds = None
assert cs == expected_cs
# Test NUM_THREADS as open option
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_137.tif",
4000,
4000,
options=["TILED=YES", "COMPRESS=DEFLATE", "PREDICTOR=2", "SPARSE_OK=YES"],
)
ds = None
ds = gdal.OpenEx(
"/vsimem/tiff_write_137.tif", gdal.OF_UPDATE, open_options=["NUM_THREADS=4"]
)
ds.GetRasterBand(1).Fill(1)
ds = None
ds = gdal.Open("/vsimem/tiff_write_137.tif")
cs = ds.GetRasterBand(1).Checksum()
ds = None
assert cs == expected_cs
# Ask data immediately while the block is compressed
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_137.tif",
4000,
4000,
options=["BLOCKYSIZE=3999", "COMPRESS=DEFLATE", "NUM_THREADS=4"],
)
ds.WriteRaster(0, 0, 1, 1, "A")
ds.FlushCache()
val = ds.ReadRaster(0, 0, 1, 1).decode("ascii")
assert val == "A"
ds = None
gdal.Unlink("/vsimem/tiff_write_137_src.tif")
gdal.Unlink("/vsimem/tiff_write_137.tif")
# Test NUM_THREADS with raster == tile
src_ds = gdal.Open("data/byte.tif")
ds = gdaltest.tiff_drv.CreateCopy(
"/vsimem/tiff_write_137.tif",
src_ds,
options=["BLOCKYSIZE=20", "COMPRESS=DEFLATE", "NUM_THREADS=ALL_CPUS"],
)
src_ds = None
ds = None
ds = gdal.Open("/vsimem/tiff_write_137.tif")
cs = ds.GetRasterBand(1).Checksum()
ds = None
assert cs == 4672, expected_cs
gdal.Unlink("/vsimem/tiff_write_137.tif")
###############################################################################
# Test that pixel-interleaved writing generates optimal size
def test_tiff_write_138():
# Test that consecutive IWriteBlock() calls for the same block but in
# different bands only generate a single tile write, and not 3 rewrites
ds = gdal.GetDriverByName("GTiff").Create(
"/vsimem/tiff_write_138.tif", 10, 1, 3, options=["COMPRESS=DEFLATE"]
)
ds.GetRasterBand(1).WriteRaster(0, 0, 10, 1, "A", buf_xsize=1, buf_ysize=1)
ds.GetRasterBand(1).FlushCache()
ds.GetRasterBand(2).WriteRaster(0, 0, 10, 1, "A", buf_xsize=1, buf_ysize=1)
ds.GetRasterBand(2).FlushCache()
ds.GetRasterBand(3).WriteRaster(0, 0, 10, 1, "A", buf_xsize=1, buf_ysize=1)
ds.GetRasterBand(3).FlushCache()
ds = None
size = gdal.VSIStatL("/vsimem/tiff_write_138.tif").size
assert size == 181
# Test fix for #5999
# Create a file with a huge block that will saturate the block cache.
with gdaltest.SetCacheMax(1000000):
tmp_ds = gdal.GetDriverByName("GTiff").Create(
"/vsimem/tiff_write_138_saturate.tif", gdal.GetCacheMax(), 1
)
tmp_ds = None
ds = gdal.GetDriverByName("GTiff").Create(
"/vsimem/tiff_write_138.tif", 10, 1, 3, options=["COMPRESS=DEFLATE"]
)
ds.GetRasterBand(1).WriteRaster(0, 0, 10, 1, "A", buf_xsize=1, buf_ysize=1)
ds.GetRasterBand(2).WriteRaster(0, 0, 10, 1, "A", buf_xsize=1, buf_ysize=1)
ds.GetRasterBand(3).WriteRaster(0, 0, 10, 1, "A", buf_xsize=1, buf_ysize=1)
# When internalizing the huge block, check that the 3 above dirty blocks
# get written as a single tile write.
tmp_ds = gdal.Open("/vsimem/tiff_write_138_saturate.tif")
tmp_ds.GetRasterBand(1).Checksum()
tmp_ds = None
ds = None
size = gdal.VSIStatL("/vsimem/tiff_write_138.tif").size
assert size == 181
gdal.Unlink("/vsimem/tiff_write_138.tif")
gdal.Unlink("/vsimem/tiff_write_138_saturate.tif")
###############################################################################
# Test that pixel-interleaved writing generates optimal size
def test_tiff_write_139():
drv = gdal.GetDriverByName("GTiff")
# Only post 4.0.5 has the fix for non-byte swabing case
has_inverted_swab_fix = drv.GetMetadataItem("LIBTIFF") == "INTERNAL"
# In the byte case, there are optimizations for the 3 and 4 case. 1 is the general case
for nbands in (1, 3, 4):
ds = drv.Create(
"/vsimem/tiff_write_139.tif",
4,
1,
nbands,
options=["PREDICTOR=2", "COMPRESS=DEFLATE"],
)
ref_content = struct.pack("B" * 4, 255, 0, 255, 0)
for i in range(nbands):
ds.GetRasterBand(i + 1).WriteRaster(0, 0, 4, 1, ref_content)
ds = None
ds = gdal.Open("/vsimem/tiff_write_139.tif")
for i in range(nbands):
content = ds.GetRasterBand(i + 1).ReadRaster()
assert ref_content == content
ds = None
gdal.Unlink("/vsimem/tiff_write_139.tif")
# Int16
for endianness in ["NATIVE", "INVERTED"]:
if endianness == "INVERTED" and not has_inverted_swab_fix:
continue
ds = drv.Create(
"/vsimem/tiff_write_139.tif",
6,
1,
1,
gdal.GDT_Int16,
options=["PREDICTOR=2", "COMPRESS=DEFLATE", "ENDIANNESS=%s" % endianness],
)
ref_content = struct.pack("h" * 6, -32768, 32767, -32768, 32767, -32768, 32767)
ds.GetRasterBand(1).WriteRaster(0, 0, 6, 1, ref_content)
ds = None
ds = gdal.Open("/vsimem/tiff_write_139.tif")
content = ds.GetRasterBand(1).ReadRaster()
if ref_content != content:
print(endianness)
pytest.fail(struct.unpack("h" * 6, content))
ds = None
gdal.Unlink("/vsimem/tiff_write_139.tif")
# UInt16 (same code path)
for endianness in ["NATIVE", "INVERTED"]:
if endianness == "INVERTED" and not has_inverted_swab_fix:
continue
ds = drv.Create(
"/vsimem/tiff_write_139.tif",
6,
1,
1,
gdal.GDT_UInt16,
options=["PREDICTOR=2", "COMPRESS=DEFLATE", "ENDIANNESS=%s" % endianness],
)
ref_content = struct.pack("H" * 6, 0, 65535, 0, 65535, 0, 65535)
ds.GetRasterBand(1).WriteRaster(0, 0, 6, 1, ref_content)
ds = None
ds = gdal.Open("/vsimem/tiff_write_139.tif")
content = ds.GetRasterBand(1).ReadRaster()
if ref_content != content:
print(endianness)
pytest.fail(struct.unpack("H" * 6, content))
ds = None
gdal.Unlink("/vsimem/tiff_write_139.tif")
# Int32
for endianness in ["NATIVE", "INVERTED"]:
if endianness == "INVERTED" and not has_inverted_swab_fix:
continue
ds = drv.Create(
"/vsimem/tiff_write_139.tif",
6,
1,
1,
gdal.GDT_UInt32,
options=["PREDICTOR=2", "COMPRESS=DEFLATE", "ENDIANNESS=%s" % endianness],
)
ref_content = struct.pack("I" * 6, 0, 2000000000, 0, 2000000000, 0, 2000000000)
ds.GetRasterBand(1).WriteRaster(0, 0, 6, 1, ref_content)
ds = None
ds = gdal.Open("/vsimem/tiff_write_139.tif")
content = ds.GetRasterBand(1).ReadRaster()
if ref_content != content:
print(endianness)
pytest.fail(struct.unpack("I" * 6, content))
ds = None
gdal.Unlink("/vsimem/tiff_write_139.tif")
# Test floating-point predictor
# Seems to be broken with ENDIANNESS=INVERTED
ds = drv.Create(
"/vsimem/tiff_write_139.tif",
4,
1,
1,
gdal.GDT_Float64,
options=["PREDICTOR=3", "COMPRESS=DEFLATE"],
)
ref_content = struct.pack("d" * 4, 1, -1e100, 1e10, -1e5)
ds.GetRasterBand(1).WriteRaster(0, 0, 4, 1, ref_content)
ds = None
ds = gdal.Open("/vsimem/tiff_write_139.tif")
content = ds.GetRasterBand(1).ReadRaster()
assert ref_content == content, struct.unpack("d" * 4, content)
ds = None
gdal.Unlink("/vsimem/tiff_write_139.tif")
###############################################################################
# Test setting a band to alpha
def test_tiff_write_140():
# Nominal case: set alpha to last band
ds = gdaltest.tiff_drv.Create("/vsimem/tiff_write_140.tif", 1, 1, 5)
ds.GetRasterBand(5).SetColorInterpretation(gdal.GCI_AlphaBand)
ds = None
statBuf = gdal.VSIStatL(
"/vsimem/tiff_write_140.tif.aux.xml",
gdal.VSI_STAT_EXISTS_FLAG | gdal.VSI_STAT_NATURE_FLAG | gdal.VSI_STAT_SIZE_FLAG,
)
assert statBuf is None, "did not expect PAM file"
ds = gdal.Open("/vsimem/tiff_write_140.tif")
assert ds.GetRasterBand(5).GetColorInterpretation() == gdal.GCI_AlphaBand
ds = None
# Strange case: set alpha to a band, but it is already set on another one
ds = gdaltest.tiff_drv.Create("/vsimem/tiff_write_140.tif", 1, 1, 5)
ds.GetRasterBand(2).SetColorInterpretation(gdal.GCI_AlphaBand)
# Should emit a warning
gdal.ErrorReset()
with gdaltest.error_handler():
ret = ds.GetRasterBand(5).SetColorInterpretation(gdal.GCI_AlphaBand)
assert gdal.GetLastErrorMsg() != ""
assert ret == 0
ds = None
statBuf = gdal.VSIStatL(
"/vsimem/tiff_write_140.tif.aux.xml",
gdal.VSI_STAT_EXISTS_FLAG | gdal.VSI_STAT_NATURE_FLAG | gdal.VSI_STAT_SIZE_FLAG,
)
assert statBuf is None, "did not expect PAM file"
ds = gdal.Open("/vsimem/tiff_write_140.tif")
assert ds.GetRasterBand(2).GetColorInterpretation() == gdal.GCI_AlphaBand
assert ds.GetRasterBand(5).GetColorInterpretation() == gdal.GCI_AlphaBand
ds = None
# Strange case: set alpha to a band, but it is already set on another one (because of ALPHA=YES)
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_140.tif", 1, 1, 5, options=["ALPHA=YES"]
)
# Should emit a warning mentioning ALPHA creation option.
gdal.ErrorReset()
with gdaltest.error_handler():
ret = ds.GetRasterBand(5).SetColorInterpretation(gdal.GCI_AlphaBand)
assert gdal.GetLastErrorMsg().find("ALPHA") >= 0
assert ret == 0
ds = None
statBuf = gdal.VSIStatL(
"/vsimem/tiff_write_140.tif.aux.xml",
gdal.VSI_STAT_EXISTS_FLAG | gdal.VSI_STAT_NATURE_FLAG | gdal.VSI_STAT_SIZE_FLAG,
)
assert statBuf is None, "did not expect PAM file"
ds = gdal.Open("/vsimem/tiff_write_140.tif")
assert ds.GetRasterBand(2).GetColorInterpretation() == gdal.GCI_AlphaBand
assert ds.GetRasterBand(5).GetColorInterpretation() == gdal.GCI_AlphaBand
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_140.tif")
###############################################################################
# Test GEOTIFF_KEYS_FLAVOR=ESRI_PE with EPSG:3857
def test_tiff_write_141():
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_141.tif", 1, 1, options=["GEOTIFF_KEYS_FLAVOR=ESRI_PE"]
)
srs = osr.SpatialReference()
srs.ImportFromEPSG(3857)
ds.SetProjection(srs.ExportToWkt())
ds = None
ds = gdal.Open("/vsimem/tiff_write_141.tif")
wkt = ds.GetProjectionRef()
ds = None
assert wkt.startswith('PROJCS["WGS 84 / Pseudo-Mercator"')
assert 'EXTENSION["PROJ4"' in wkt
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_141.tif")
###############################################################################
# Test PixelIsPoint without SRS (#6225)
def test_tiff_write_142():
ds = gdaltest.tiff_drv.Create("/vsimem/tiff_write_142.tif", 1, 1)
ds.SetMetadataItem("AREA_OR_POINT", "Point")
ds.SetGeoTransform([10, 1, 0, 100, 0, -1])
ds = None
src_ds = gdal.Open("/vsimem/tiff_write_142.tif")
gdaltest.tiff_drv.CreateCopy("/vsimem/tiff_write_142_2.tif", src_ds)
src_ds = None
ds = gdal.Open("/vsimem/tiff_write_142_2.tif")
gt = ds.GetGeoTransform()
md = ds.GetMetadataItem("AREA_OR_POINT")
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_142.tif")
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_142_2.tif")
gt_expected = (10, 1, 0, 100, 0, -1)
assert gt == gt_expected, "did not get expected geotransform"
assert md == "Point", "did not get expected AREA_OR_POINT value"
###############################################################################
# Check that we detect that free space isn't sufficient
def test_tiff_write_143():
with gdaltest.error_handler():
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_143.tif", 1000000000, 1000000000
)
assert ds is None
###############################################################################
# Test creating a real BigTIFF file > 4 GB with multiple directories (on filesystems supporting sparse files)
def test_tiff_write_144():
# Determine if the filesystem supports sparse files (we don't want to create a real 10 GB
# file !
if not gdaltest.filesystem_supports_sparse_files("tmp"):
pytest.skip()
ds = gdal.GetDriverByName("GTiff").Create(
"tmp/tiff_write_144.tif", 20, 20, 1, options=["BIGTIFF=YES"]
)
ds.GetRasterBand(1).Fill(255)
ds = None
# Extend the file to 4 GB
f = open("tmp/tiff_write_144.tif", "rb+")
f.seek(4294967296, 0)
f.write(" ".encode("ascii"))
f.close()
ds = gdal.Open("tmp/tiff_write_144.tif", gdal.GA_Update)
ds.BuildOverviews("NEAR", [2])
ds = None
ds = gdal.Open("tmp/tiff_write_144.tif")
got_cs = ds.GetRasterBand(1).Checksum()
got_cs_ovr = ds.GetRasterBand(1).GetOverview(0).Checksum()
ds = None
gdal.Unlink("tmp/tiff_write_144.tif")
assert got_cs == 4873 and got_cs_ovr == 1218
###############################################################################
# Test various warnings / errors of Create()
def test_tiff_write_145():
options_list = [
{"bands": 65536, "expected_failure": True},
{"creation_options": ["INTERLEAVE=foo"], "expected_failure": True},
{"creation_options": ["COMPRESS=foo"], "expected_failure": False},
{
"creation_options": ["STREAMABLE_OUTPUT=YES", "SPARSE_OK=YES"],
"expected_failure": True,
},
{
"creation_options": ["STREAMABLE_OUTPUT=YES", "COPY_SRC_OVERVIEWS=YES"],
"expected_failure": True,
},
{
"use_tmp": True,
"xsize": 100000,
"ysize": 100000,
"creation_options": ["BIGTIFF=NO"],
"expected_failure": True,
},
{"creation_options": ["ENDIANNESS=foo"], "expected_failure": False},
{"creation_options": ["NBITS=9"], "expected_failure": False},
{
"datatype": gdal.GDT_Float32,
"creation_options": ["NBITS=8"],
"expected_failure": False,
},
{
"datatype": gdal.GDT_UInt16,
"creation_options": ["NBITS=8"],
"expected_failure": False,
},
{
"datatype": gdal.GDT_UInt16,
"creation_options": ["NBITS=17"],
"expected_failure": False,
},
{
"datatype": gdal.GDT_UInt32,
"creation_options": ["NBITS=16"],
"expected_failure": False,
},
{
"datatype": gdal.GDT_UInt32,
"creation_options": ["NBITS=33"],
"expected_failure": False,
},
{
"bands": 3,
"creation_options": ["PHOTOMETRIC=YCBCR"],
"expected_failure": True,
},
{
"bands": 3,
"creation_options": [
"PHOTOMETRIC=YCBCR",
"COMPRESS=JPEG",
"INTERLEAVE=BAND",
],
"expected_failure": True,
},
{
"bands": 1,
"creation_options": ["PHOTOMETRIC=YCBCR", "COMPRESS=JPEG"],
"expected_failure": True,
},
{"creation_options": ["PHOTOMETRIC=foo"], "expected_failure": False},
{"creation_options": ["PHOTOMETRIC=RGB"], "expected_failure": False},
{
"creation_options": ["TILED=YES", "BLOCKSIZE=1", "BLOCKYSIZE=1"],
"expected_failure": True,
},
]
for options in options_list:
xsize = options.get("xsize", 1)
ysize = options.get("ysize", 1)
bands = options.get("bands", 1)
datatype = options.get("datatype", gdal.GDT_Byte)
use_tmp = options.get("use_tmp", False)
if use_tmp:
filename = "tmp/tiff_write_145.tif"
else:
filename = "/vsimem/tiff_write_145.tif"
creation_options = options.get("creation_options", [])
gdal.Unlink(filename)
gdal.ErrorReset()
with gdaltest.error_handler():
ds = gdaltest.tiff_drv.Create(
filename, xsize, ysize, bands, datatype, options=creation_options
)
if ds is not None and options.get("expected_failure", False):
print(options)
pytest.fail("expected failure, but did not get it")
elif ds is None and not options.get("expected_failure", False):
print(options)
pytest.fail("got failure, but did not expect it")
ds = None
# print(gdal.GetLastErrorMsg())
if gdal.GetLastErrorMsg() == "":
print(options)
pytest.fail("did not get any warning/error")
gdal.Unlink(filename)
###############################################################################
# Test implicit JPEG-in-TIFF overviews with RGBA (not completely sure this
# is a legal formulation since 4 bands should probably be seen as CMYK)
@pytest.mark.require_creation_option("GTiff", "JPEG")
@pytest.mark.require_driver("JPEG")
def test_tiff_write_146():
tmp_ds = gdal.Translate("", "data/stefan_full_rgba.tif", format="MEM")
original_stats = [
tmp_ds.GetRasterBand(i + 1).ComputeStatistics(True) for i in range(4)
]
gdal.Translate(
"/vsimem/tiff_write_146.tif",
"data/stefan_full_rgba.tif",
options="-outsize 1000% 1000% -co COMPRESS=JPEG",
)
out_ds = gdal.Open("/vsimem/tiff_write_146.tif")
got_stats = [
out_ds.GetRasterBand(i + 1).GetOverview(2).ComputeStatistics(True)
for i in range(4)
]
out_ds = None
gdal.GetDriverByName("GTiff").Delete("/vsimem/tiff_write_146.tif")
for i in range(4):
for j in range(4):
assert (
i == 2
or j < 2
or original_stats[i][j] == pytest.approx(got_stats[i][j], abs=5)
), "did not get expected statistics"
###############################################################################
# Test that we don't use implicit JPEG-in-TIFF overviews with CMYK when converting
# to RGBA
@pytest.mark.require_creation_option("GTiff", "JPEG")
@pytest.mark.require_driver("JPEG")
def test_tiff_write_147():
with gdal.config_options({"GDAL_JPEG_TO_RGB": "NO", "GDAL_PAM_ENABLED": "NO"}):
gdal.Translate(
"/vsimem/tiff_write_147.tif",
"../gdrivers/data/jpeg/rgb_ntf_cmyk.jpg",
options="-outsize 1000% 1000% -co COMPRESS=JPEG -co PHOTOMETRIC=CMYK",
)
out_ds = gdal.Open("/vsimem/tiff_write_147.tif")
assert out_ds.GetRasterBand(1).GetOverview(0) is None, "did not expected overview"
out_ds = None
gdal.GetDriverByName("GTiff").Delete("/vsimem/tiff_write_147.tif")
###############################################################################
# Test that we can use implicit JPEG-in-TIFF overviews with CMYK in raw mode
@pytest.mark.require_creation_option("GTiff", "JPEG")
@pytest.mark.require_driver("JPEG")
def test_tiff_write_148():
with gdal.config_option("GDAL_JPEG_TO_RGB", "NO"):
tmp_ds = gdal.Translate(
"", "../gdrivers/data/jpeg/rgb_ntf_cmyk.jpg", format="MEM"
)
original_stats = [
tmp_ds.GetRasterBand(i + 1).ComputeStatistics(True) for i in range(4)
]
with gdal.config_options({"GDAL_JPEG_TO_RGB": "NO", "GDAL_PAM_ENABLED": "NO"}):
gdal.Translate(
"/vsimem/tiff_write_148.tif",
"../gdrivers/data/jpeg/rgb_ntf_cmyk.jpg",
options="-outsize 1000% 1000% -co COMPRESS=JPEG -co PHOTOMETRIC=CMYK",
)
out_ds = gdal.Open("GTIFF_RAW:/vsimem/tiff_write_148.tif")
got_stats = [
out_ds.GetRasterBand(i + 1).GetOverview(0).ComputeStatistics(True)
for i in range(4)
]
out_ds = None
gdal.GetDriverByName("GTiff").Delete("/vsimem/tiff_write_148.tif")
for i in range(4):
for j in range(4):
assert j < 2 or original_stats[i][j] == pytest.approx(
got_stats[i][j], abs=5
), "did not get expected statistics"
###############################################################################
# Test filling missing blocks with nodata
def test_tiff_write_149():
# Power-of-two bit depth
ds = gdaltest.tiff_drv.Create("/vsimem/tiff_write_149.tif", 1, 1)
ds.GetRasterBand(1).SetNoDataValue(127)
ds = None
ds = gdal.Open("/vsimem/tiff_write_149.tif")
cs = ds.GetRasterBand(1).Checksum()
ds = None
assert cs == 1
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_149.tif")
# Test implicit blocks
expected_cs = 13626
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_149.tif",
40,
30,
2,
gdal.GDT_UInt16,
options=[
"NBITS=12",
"TILED=YES",
"BLOCKXSIZE=16",
"BLOCKYSIZE=16",
"INTERLEAVE=BAND",
"SPARSE_OK=YES",
],
)
ds.GetRasterBand(1).SetNoDataValue(127)
ds.GetRasterBand(2).SetNoDataValue(127)
ds = None
ds = gdal.Open("/vsimem/tiff_write_149.tif")
cs = ds.GetRasterBand(1).Checksum()
ds = None
assert cs == expected_cs
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_149.tif")
# NBITS=12, SEPARATE. Checksum must be the same as in the implicit blocks case
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_149.tif",
40,
30,
2,
gdal.GDT_UInt16,
options=[
"NBITS=12",
"TILED=YES",
"BLOCKXSIZE=16",
"BLOCKYSIZE=16",
"INTERLEAVE=BAND",
],
)
ds.GetRasterBand(1).SetNoDataValue(127)
ds.GetRasterBand(2).SetNoDataValue(127)
ds = None
ds = gdal.Open("/vsimem/tiff_write_149.tif")
cs = ds.GetRasterBand(1).Checksum()
ds = None
assert cs == expected_cs
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_149.tif")
# NBITS=12, CONTIG. Checksum must be the same as in the implicit blocks case
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_149.tif",
40,
30,
2,
gdal.GDT_UInt16,
options=[
"NBITS=12",
"TILED=YES",
"BLOCKXSIZE=16",
"BLOCKYSIZE=16",
"INTERLEAVE=PIXEL",
],
)
ds.GetRasterBand(1).SetNoDataValue(127)
ds.GetRasterBand(2).SetNoDataValue(127)
ds = None
ds = gdal.Open("/vsimem/tiff_write_149.tif")
cs = ds.GetRasterBand(1).Checksum()
ds = None
assert cs == expected_cs
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_149.tif")
###############################################################################
# Test failure when loading block from disk in IWriteBlock()
def test_tiff_write_150():
shutil.copy("data/tiled_bad_offset.tif", "tmp/tiled_bad_offset.tif")
ds = gdal.Open("tmp/tiled_bad_offset.tif", gdal.GA_Update)
ds.GetRasterBand(1).Fill(0)
gdal.ErrorReset()
with gdaltest.error_handler():
ds.FlushCache()
assert gdal.GetLastErrorMsg() != ""
ds = None
gdaltest.tiff_drv.Delete("tmp/tiled_bad_offset.tif")
###############################################################################
# Test IWriteBlock() with more than 10 bands
def test_tiff_write_151():
ds = gdaltest.tiff_drv.Create("/vsimem/tiff_write_151.tif", 1, 1, 11)
ds = None
ds = gdal.Open("/vsimem/tiff_write_151.tif", gdal.GA_Update)
ds.GetRasterBand(1).Fill(1)
ds = None
ds = gdal.Open("/vsimem/tiff_write_151.tif", gdal.GA_Update)
ds.GetRasterBand(1).Checksum()
ds.GetRasterBand(2).Fill(1)
ds.GetRasterBand(3).Fill(1)
ds = None
ds = gdal.Open("/vsimem/tiff_write_151.tif")
assert ds.GetRasterBand(1).Checksum() == 1
assert ds.GetRasterBand(2).Checksum() == 1
assert ds.GetRasterBand(3).Checksum() == 1
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_151.tif")
###############################################################################
# Test flushing of blocks in a contig multi band file with Create()
def test_tiff_write_152():
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_152.tif", 1, 1, 2, options=["NBITS=2"]
)
ds.GetRasterBand(2).SetNoDataValue(3)
ds.GetRasterBand(2).Fill(1)
ds = None
ds = gdal.Open("/vsimem/tiff_write_152.tif")
assert ds.GetRasterBand(1).Checksum() == 0
assert ds.GetRasterBand(2).Checksum() == 1
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_152.tif")
###############################################################################
# Test that empty blocks are created in a filesystem sparse way
def test_tiff_write_153():
target_dir = "tmp"
if gdal.VSISupportsSparseFiles(target_dir) == 0:
pytest.skip()
gdaltest.tiff_drv.Create(target_dir + "/tiff_write_153.tif", 500, 500)
f = gdal.VSIFOpenL(target_dir + "/tiff_write_153.tif", "rb")
ret = gdal.VSIFGetRangeStatusL(f, 500 * 500, 1)
gdal.VSIFCloseL(f)
gdaltest.tiff_drv.Delete(target_dir + "/tiff_write_153.tif")
assert ret != gdal.VSI_RANGE_STATUS_DATA
###############################################################################
# Test empty block writing skipping and SPARSE_OK in CreateCopy() and Open()
def test_tiff_write_154():
src_ds = gdal.GetDriverByName("MEM").Create("", 500, 500)
ds = gdaltest.tiff_drv.CreateCopy(
"/vsimem/tiff_write_154.tif", src_ds, options=["BLOCKYSIZE=256"]
)
ds.FlushCache()
# At that point empty blocks have not yet been flushed
assert gdal.VSIStatL("/vsimem/tiff_write_154.tif").size == 162
ds = None
# Now they are and that's done in a filesystem sparse way. TODO: check this
assert gdal.VSIStatL("/vsimem/tiff_write_154.tif").size == 256162
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_154.tif")
ds = gdaltest.tiff_drv.CreateCopy(
"/vsimem/tiff_write_154.tif",
src_ds,
options=["BLOCKYSIZE=256", "COMPRESS=DEFLATE"],
)
ds.FlushCache()
# With compression, empty blocks are written right away
# 461 is with libdeflate, 462 with zlib
assert gdal.VSIStatL("/vsimem/tiff_write_154.tif").size in (461, 462)
ds = None
assert gdal.VSIStatL("/vsimem/tiff_write_154.tif").size in (461, 462)
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_154.tif")
# SPARSE_OK in CreateCopy(): blocks are not written
ds = gdaltest.tiff_drv.CreateCopy(
"/vsimem/tiff_write_154.tif",
src_ds,
options=["SPARSE_OK=YES", "BLOCKYSIZE=256"],
)
ds = None
assert gdal.VSIStatL("/vsimem/tiff_write_154.tif").size == 162
# SPARSE_OK in Open()/update: blocks are not written
ds = gdal.OpenEx(
"/vsimem/tiff_write_154.tif", gdal.OF_UPDATE, open_options=["SPARSE_OK=YES"]
)
ds.GetRasterBand(1).Fill(0)
ds = None
assert gdal.VSIStatL("/vsimem/tiff_write_154.tif").size == 162
ds = None
# Default behaviour in Open()/update: blocks are written
ds = gdal.OpenEx("/vsimem/tiff_write_154.tif", gdal.OF_UPDATE)
ds.GetRasterBand(1).Fill(0)
ds = None
assert gdal.VSIStatL("/vsimem/tiff_write_154.tif").size == 250162
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_154.tif")
# SPARSE_OK in CreateCopy() in compressed case (strips): blocks are not written
ds = gdaltest.tiff_drv.CreateCopy(
"/vsimem/tiff_write_154.tif",
src_ds,
options=["SPARSE_OK=YES", "BLOCKYSIZE=256", "COMPRESS=DEFLATE"],
)
ds = None
assert gdal.VSIStatL("/vsimem/tiff_write_154.tif").size == 174
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_154.tif")
# SPARSE_OK in CreateCopy() in compressed case (tiling): blocks are not written
ds = gdaltest.tiff_drv.CreateCopy(
"/vsimem/tiff_write_154.tif", src_ds, options=["SPARSE_OK=YES", "TILED=YES"]
)
ds = None
assert gdal.VSIStatL("/vsimem/tiff_write_154.tif").size == 190
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_154.tif")
# Test detection of 0 blocks for all data types
for dt in [
"signedbyte",
gdal.GDT_Int16,
gdal.GDT_UInt16,
gdal.GDT_Int32,
gdal.GDT_UInt32,
gdal.GDT_Float32,
gdal.GDT_Float64,
]:
# SPARSE_OK in CreateCopy(): blocks are not written
if dt == "signedbyte":
src_ds = gdal.GetDriverByName("MEM").Create("", 500, 500, 1, gdal.GDT_Byte)
options = ["SPARSE_OK=YES", "BLOCKYSIZE=256", "PIXELTYPE=SIGNEDBYTE"]
else:
src_ds = gdal.GetDriverByName("MEM").Create("", 500, 500, 1, dt)
options = ["SPARSE_OK=YES", "BLOCKYSIZE=256"]
gdaltest.tiff_drv.CreateCopy(
"/vsimem/tiff_write_154.tif", src_ds, options=options
)
assert gdal.VSIStatL("/vsimem/tiff_write_154.tif").size == 162, dt
# Test detection of nodata blocks with nodata != 0 for all data types
for dt in [
"signedbyte",
gdal.GDT_Int16,
gdal.GDT_UInt16,
gdal.GDT_Int32,
gdal.GDT_UInt32,
gdal.GDT_Float32,
gdal.GDT_Float64,
]:
# SPARSE_OK in CreateCopy(): blocks are not written
if dt == "signedbyte":
src_ds = gdal.GetDriverByName("MEM").Create("", 500, 500, 1, gdal.GDT_Byte)
options = ["SPARSE_OK=YES", "BLOCKYSIZE=256", "PIXELTYPE=SIGNEDBYTE"]
else:
src_ds = gdal.GetDriverByName("MEM").Create("", 500, 500, 1, dt)
options = ["SPARSE_OK=YES", "BLOCKYSIZE=256"]
src_ds.GetRasterBand(1).Fill(1)
src_ds.GetRasterBand(1).SetNoDataValue(1)
ds = gdaltest.tiff_drv.CreateCopy(
"/vsimem/tiff_write_154.tif", src_ds, options=options
)
ds = None
assert gdal.VSIStatL("/vsimem/tiff_write_154.tif").size == 174, dt
# Test optimized detection when nodata==0, and with the last pixel != 0
src_ds = gdal.GetDriverByName("MEM").Create("", 100, 1, 1)
src_ds.GetRasterBand(1).Fill(0)
src_ds.GetRasterBand(1).WriteRaster(99, 0, 1, 1, struct.pack("B" * 1, 1))
gdaltest.tiff_drv.CreateCopy(
"/vsimem/tiff_write_154.tif", src_ds, options=["SPARSE_OK=YES"]
)
assert gdal.VSIStatL("/vsimem/tiff_write_154.tif").size == 246
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_154.tif")
# Test that setting nodata doesn't prevent blocks to be written (#6706)
ds = gdal.GetDriverByName("GTiff").Create("/vsimem/tiff_write_154.tif", 1, 100, 1)
ds.GetRasterBand(1).SetNoDataValue(1)
ds = None
ds = gdal.Open("/vsimem/tiff_write_154.tif")
offset = ds.GetRasterBand(1).GetMetadataItem("BLOCK_OFFSET_0_0", "TIFF")
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_154.tif")
assert not (offset is None or int(offset) == 0)
###############################################################################
# Test reading and writing band description
def test_tiff_write_155():
tiff_drv = gdal.GetDriverByName("GTiff")
ds = tiff_drv.Create("/vsimem/tiff_write_155.tif", 1, 1)
ds.GetRasterBand(1).SetDescription("foo")
ds = None
assert gdal.VSIStatL("/vsimem/tiff_write_155.tif.aux.xml") is None
ds = gdal.Open("/vsimem/tiff_write_155.tif")
assert ds.GetRasterBand(1).GetDescription() == "foo"
ds = None
# Override in PAM
ds = gdal.Open("/vsimem/tiff_write_155.tif")
ds.GetRasterBand(1).SetDescription("bar")
ds = None
assert gdal.VSIStatL("/vsimem/tiff_write_155.tif.aux.xml") is not None
ds = gdal.Open("/vsimem/tiff_write_155.tif")
assert ds.GetRasterBand(1).GetDescription() == "bar"
ds = None
tiff_drv.Delete("/vsimem/tiff_write_155.tif")
assert gdal.VSIStatL("/vsimem/tiff_write_155.tif.aux.xml") is None
ds = tiff_drv.Create(
"/vsimem/tiff_write_155.tif", 1, 1, options=["PROFILE=GeoTIFF"]
)
ds.GetRasterBand(1).SetDescription("foo")
ds = None
assert gdal.VSIStatL("/vsimem/tiff_write_155.tif.aux.xml") is not None
ds = gdal.Open("/vsimem/tiff_write_155.tif")
assert ds.GetRasterBand(1).GetDescription() == "foo"
ds = None
tiff_drv.Delete("/vsimem/tiff_write_155.tif")
###############################################################################
# Test GetDataCoverageStatus()
def test_tiff_write_156():
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_156.tif",
64,
64,
options=["SPARSE_OK=YES", "TILED=YES", "BLOCKXSIZE=32", "BLOCKYSIZE=32"],
)
ds.GetRasterBand(1).WriteRaster(0, 0, 1, 1, "X")
(flags, pct) = ds.GetRasterBand(1).GetDataCoverageStatus(0, 0, 32, 32)
assert flags == gdal.GDAL_DATA_COVERAGE_STATUS_DATA and pct == 100.0
(flags, pct) = ds.GetRasterBand(1).GetDataCoverageStatus(32, 0, 32, 32)
assert flags == gdal.GDAL_DATA_COVERAGE_STATUS_EMPTY and pct == 0.0
(flags, pct) = ds.GetRasterBand(1).GetDataCoverageStatus(16, 16, 32, 32)
assert (
flags
== gdal.GDAL_DATA_COVERAGE_STATUS_DATA | gdal.GDAL_DATA_COVERAGE_STATUS_EMPTY
and pct == 25.0
)
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_156.tif")
# Test fix for #6703
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_156.tif", 1, 512, options=["SPARSE_OK=YES", "BLOCKYSIZE=1"]
)
ds.GetRasterBand(1).WriteRaster(0, 100, 1, 1, "X")
ds = None
ds = gdal.Open("/vsimem/tiff_write_156.tif")
flags, _ = ds.GetRasterBand(1).GetDataCoverageStatus(0, 100, 1, 1)
assert flags == gdal.GDAL_DATA_COVERAGE_STATUS_DATA
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_156.tif")
###############################################################################
# Test Float16
def test_tiff_write_157():
# Write controlled values of Float16
vals = struct.pack(
"H" * 14,
0x0000, # Positive zero
0x8000, # Negative zero
0x7C00, # Positive infinity
0xFC00, # Negative infinity
0x7E00, # Some positive quiet NaN
0xFE00, # Some negative quiet NaN
0x3D00, # 1.25
0xBD00, # -1.25
0x0001, # Smallest positive denormalized value
0x8001, # Smallest negative denormalized value
0x03FF, # Largest positive denormalized value
0x83FF, # Largest negative denormalized value
0x0400, # Smallest positive normalized value
0x8400, # Smallest negative normalized value
)
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_157.tif", 14, 1, 1, gdal.GDT_Float32, options=["NBITS=16"]
)
ds = None
ds = gdal.Open("/vsimem/tiff_write_157.tif")
offset = int(ds.GetRasterBand(1).GetMetadataItem("BLOCK_OFFSET_0_0", "TIFF"))
ds = None
f = gdal.VSIFOpenL("/vsimem/tiff_write_157.tif", "rb+")
gdal.VSIFSeekL(f, offset, 0)
gdal.VSIFWriteL(vals, 1, len(vals), f)
gdal.VSIFCloseL(f)
# Check that we properly deserialize Float16 values
ds = gdal.Open("/vsimem/tiff_write_157.tif")
assert ds.GetRasterBand(1).GetMetadataItem("NBITS", "IMAGE_STRUCTURE") == "16"
got = struct.unpack("f" * 14, ds.ReadRaster())
expected = [
0.0,
-0.0,
gdaltest.posinf(),
-gdaltest.posinf(),
gdaltest.NaN(),
gdaltest.NaN(),
1.25,
-1.25,
5.9604644775390625e-08,
-5.9604644775390625e-08,
6.0975551605224609e-05,
-6.0975551605224609e-05,
6.103515625e-05,
-6.103515625e-05,
]
for i in range(14):
if i == 4 or i == 5:
assert got[i] != got[i]
elif got[i] != pytest.approx(expected[i], abs=1e-15):
print(got[i])
print(expected[i])
pytest.fail(i)
# Check that we properly decode&re-encode Float16 values
gdal.Translate("/vsimem/tiff_write_157_dst.tif", ds)
ds = None
ds = gdal.Open("/vsimem/tiff_write_157_dst.tif")
offset = int(ds.GetRasterBand(1).GetMetadataItem("BLOCK_OFFSET_0_0", "TIFF"))
ds = None
f = gdal.VSIFOpenL("/vsimem/tiff_write_157_dst.tif", "rb")
gdal.VSIFSeekL(f, offset, 0)
vals_copied = gdal.VSIFReadL(1, 14 * 2, f)
gdal.VSIFCloseL(f)
if vals != vals_copied:
print(struct.unpack("H" * 14, vals))
pytest.fail(struct.unpack("H" * 14, vals_copied))
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_157.tif")
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_157_dst.tif")
# Now try Float32 -> Float16 conversion
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_157.tif", 18, 1, 1, gdal.GDT_Float32, options=["NBITS=16"]
)
vals = struct.pack(
"I" * 18,
0x00000000, # Positive zero
0x80000000, # Negative zero
0x7F800000, # Positive infinity
0xFF800000, # Negative infinity
0x7FC00000, # Some positive quiet NaN
0xFFC00000, # Some negative quiet NaN
0x7F800001, # Some positive signaling NaN with significant that will get lost
0xFF800001, # Some negative signaling NaN with significant that will get lost
0x3FA00000, # 1.25
0xBFA00000, # -1.25
0x00000001, # Smallest positive denormalized value
0x80000001, # Smallest negative denormalized value
0x007FFFFF, # Largest positive denormalized value
0x807FFFFF, # Largest negative denormalized value
0x00800000, # Smallest positive normalized value
0x80800000, # Smallest negative normalized value
0x33800000, # 5.9604644775390625e-08 = Smallest number that can be converted as a float16 denormalized value
0x47800000, # 65536 --> converted to infinity
)
ds.GetRasterBand(1).WriteRaster(0, 0, 18, 1, vals, buf_type=gdal.GDT_Float32)
with gdaltest.error_handler():
ds.FlushCache()
ds = None
ds = gdal.Open("/vsimem/tiff_write_157.tif")
got = struct.unpack("f" * 18, ds.ReadRaster())
ds = None
expected = (
0.0,
-0.0,
gdaltest.posinf(),
-gdaltest.posinf(),
gdaltest.NaN(),
gdaltest.NaN(),
gdaltest.NaN(),
gdaltest.NaN(),
1.25,
-1.25,
0.0,
-0.0,
0.0,
-0.0,
0.0,
-0.0,
5.9604644775390625e-08,
gdaltest.posinf(),
)
for i in range(18):
if i in (4, 5, 6, 7):
# NaN comparison doesn't work like you'd expect
assert got[i] != got[i]
else:
assert got[i] == pytest.approx(expected[i], abs=1e-15)
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_157.tif")
# Test pixel interleaved
gdal.Translate(
"/vsimem/tiff_write_157.tif",
"../gdrivers/data/small_world.tif",
options="-co NBITS=16 -ot Float32",
)
ds = gdal.Open("/vsimem/tiff_write_157.tif")
cs = ds.GetRasterBand(1).Checksum()
assert cs == 30111
cs = ds.GetRasterBand(2).Checksum()
assert cs == 32302
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_157.tif")
###############################################################################
# Test GetActualBlockSize() (perhaps not the best place for that...)
def test_tiff_write_158():
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_158.tif",
20,
40,
1,
options=["TILED=YES", "BLOCKXSIZE=16", "BLOCKYSIZE=32"],
)
(w, h) = ds.GetRasterBand(1).GetActualBlockSize(0, 0)
assert (w, h) == (16, 32)
(w, h) = ds.GetRasterBand(1).GetActualBlockSize(1, 1)
assert (w, h) == (4, 8)
res = ds.GetRasterBand(1).GetActualBlockSize(2, 0)
assert res is None
res = ds.GetRasterBand(1).GetActualBlockSize(0, 2)
assert res is None
res = ds.GetRasterBand(1).GetActualBlockSize(-1, 0)
assert res is None
res = ds.GetRasterBand(1).GetActualBlockSize(0, -1)
assert res is None
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_158.tif")
###############################################################################
# Test that COPY_SRC_OVERVIEWS creation option with JPEG compression
# result in a https://trac.osgeo.org/gdal/wiki/CloudOptimizedGeoTIFF
@pytest.mark.require_creation_option("GTiff", "JPEG")
def test_tiff_write_159():
prev_table = ""
for options in [[], ["JPEG_QUALITY=50"], ["PHOTOMETRIC=YCBCR"]]:
src_ds = gdal.Translate("", "../gdrivers/data/small_world.tif", format="MEM")
src_ds.BuildOverviews("NEAR", overviewlist=[2, 4])
ds = gdaltest.tiff_drv.CreateCopy(
"/vsimem/tiff_write_159.tif",
src_ds,
options=["COPY_SRC_OVERVIEWS=YES", "COMPRESS=JPEG"] + options,
)
ds = None
src_ds = None
ds = gdal.Open("/vsimem/tiff_write_159.tif")
cs0 = ds.GetRasterBand(1).Checksum()
cs1 = ds.GetRasterBand(1).GetOverview(0).Checksum()
cs2 = ds.GetRasterBand(1).GetOverview(1).Checksum()
assert not (cs0 == 0 or cs1 == 0 or cs2 == 0), options
ifd_main = int(ds.GetRasterBand(1).GetMetadataItem("IFD_OFFSET", "TIFF"))
ifd_ovr_0 = int(
ds.GetRasterBand(1).GetOverview(0).GetMetadataItem("IFD_OFFSET", "TIFF")
)
ifd_ovr_1 = int(
ds.GetRasterBand(1).GetOverview(1).GetMetadataItem("IFD_OFFSET", "TIFF")
)
data_ovr_1 = int(
ds.GetRasterBand(1)
.GetOverview(1)
.GetMetadataItem("BLOCK_OFFSET_0_0", "TIFF")
)
data_ovr_0 = int(
ds.GetRasterBand(1)
.GetOverview(0)
.GetMetadataItem("BLOCK_OFFSET_0_0", "TIFF")
)
data_main = int(ds.GetRasterBand(1).GetMetadataItem("BLOCK_OFFSET_0_0", "TIFF"))
assert (
ifd_main < ifd_ovr_0
and ifd_ovr_0 < ifd_ovr_1
and ifd_ovr_1 < data_ovr_1
and data_ovr_1 < data_ovr_0
and data_ovr_0 < data_main
), options
table_main = ds.GetRasterBand(1).GetMetadataItem("JPEGTABLES", "TIFF")
table_ovr_0 = (
ds.GetRasterBand(1).GetOverview(0).GetMetadataItem("JPEGTABLES", "TIFF")
)
table_ovr_1 = (
ds.GetRasterBand(1).GetOverview(1).GetMetadataItem("JPEGTABLES", "TIFF")
)
assert table_main == table_ovr_0 and table_ovr_0 == table_ovr_1, options
# Check that the JPEG tables are different in the 3 modes
assert table_main != prev_table, options
prev_table = table_main
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_159.tif")
for value in range(4):
src_ds = gdal.Translate("", "data/byte.tif", format="MEM")
src_ds.BuildOverviews("NEAR", overviewlist=[2])
ds = gdaltest.tiff_drv.CreateCopy(
"/vsimem/tiff_write_159.tif",
src_ds,
options=[
"COPY_SRC_OVERVIEWS=YES",
"COMPRESS=JPEG",
"JPEGTABLESMODE=%d" % value,
],
)
ds = None
src_ds = None
ds = gdal.Open("/vsimem/tiff_write_159.tif")
cs0 = ds.GetRasterBand(1).Checksum()
cs1 = ds.GetRasterBand(1).GetOverview(0).Checksum()
assert cs0 == 4743 and cs1 == 1133, value
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_159.tif")
###############################################################################
# Test the Create() interface with a BLOCKYSIZE > image height
def test_tiff_write_160():
ds = gdaltest.tiff_drv.Create(
"/vsimem/tiff_write_160.tif", 10, 10, options=["BLOCKYSIZE=11"]
)
ds.GetRasterBand(1).Fill(255)
ds = None
ds = gdal.Open("/vsimem/tiff_write_160.tif")
cs = ds.GetRasterBand(1).Checksum()
assert cs == 1218
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_160.tif")
###############################################################################
# Test setting GCPs on an image with already a geotransform and vice-versa (#6751)
def test_tiff_write_161():
ds = gdaltest.tiff_drv.Create("/vsimem/tiff_write_161.tif", 1, 1)
ds.SetGeoTransform([0, 1, 2, 3, 4, 5])
ds = None
ds = gdal.Open("/vsimem/tiff_write_161.tif", gdal.GA_Update)
src_ds = gdal.Open("data/gcps.vrt")
with gdaltest.error_handler():
assert ds.SetGCPs(src_ds.GetGCPs(), "") == 0
assert ds.GetGeoTransform(can_return_null=True) is None
ds = None
ds = gdal.Open("/vsimem/tiff_write_161.tif", gdal.GA_Update)
assert ds.GetGCPs()
assert ds.GetGeoTransform(can_return_null=True) is None
with gdaltest.error_handler():
assert ds.SetGeoTransform([0, 1, 2, 3, 4, 5]) == 0
assert ds.GetGeoTransform() == (0.0, 1.0, 2.0, 3.0, 4.0, 5.0)
assert not ds.GetGCPs()
ds = None
ds = gdal.Open("/vsimem/tiff_write_161.tif", gdal.GA_Update)
assert not ds.GetGCPs()
assert ds.GetGeoTransform() == (0.0, 1.0, 2.0, 3.0, 4.0, 5.0)
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_161.tif")
###############################################################################
# Test creating a JPEG compressed file with big tiles (#6757)
@pytest.mark.require_creation_option("GTiff", "JPEG")
def test_tiff_write_162():
src_ds = gdal.GetDriverByName("MEM").Create("", 512, 512, 3)
options = ["TILED=YES", "BLOCKXSIZE=512", "BLOCKYSIZE=512", "COMPRESS=JPEG"]
gdaltest.tiff_drv.CreateCopy("/vsimem/tiff_write_162.tif", src_ds, options=options)
assert gdal.GetLastErrorMsg() == ""
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_162.tif")
###############################################################################
# Test creating a file that would trigger strip chopping (#6924)
def test_tiff_write_163():
# Was a libtiff 4.0.8 regression
if gdaltest.tiff_drv.GetMetadataItem("LIBTIFF").find("4.0.8") >= 0:
pytest.skip("Test broken with libtiff 4.0.8")
gdal.Translate(
"/vsimem/tiff_write_163.tif",
"data/byte.tif",
options="-outsize 1 20000 -co BLOCKYSIZE=20000 -co PROFILE=BASELINE",
)
ds = gdal.Open("/vsimem/tiff_write_163.tif")
cs = ds.GetRasterBand(1).Checksum()
assert cs == 47600
# Check that IsBlockAvailable() works properly in that mode
offset_0_2 = ds.GetRasterBand(1).GetMetadataItem("BLOCK_OFFSET_0_2", "TIFF")
assert offset_0_2 == str(146 + 2 * 8192)
ds = None
gdaltest.tiff_drv.Delete("/vsimem/tiff_write_163.tif")
###############################################################################
# Test that we handle [0,1,0,0,0,1] geotransform as a regular geotransform
def test_tiff_write_164():
ds = gdaltest.tiff_drv.Create("/vsimem/test.tif", 1, 1)
ds.SetGeoTransform([0, 1, 0, 0, 0, 1])
ds = None
ds = gdal.Open("/vsimem/test.tif")
gt = ds.GetGeoTransform(can_return_null=True)
ds = None
assert gt == (0, 1, 0, 0, 0, 1)
# Test [0,1,0,0,0,-1] as well
ds = gdaltest.tiff_drv.Create("/vsimem/test.tif", 1, 1)
ds.SetGeoTransform([0, 1, 0, 0, 0, -1])
ds = None
ds = gdal.Open("/vsimem/test.tif")
gt = ds.GetGeoTransform(can_return_null=True)
ds = None
assert gt == (0, 1, 0, 0, 0, -1)
gdal.Unlink("/vsimem/test.tif")
###############################################################################
# Test the current behaviour of per-band nodata vs per-dataset serialization
def test_tiff_write_165():
ds = gdaltest.tiff_drv.Create("/vsimem/test.tif", 1, 1, 3)
ret = ds.GetRasterBand(1).SetNoDataValue(100)
assert ret == 0
with gdaltest.error_handler():
ret = ds.GetRasterBand(2).SetNoDataValue(200)
assert gdal.GetLastErrorMsg() != "", "warning expected, but not emitted"
assert ret == 0
nd = ds.GetRasterBand(1).GetNoDataValue()
assert nd == 100
nd = ds.GetRasterBand(2).GetNoDataValue()
assert nd == 200
ds = None
ds = gdal.Open("/vsimem/test.tif")
nd = ds.GetRasterBand(1).GetNoDataValue()
ds = None
assert nd == 200
gdal.Unlink("/vsimem/test.tif")
###############################################################################
# Test reading & writing Z dimension for ModelTiepointTag and ModelPixelScaleTag (#7093)
def test_tiff_write_166():
with gdaltest.config_option("GTIFF_REPORT_COMPD_CS", "YES"):
ds = gdal.Open("data/tiff_vertcs_scale_offset.tif")
assert ds.GetRasterBand(1).GetScale() == 2.0
assert ds.GetRasterBand(1).GetOffset() == 10.0
# Scale + offset through CreateCopy()
gdal.Translate(
"/vsimem/tiff_write_166.tif",
"data/byte.tif",
options="-a_srs EPSG:26711+5773 -a_scale 2.0 -a_offset 10 -co PROFILE=GEOTIFF",
)
assert gdal.VSIStatL("/vsimem/tiff_write_166.tif.aux.xml") is None
with gdaltest.config_option("GTIFF_REPORT_COMPD_CS", "YES"):
ds = gdal.Open("/vsimem/tiff_write_166.tif")
assert ds.GetRasterBand(1).GetScale() == 2.0
assert ds.GetRasterBand(1).GetOffset() == 10.0
ds = None
gdal.Unlink("/vsimem/tiff_write_166.tif")
# Offset only through CreateCopy()
gdal.Translate(
"/vsimem/tiff_write_166.tif",
"data/byte.tif",
options="-a_srs EPSG:26711+5773 -a_offset 10 -co PROFILE=GEOTIFF",
)
assert gdal.VSIStatL("/vsimem/tiff_write_166.tif.aux.xml") is None
with gdaltest.config_option("GTIFF_REPORT_COMPD_CS", "YES"):
ds = gdal.Open("/vsimem/tiff_write_166.tif")
assert ds.GetRasterBand(1).GetScale() == 1.0
assert ds.GetRasterBand(1).GetOffset() == 10.0
ds = None
gdal.Unlink("/vsimem/tiff_write_166.tif")
# Scale + offset through Create()
ds = gdal.GetDriverByName("GTiff").Create(
"/vsimem/tiff_write_166.tif", 1, 1, options=["PROFILE=GEOTIFF"]
)
sr = osr.SpatialReference()
sr.SetFromUserInput("EPSG:26711+5773")
ds.SetProjection(sr.ExportToWkt())
ds.SetGeoTransform([440720, 60, 0, 3751320, 0, -60])
ds.GetRasterBand(1).SetScale(2)
ds.GetRasterBand(1).SetOffset(10)
ds = None
assert gdal.VSIStatL("/vsimem/tiff_write_166.tif.aux.xml") is None
with gdaltest.config_option("GTIFF_REPORT_COMPD_CS", "YES"):
ds = gdal.Open("/vsimem/tiff_write_166.tif")
assert ds.GetRasterBand(1).GetScale() == 2.0
assert ds.GetRasterBand(1).GetOffset() == 10.0
ds = None
gdal.Unlink("/vsimem/tiff_write_166.tif")
# Scale only through Create()
ds = gdal.GetDriverByName("GTiff").Create(
"/vsimem/tiff_write_166.tif", 1, 1, options=["PROFILE=GEOTIFF"]
)
sr = osr.SpatialReference()
sr.SetFromUserInput("EPSG:26711+5773")
ds.SetProjection(sr.ExportToWkt())
ds.SetGeoTransform([440720, 60, 0, 3751320, 0, -60])
ds.GetRasterBand(1).SetScale(2)
ds = None
assert gdal.VSIStatL("/vsimem/tiff_write_166.tif.aux.xml") is None
with gdaltest.config_option("GTIFF_REPORT_COMPD_CS", "YES"):
ds = gdal.Open("/vsimem/tiff_write_166.tif")
assert ds.GetRasterBand(1).GetScale() == 2.0
assert ds.GetRasterBand(1).GetOffset() == 0.0
ds = None
gdal.Unlink("/vsimem/tiff_write_166.tif")
# Offset only through through Create()
ds = gdal.GetDriverByName("GTiff").Create(
"/vsimem/tiff_write_166.tif", 1, 1, options=["PROFILE=GEOTIFF"]
)
sr = osr.SpatialReference()
sr.SetFromUserInput("EPSG:26711+5773")
ds.SetProjection(sr.ExportToWkt())
ds.SetGeoTransform([440720, 60, 0, 3751320, 0, -60])
ds.GetRasterBand(1).SetOffset(10)
ds = None
assert gdal.VSIStatL("/vsimem/tiff_write_166.tif.aux.xml") is None
with gdaltest.config_option("GTIFF_REPORT_COMPD_CS", "YES"):
ds = gdal.Open("/vsimem/tiff_write_166.tif")
assert ds.GetRasterBand(1).GetScale() == 1.0
assert ds.GetRasterBand(1).GetOffset() == 10.0
ds = None
gdal.Unlink("/vsimem/tiff_write_166.tif")
###############################################################################
def test_tiff_write_167_deflate_zlevel():
src_ds = gdal.Open("data/byte.tif")
gdal.GetDriverByName("GTiff").CreateCopy(
"/vsimem/out.tif", src_ds, options=["COMPRESS=DEFLATE", "ZLEVEL=1"]
)
size1 = gdal.VSIStatL("/vsimem/out.tif").size
gdal.GetDriverByName("GTiff").CreateCopy(
"/vsimem/out.tif",
src_ds,
options=["COMPRESS=DEFLATE", "NUM_THREADS=2", "ZLEVEL=9"],
)
size2 = gdal.VSIStatL("/vsimem/out.tif").size
gdal.Unlink("/vsimem/out.tif")
assert size2 < size1
ds = gdal.GetDriverByName("GTiff").Create(
"/vsimem/out.tif", 20, 20, 1, options=["COMPRESS=DEFLATE", "ZLEVEL=9"]
)
ds.SetProjection(src_ds.GetProjectionRef())
ds.SetGeoTransform(src_ds.GetGeoTransform())
ds.WriteRaster(0, 0, 20, 20, src_ds.ReadRaster())
ds = None
size2_create = gdal.VSIStatL("/vsimem/out.tif").size
gdal.Unlink("/vsimem/out.tif")
assert size2 == size2_create
###############################################################################
# Test CCITTFAX3
def test_tiff_write_168_ccitfax3():
ut = gdaltest.GDALTest(
"GTiff", "oddsize1bit.tif", 1, 5918, options=["NBITS=1", "COMPRESS=CCITTFAX3"]
)
return ut.testCreateCopy()
###############################################################################
# Test CCITTRLE
def test_tiff_write_169_ccitrle():
ut = gdaltest.GDALTest(
"GTiff", "oddsize1bit.tif", 1, 5918, options=["NBITS=1", "COMPRESS=CCITTRLE"]
)
return ut.testCreateCopy()
###############################################################################
# Test invalid compression method
def test_tiff_write_170_invalid_compresion():
src_ds = gdal.Open("data/byte.tif")
with gdaltest.error_handler():
gdal.GetDriverByName("GTiff").CreateCopy(
"/vsimem/out.tif", src_ds, options=["COMPRESS=INVALID"]
)
assert gdal.GetLastErrorMsg() != ""
gdal.Unlink("/vsimem/out.tif")
###############################################################################
# Test ZSTD compression
@pytest.mark.require_creation_option("GTiff", "ZSTD")
def test_tiff_write_171_zstd():
ut = gdaltest.GDALTest(
"GTiff", "byte.tif", 1, 4672, options=["COMPRESS=ZSTD", "ZSTD_LEVEL=1"]
)
return ut.testCreateCopy()
###############################################################################
# Test ZSTD compression with PREDICTOR = 2
@pytest.mark.require_creation_option("GTiff", "ZSTD")
def test_tiff_write_171_zstd_predictor():
ut = gdaltest.GDALTest(
"GTiff",
"byte.tif",
1,
4672,
options=["COMPRESS=ZSTD", "ZSTD_LEVEL=1", "PREDICTOR=2"],
)
return ut.testCreateCopy()
###############################################################################
# Test WEBP compression
@pytest.mark.parametrize("writeImageStructureMetadata", [True, False])
@pytest.mark.require_creation_option("GTiff", "WEBP")
def test_tiff_write_webp(writeImageStructureMetadata):
filename = "/vsimem/test_tiff_write_webp.tif"
src_ds = gdal.Open("data/md_ge_rgb_0010000.tif")
with gdaltest.config_option(
"GTIFF_WRITE_IMAGE_STRUCTURE_METADATA",
"YES" if writeImageStructureMetadata else "NO",
):
gdaltest.tiff_drv.CreateCopy(
filename, src_ds, options=["COMPRESS=WEBP", "WEBP_LEVEL=50"]
)
ds = gdal.Open(filename)
assert ds.GetMetadataItem("WEBP_LOSSLESS", "_DEBUG_") == "0"
if writeImageStructureMetadata:
assert ds.GetMetadataItem("WEBP_LEVEL", "_DEBUG_") == "50"
assert ds.GetMetadata("IMAGE_STRUCTURE")["WEBP_LEVEL"] == "50"
else:
assert ds.GetMetadataItem("WEBP_LEVEL", "_DEBUG_") == "75"
if writeImageStructureMetadata or gdal.GetDriverByName("WEBP") is not None:
assert ds.GetMetadata("IMAGE_STRUCTURE")["COMPRESSION_REVERSIBILITY"] == "LOSSY"
cs = [ds.GetRasterBand(i + 1).Checksum() for i in range(3)]
assert cs != [0, 0, 0]
gdaltest.tiff_drv.Delete(filename)
gdal.Unlink("data/md_ge_rgb_0010000.tif.aux.xml")
###############################################################################
# Test WEBP compression with internal tiling
@pytest.mark.parametrize("writeImageStructureMetadata", [True, False])
@pytest.mark.require_creation_option("GTiff", "WEBP")
@pytest.mark.require_creation_option("GTiff", "WEBP_LOSSLESS")
def test_tiff_write_tiled_webp(writeImageStructureMetadata):
filename = "/vsimem/tiff_write_tiled_webp.tif"
src_ds = gdal.Open("data/md_ge_rgb_0010000.tif")
with gdaltest.config_option(
"GTIFF_WRITE_IMAGE_STRUCTURE_METADATA",
"YES" if writeImageStructureMetadata else "NO",
):
gdaltest.tiff_drv.CreateCopy(
filename,
src_ds,
options=["COMPRESS=WEBP", "WEBP_LOSSLESS=true", "TILED=true"],
)
ds = gdal.Open(filename)
if writeImageStructureMetadata:
assert ds.GetMetadataItem("WEBP_LOSSLESS", "_DEBUG_") == "1"
else:
assert ds.GetMetadataItem("WEBP_LOSSLESS", "_DEBUG_") == "0"
if writeImageStructureMetadata or gdal.GetDriverByName("WEBP"):
assert (
ds.GetMetadata("IMAGE_STRUCTURE")["COMPRESSION_REVERSIBILITY"] == "LOSSLESS"
)
assert ds.GetMetadataItem("WEBP_LEVEL", "IMAGE_STRUCTURE") is None
cs = [ds.GetRasterBand(i + 1).Checksum() for i in range(3)]
assert cs == [21212, 21053, 21349]
ds = None
ds = gdal.Open(filename, gdal.GA_Update)
if writeImageStructureMetadata or gdal.GetDriverByName("WEBP"):
assert ds.GetMetadataItem("WEBP_LOSSLESS", "_DEBUG_") == "1"
assert (
ds.GetMetadata("IMAGE_STRUCTURE")["COMPRESSION_REVERSIBILITY"] == "LOSSLESS"
)
ds = None
gdaltest.tiff_drv.Delete(filename)
gdal.Unlink("data/md_ge_rgb_0010000.tif.aux.xml")
###############################################################################
# Test WEBP compression with huge single strip
@pytest.mark.require_creation_option("GTiff", "WEBP")
def test_tiff_write_webp_huge_single_strip():
filename = "/vsimem/tif_webp_huge_single_strip.tif"
src_ds = gdal.Open("data/tif_webp_huge_single_strip.tif")
gdaltest.tiff_drv.CreateCopy(
filename, src_ds, options=["COMPRESS=WEBP", "BLOCKYSIZE=2001"]
)
ds = gdal.Open(filename)
original_stats = [
src_ds.GetRasterBand(i + 1).ComputeStatistics(True) for i in range(3)
]
got_stats = [ds.GetRasterBand(i + 1).ComputeStatistics(True) for i in range(3)]
ds = None
src_ds = None
for i in range(3):
for j in range(4):
assert original_stats[i][j] == pytest.approx(
got_stats[i][j], abs=1e-1 * abs(original_stats[i][j])
), "did not get expected statistics"
gdaltest.tiff_drv.Delete(filename)
gdal.Unlink("data/tif_webp_huge_single_strip.tif.aux.xml")
###############################################################################
# GeoTIFF DGIWG tags
def test_tiff_write_172_geometadata_tiff_rsid():
tmpfilename = "/vsimem/tiff_write_172_geometadata_tiff_rsid.tiff"
ds = gdal.GetDriverByName("GTiff").Create(tmpfilename, 1, 1)
ds.SetMetadataItem("GEO_METADATA", "foo")
ds.SetMetadataItem("TIFF_RSID", "bar")
ds = None
ds = gdal.Open(tmpfilename, gdal.GA_Update)
assert ds.GetMetadataItem("GEO_METADATA") == "foo", ds.GetMetadata()
assert ds.GetMetadataItem("TIFF_RSID") == "bar", ds.GetMetadata()
ds.SetMetadata({})
ds = None
ds = gdal.Open(tmpfilename)
assert ds.GetMetadataItem("GEO_METADATA") is None, ds.GetMetadata()
assert ds.GetMetadataItem("TIFF_RSID") is None, ds.GetMetadata()
ds = None
gdal.Unlink(tmpfilename)
###############################################################################
# Test LERC compression
@pytest.mark.require_creation_option("GTiff", "LERC")
def test_tiff_write_173_lerc():
ut = gdaltest.GDALTest("GTiff", "byte.tif", 1, 4672, options=["COMPRESS=LERC"])
return ut.testCreateCopy()
###############################################################################
# Test LERC_DEFLATE compression
@pytest.mark.require_creation_option("GTiff", "LERC_DEFLATE")
def test_tiff_write_174_lerc_deflate():
ut = gdaltest.GDALTest(
"GTiff", "byte.tif", 1, 4672, options=["COMPRESS=LERC_DEFLATE"]
)
return ut.testCreateCopy()
###############################################################################
# Test LERC_DEFLATE compression
@pytest.mark.require_creation_option("GTiff", "LERC_DEFLATE")
def test_tiff_write_174_lerc_deflate_with_level():
ut = gdaltest.GDALTest(
"GTiff", "byte.tif", 1, 4672, options=["COMPRESS=LERC_DEFLATE", "ZLEVEL=1"]
)
return ut.testCreateCopy()
###############################################################################
# Test LERC_ZSTD compression
@pytest.mark.require_creation_option("GTiff", "LERC_ZSTD")
def test_tiff_write_175_lerc_zstd():
ut = gdaltest.GDALTest("GTiff", "byte.tif", 1, 4672, options=["COMPRESS=LERC_ZSTD"])
return ut.testCreateCopy()
###############################################################################
# Test LERC_ZSTD compression
@pytest.mark.require_creation_option("GTiff", "LERC_ZSTD")
def test_tiff_write_175_lerc_zstd_with_level():
ut = gdaltest.GDALTest(
"GTiff", "byte.tif", 1, 4672, options=["COMPRESS=LERC_ZSTD", "ZSTD_LEVEL=1"]
)
return ut.testCreateCopy()
###############################################################################
# Test LERC compression with MAX_Z_ERROR
@pytest.mark.require_creation_option("GTiff", "LERC")
def test_tiff_write_176_lerc_max_z_error():
ut = gdaltest.GDALTest(
"GTiff", "byte.tif", 1, 4529, options=["COMPRESS=LERC", "MAX_Z_ERROR=1"]
)
return ut.testCreateCopy(skip_preclose_test=1)
###############################################################################
# Test LERC compression with several bands and tiling
@pytest.mark.require_creation_option("GTiff", "LERC")
def test_tiff_write_177_lerc_several_bands_tiling():
filename = "/vsimem/tiff_write_177_lerc_several_bands_tiling.tif"
gdal.Translate(
filename,
"../gdrivers/data/small_world.tif",
creationOptions=["COMPRESS=LERC", "TILED=YES"],
)
ds = gdal.Open(filename)
cs = [ds.GetRasterBand(i + 1).Checksum() for i in range(3)]
ds = None
gdal.Unlink(filename)
assert cs == [30111, 32302, 40026]
###############################################################################
# Test LERC compression with alpha band
@pytest.mark.require_creation_option("GTiff", "LERC")
def test_tiff_write_178_lerc_with_alpha():
filename = "/vsimem/tiff_write_178_lerc_with_alpha.tif"
gdal.Translate(
filename, "data/stefan_full_rgba.tif", creationOptions=["COMPRESS=LERC"]
)
ds = gdal.Open(filename)
cs = [ds.GetRasterBand(i + 1).Checksum() for i in range(4)]
ds = None
gdal.Unlink(filename)
assert cs == [12603, 58561, 36064, 10807]
###############################################################################
# Test LERC compression with alpha band with only 0 and 255
@pytest.mark.require_creation_option("GTiff", "LERC")
def test_tiff_write_178_lerc_with_alpha_0_and_255():
filename = "/vsimem/tiff_write_178_lerc_with_alpha_0_and_255.tif"
gdal.Translate(
filename,
"data/rgba_with_alpha_0_and_255.tif",
creationOptions=["COMPRESS=LERC"],
)
ds = gdal.Open(filename)
cs = [ds.GetRasterBand(i + 1).Checksum() for i in range(4)]
ds = None
gdal.Unlink(filename)
assert cs == [13, 13, 13, 13]
###############################################################################
# Test LERC compression with different data types
@pytest.mark.require_creation_option("GTiff", "LERC")
def test_tiff_write_179_lerc_data_types():
filename = "/vsimem/tiff_write_179_lerc_data_types.tif"
for src_filename in [
"uint16.tif",
"int16.tif",
"uint32.tif",
"int32.tif",
"float32.tif",
"float64.tif",
]:
gdal.Translate(
filename, "data/" + src_filename, creationOptions=["COMPRESS=LERC"]
)
ds = gdal.Open(filename)
cs = ds.GetRasterBand(1).Checksum()
ds = None
gdal.Unlink(filename)
assert cs == 4672
filename_tmp = filename + ".tmp.tif"
with gdaltest.error_handler():
gdal.Translate(
filename_tmp, "data/byte.tif", creationOptions=["PIXELTYPE=SIGNEDBYTE"]
)
gdal.Translate(filename, filename_tmp, creationOptions=["COMPRESS=LERC"])
gdal.Unlink(filename_tmp)
ds = gdal.Open(filename)
cs = ds.GetRasterBand(1).Checksum()
ds = None
gdal.Unlink(filename)
assert cs == 1046
gdal.ErrorReset()
with gdaltest.error_handler():
gdal.Translate(filename, "data/cfloat32.tif", creationOptions=["COMPRESS=LERC"])
assert gdal.GetLastErrorMsg() != ""
gdal.Unlink(filename)
###############################################################################
# Test LERC compression with several bands and separate
@pytest.mark.require_creation_option("GTiff", "LERC")
def test_tiff_write_180_lerc_separate():
filename = "/vsimem/tiff_write_180_lerc_separate.tif"
gdal.Translate(
filename,
"../gdrivers/data/small_world.tif",
creationOptions=["COMPRESS=LERC", "INTERLEAVE=BAND"],
)
ds = gdal.Open(filename)
cs = [ds.GetRasterBand(i + 1).Checksum() for i in range(3)]
ds = None
gdal.Unlink(filename)
assert cs == [30111, 32302, 40026]
###############################################################################
# Test MAX_Z_ERROR_OVERVIEW effect while creating overviews
# on a newly created dataset
@pytest.mark.parametrize(
"external_ovr,compression",
[
(True, "LERC_ZSTD"),
(False, "LERC_ZSTD"),
(True, "LERC_DEFLATE"),
(False, "LERC_DEFLATE"),
],
)
def test_tiff_write_lerc_overview(external_ovr, compression):
md = gdaltest.tiff_drv.GetMetadata()
if compression not in md["DMD_CREATIONOPTIONLIST"]:
pytest.skip()
checksums = {}
errors = [0, 10, 10]
src_ds = gdal.Open("../gdrivers/data/utm.tif")
for i, error in enumerate(errors):
fname = "/vsimem/test_tiff_write_lerc_overview_%d" % i
ds = gdal.GetDriverByName("GTiff").Create(
fname,
256,
256,
1,
options=["COMPRESS=" + compression, "MAX_Z_ERROR=%f" % error],
)
data = src_ds.GetRasterBand(1).ReadRaster(0, 0, 512, 512, 256, 256)
ds.GetRasterBand(1).WriteRaster(0, 0, 256, 256, data)
if i == 2:
error = 30
options = {}
if external_ovr:
ds = None
ds = gdal.Open(fname)
options["COMPRESS_OVERVIEW"] = compression
options["MAX_Z_ERROR_OVERVIEW"] = "%d" % error
with gdaltest.config_options(options):
ds.BuildOverviews("AVERAGE", overviewlist=[2, 4])
ds = None
ds = gdal.Open(fname)
assert (
ds.GetRasterBand(1)
.GetOverview(0)
.GetDataset()
.GetMetadataItem("COMPRESSION", "IMAGE_STRUCTURE")
== compression
)
checksums[i] = [
ds.GetRasterBand(1).Checksum(),
ds.GetRasterBand(1).GetOverview(0).Checksum(),
ds.GetRasterBand(1).GetOverview(1).Checksum(),
]
ds = None
gdaltest.tiff_drv.Delete(fname)
assert checksums[0][0] != checksums[1][0]
assert checksums[0][1] != checksums[1][1]
assert checksums[0][2] != checksums[1][2]
assert checksums[0][0] != checksums[2][0]
assert checksums[0][1] != checksums[2][1]
assert checksums[0][2] != checksums[2][2]
assert checksums[1][0] == checksums[2][0]
assert checksums[1][1] != checksums[2][1]
assert checksums[1][2] != checksums[2][2]
###############################################################################
# Test ZLEVEL_OVERVIEW effect while creating overviews
# on a newly created dataset
@pytest.mark.parametrize("external_ovr", [True, False])
@pytest.mark.require_creation_option("GTiff", "LERC_DEFLATE")
def test_tiff_write_lerc_zlevel(external_ovr):
filesize = {}
src_ds = gdal.Open("../gdrivers/data/utm.tif")
for level in (1, 9):
fname = "/vsimem/test_tiff_write_lerc_zlevel_%d" % level
ds = gdal.GetDriverByName("GTiff").Create(
fname, 256, 256, 1, options=["COMPRESS=LERC_DEFLATE"]
)
data = src_ds.GetRasterBand(1).ReadRaster(0, 0, 512, 512, 256, 256)
ds.GetRasterBand(1).WriteRaster(0, 0, 256, 256, data)
options = {"MAX_Z_ERROR_OVERVIEW": "10"}
if external_ovr:
ds = None
ds = gdal.Open(fname)
options["COMPRESS_OVERVIEW"] = "LERC_DEFLATE"
options["ZLEVEL_OVERVIEW"] = "%d" % level
with gdaltest.config_options(options):
ds.BuildOverviews("AVERAGE", overviewlist=[2, 4])
ds = None
if external_ovr:
filesize[level] = gdal.VSIStatL(fname + ".ovr").size
else:
filesize[level] = gdal.VSIStatL(fname).size
gdaltest.tiff_drv.Delete(fname)
assert filesize[1] > filesize[9]
###############################################################################
# Test ZSTD_LEVEL_OVERVIEW effect while creating overviews
# on a newly created dataset
@pytest.mark.parametrize("external_ovr", [True, False])
@pytest.mark.require_creation_option("GTiff", "LERC_ZSTD")
def test_tiff_write_lerc_zstd_level(external_ovr):
filesize = {}
src_ds = gdal.Open("../gdrivers/data/utm.tif")
for level in (1, 22):
fname = "/vsimem/test_tiff_write_lerc_zstd_level_%d" % level
ds = gdal.GetDriverByName("GTiff").Create(
fname, 256, 256, 1, options=["COMPRESS=LERC_ZSTD"]
)
data = src_ds.GetRasterBand(1).ReadRaster(0, 0, 512, 512, 256, 256)
ds.GetRasterBand(1).WriteRaster(0, 0, 256, 256, data)
options = {"MAX_Z_ERROR_OVERVIEW": "10"}
if external_ovr:
ds = None
ds = gdal.Open(fname)
options["COMPRESS_OVERVIEW"] = "LERC_ZSTD"
options["ZSTD_LEVEL_OVERVIEW"] = "%d" % level
with gdaltest.config_options(options):
ds.BuildOverviews("AVERAGE", overviewlist=[2, 4])
ds = None
if external_ovr:
filesize[level] = gdal.VSIStatL(fname + ".ovr").size
else:
filesize[level] = gdal.VSIStatL(fname).size
gdaltest.tiff_drv.Delete(fname)
assert filesize[1] > filesize[22]
###############################################################################
# Test set XMP metadata
def test_tiff_write_181_xmp():
src_ds = gdal.Open("data/utmsmall.tif")
new_ds = gdaltest.tiff_drv.CreateCopy("tmp/test_181.tif", src_ds)
src_ds = None
xmp_ds = gdal.Open("../gdrivers/data/gtiff/byte_with_xmp.tif")
xmp = xmp_ds.GetMetadata("xml:XMP")
xmp_ds = None
assert "W5M0MpCehiHzreSzNTczkc9d" in xmp[0], "Wrong input file without XMP"
new_ds.SetMetadata(xmp, "xml:XMP")
new_ds = None
# hopefully it's closed now!
new_ds = gdal.Open("tmp/test_181.tif")
read_xmp = new_ds.GetMetadata("xml:XMP")
assert (
read_xmp and "W5M0MpCehiHzreSzNTczkc9d" in read_xmp[0]
), "No XMP data written in output file"
new_ds = None
gdaltest.tiff_drv.Delete("tmp/test_181.tif")
def test_tiff_write_181_xmp_copy():
src_ds = gdal.Open("../gdrivers/data/gtiff/byte_with_xmp.tif")
filename = "tmp/test_181_copy.tif"
new_ds = gdaltest.tiff_drv.CreateCopy(filename, src_ds)
assert new_ds is not None
src_ds = None
new_ds = None
new_ds = gdal.Open(filename)
assert (
int(new_ds.GetRasterBand(1).GetMetadataItem("IFD_OFFSET", "TIFF")) == 8
), "TIFF directory not at the beginning"
xmp = new_ds.GetMetadata("xml:XMP")
new_ds = None
assert "W5M0MpCehiHzreSzNTczkc9d" in xmp[0], "Wrong input file without XMP"
gdaltest.tiff_drv.Delete(filename)
###############################################################################
# Test delete XMP from a dataset
def test_tiff_write_182_xmp_delete():
shutil.copyfile("../gdrivers/data/gtiff/byte_with_xmp.tif", "tmp/test_182.tif")
chg_ds = gdal.Open("tmp/test_182.tif", gdal.GA_Update)
read_xmp = chg_ds.GetMetadata("xml:XMP")
assert (
read_xmp and "W5M0MpCehiHzreSzNTczkc9d" in read_xmp[0]
), "No XMP data written in output file"
chg_ds.SetMetadata(None, "xml:XMP")
chg_ds = None
again_ds = gdal.Open("tmp/test_182.tif")
read_xmp = again_ds.GetMetadata("xml:XMP")
assert not read_xmp, "XMP data not removed"
again_ds = None
gdaltest.tiff_drv.Delete("tmp/test_182.tif")
###############################################################################
def test_tiff_write_183_createcopy_append_subdataset():
tmpfilename = "/vsimem/test_tiff_write_183_createcopy_append_subdataset.tif"
gdal.Translate(tmpfilename, "data/byte.tif")
gdal.Translate(
tmpfilename, "data/utmsmall.tif", creationOptions=["APPEND_SUBDATASET=YES"]
)
ds = gdal.Open(tmpfilename)
assert ds.GetRasterBand(1).Checksum() == 4672
ds = gdal.Open("GTIFF_DIR:2:" + tmpfilename)
assert ds.GetRasterBand(1).Checksum() == 50054
ds = None
gdal.Unlink(tmpfilename)
###############################################################################
def test_tiff_write_184_create_append_subdataset():
tmpfilename = "/vsimem/test_tiff_write_184_create_append_subdataset.tif"
gdal.Translate(tmpfilename, "data/byte.tif")
ds = gdal.GetDriverByName("GTiff").Create(
tmpfilename, 1, 1, options=["APPEND_SUBDATASET=YES"]
)
ds.GetRasterBand(1).Fill(255)
ds = None
ds = gdal.Open(tmpfilename)
assert ds.GetRasterBand(1).Checksum() == 4672
ds = gdal.Open("GTIFF_DIR:2:" + tmpfilename)
assert ds.GetRasterBand(1).Checksum() == 3
ds = None
gdal.Unlink(tmpfilename)
###############################################################################
# Test LERC compression with Create() and BuildOverviews()
# Fixes https://github.com/OSGeo/gdal/issues/1257
@pytest.mark.require_creation_option("GTiff", "LERC")
def test_tiff_write_185_lerc_create_and_overview():
filename = "/vsimem/test_tiff_write_185_lerc_create_and_overview.tif"
ds = gdaltest.tiff_drv.Create(filename, 20, 20, options=["COMPRESS=LERC_DEFLATE"])
src_ds = gdal.Open("data/byte.tif")
ds.WriteRaster(0, 0, 20, 20, src_ds.ReadRaster())
gdal.ErrorReset()
ds.BuildOverviews("NEAR", [2])
assert gdal.GetLastErrorMsg() == ""
ds = None
ds = gdal.Open(filename)
cs = ds.GetRasterBand(1).Checksum()
cs_ovr = ds.GetRasterBand(1).GetOverview(0).Checksum()
gdal.Unlink(filename)
assert (cs, cs_ovr) == (4672, 1087)
filename2 = "/vsimem/test_tiff_write_185_lerc_create_and_overview_copy.tif"
gdaltest.tiff_drv.CreateCopy(
filename2, ds, options=["COMPRESS=LERC_DEFLATE", "COPY_SRC_OVERVIEWS=YES"]
)
assert gdal.GetLastErrorMsg() == ""
ds = gdal.Open(filename2)
cs = ds.GetRasterBand(1).Checksum()
cs_ovr = ds.GetRasterBand(1).GetOverview(0).Checksum()
gdal.Unlink(filename2)
assert (cs, cs_ovr) == (4672, 1087)
###############################################################################
def check_libtiff_internal_or_at_least(expected_maj, expected_min, expected_micro):
md = gdal.GetDriverByName("GTiff").GetMetadata()
if md["LIBTIFF"] == "INTERNAL":
return True
if md["LIBTIFF"].startswith("LIBTIFF, Version "):
version = md["LIBTIFF"][len("LIBTIFF, Version ") :]
version = version[0 : version.find("\n")]
got_maj, got_min, got_micro = version.split(".")
got_maj = int(got_maj)
got_min = int(got_min)
got_micro = int(got_micro)
if got_maj > expected_maj:
return True
if got_maj < expected_maj:
return False
if got_min > expected_min:
return True
if got_min < expected_min:
return False
return got_micro >= expected_micro
return False
###############################################################################
# Test writing a deflate compressed file with a uncompressed strip larger than 4 GB
#
@pytest.mark.slow()
def test_tiff_write_deflate_4GB():
if not check_libtiff_internal_or_at_least(4, 0, 11):
pytest.skip()
ref_ds = gdal.GetDriverByName("MEM").Create("", 20, 20)
ref_ds.GetRasterBand(1).Fill(127)
gdal.Translate(
"/vsimem/out.tif",
ref_ds,
options="-co TILED=YES -co COMPRESS=DEFLATE -co BLOCKXSIZE=50000 -co BLOCKYSIZE=86000 -outsize 50000 86000",
)
ds = gdal.Open("/vsimem/out.tif")
data = ds.ReadRaster(
0, 0, ds.RasterXSize, ds.RasterYSize, buf_xsize=20, buf_ysize=20
)
assert data == ref_ds.ReadRaster()
ds = None
gdal.Unlink("/vsimem/out.tif")
###############################################################################
# Test rewriting a LZW strip/tile that is very close to 8 KB with larger data
def test_tiff_write_rewrite_lzw_strip():
if not check_libtiff_internal_or_at_least(4, 0, 11):
pytest.skip()
src_data = open("data/bug_gh_1439_to_be_updated_lzw.tif", "rb").read()
tmpfilename = "/vsimem/out.tif"
gdal.FileFromMemBuffer(tmpfilename, src_data)
ds = gdal.Open(tmpfilename, gdal.GA_Update)
src_ds = gdal.Open("data/bug_gh_1439_update_lzw.tif")
ds.WriteRaster(0, 0, 4096, 1, src_ds.ReadRaster())
ds = None
ds = gdal.Open(tmpfilename)
gdal.ErrorReset()
assert ds.GetRasterBand(1).ReadRaster(0, 1, 4096, 1)
assert gdal.GetLastErrorMsg() == ""
gdal.Unlink(tmpfilename)
###############################################################################
# Test COPY_SRC_OVERVIEWS on a configuration with overviews, mask, but no
# overview on the mask
def test_tiff_write_overviews_mask_no_ovr_on_mask():
tmpfile = "/vsimem/test_tiff_write_overviews_mask_no_ovr_on_mask.tif"
with gdaltest.config_option("GDAL_TIFF_INTERNAL_MASK", "YES"):
ds = gdaltest.tiff_drv.Create(tmpfile, 100, 100)
ds.GetRasterBand(1).Fill(255)
ds.CreateMaskBand(gdal.GMF_PER_DATASET)
ds = gdal.Open(tmpfile)
gdal.ErrorReset()
with gdaltest.error_handler():
ds.BuildOverviews("NEAR", overviewlist=[2])
assert (
"Building external overviews whereas there is an internal mask is not fully supported. The overviews of the non-mask bands will be created, but not the overviews of the mask band."
in gdal.GetLastErrorMsg()
)
# No overview on the mask
assert ds.GetRasterBand(1).GetOverview(0).GetMaskFlags() == gdal.GMF_ALL_VALID
ds = None
tmpfile2 = "/vsimem/test_tiff_write_overviews_mask_no_ovr_on_mask_copy.tif"
src_ds = gdal.Open(tmpfile)
gdal.ErrorReset()
with gdaltest.error_handler():
ds = gdaltest.tiff_drv.CreateCopy(
tmpfile2, src_ds, options=["COPY_SRC_OVERVIEWS=YES"]
)
assert (
"Source dataset has a mask band on full resolution, overviews on the regular bands, but lacks overviews on the mask band."
in gdal.GetLastErrorMsg()
)
assert ds
ds = None
src_ds = None
ds = gdal.Open(tmpfile)
assert ds.GetRasterBand(1).GetMaskFlags() == gdal.GMF_PER_DATASET
# No overview on the mask
assert ds.GetRasterBand(1).GetOverview(0).GetMaskFlags() == gdal.GMF_ALL_VALID
ds = None
gdaltest.tiff_drv.Delete(tmpfile)
gdaltest.tiff_drv.Delete(tmpfile2)
###############################################################################
# Test that -co PHOTOMETRIC=YCBCR -co COMPRESS=JPEG does not create a TIFFTAG_GDAL_METADATA
@pytest.mark.require_creation_option("GTiff", "JPEG")
def test_tiff_write_no_gdal_metadata_tag_for_ycbcr_jpeg():
tmpfile = "/vsimem/test_tiff_write_no_gdal_metadata_tag_for_ycbcr_jpeg.tif"
assert gdaltest.tiff_drv.Create(
tmpfile,
16,
16,
3,
gdal.GDT_Byte,
options=["PHOTOMETRIC=YCBCR", "COMPRESS=JPEG"],
)
statBuf = gdal.VSIStatL(
tmpfile + ".aux.xml",
gdal.VSI_STAT_EXISTS_FLAG | gdal.VSI_STAT_NATURE_FLAG | gdal.VSI_STAT_SIZE_FLAG,
)
assert statBuf is None, "did not expect PAM file"
ds = gdal.Open(tmpfile)
assert (
ds.GetMetadataItem("TIFFTAG_GDAL_METADATA", "_DEBUG_") is None
), "did not expect TIFFTAG_GDAL_METADATA tag"
assert ds.GetRasterBand(1).GetColorInterpretation() == gdal.GCI_RedBand
tmpfile2 = tmpfile + "2"
assert gdaltest.tiff_drv.CreateCopy(
tmpfile2, ds, options=["PHOTOMETRIC=YCBCR", "COMPRESS=JPEG"]
)
ds = None
ds = gdal.Open(tmpfile2)
assert (
ds.GetMetadataItem("TIFFTAG_GDAL_METADATA", "_DEBUG_") is None
), "did not expect TIFFTAG_GDAL_METADATA tag"
assert ds.GetRasterBand(1).GetColorInterpretation() == gdal.GCI_RedBand
ds = None
gdaltest.tiff_drv.Delete(tmpfile)
gdaltest.tiff_drv.Delete(tmpfile2)
###############################################################################
# Test that repated flushing after SetGeoTransform() does not grow file size
# indefinitely
def test_tiff_write_setgeotransform_flush():
tmpfile = "/vsimem/test_tiff_write_setgeotransform_flush.tif"
gdal.GetDriverByName("GTiff").Create(tmpfile, 1, 1)
ds = gdal.Open(tmpfile, gdal.GA_Update)
ds.SetGeoTransform([2, 0, 1, 49, 0, -1])
for i in range(10):
ds.FlushCache()
ds = None
assert gdal.VSIStatL(tmpfile).size < 1000
gdaltest.tiff_drv.Delete(tmpfile)
###############################################################################
# Test that compression parameters are taken into account in Create() mode
def test_tiff_write_compression_create_and_createcopy():
md = gdaltest.tiff_drv.GetMetadata()
tests = []
if "DEFLATE" in md["DMD_CREATIONOPTIONLIST"]:
tests.append(
(["COMPRESS=DEFLATE", "ZLEVEL=1"], ["COMPRESS=DEFLATE", "ZLEVEL=9"])
)
if "LZMA" in md["DMD_CREATIONOPTIONLIST"]:
tests.append(
(["COMPRESS=LZMA", "LZMA_PRESET=1"], ["COMPRESS=LZMA", "LZMA_PRESET=9"])
)
if "JPEG" in md["DMD_CREATIONOPTIONLIST"]:
tests.append(
(["COMPRESS=JPEG", "JPEG_QUALITY=95"], ["COMPRESS=JPEG", "JPEG_QUALITY=50"])
)
if "ZSTD" in md["DMD_CREATIONOPTIONLIST"]:
tests.append(
(["COMPRESS=ZSTD", "ZSTD_LEVEL=1"], ["COMPRESS=ZSTD", "ZSTD_LEVEL=9"])
)
# FIXME: this test randomly fails, especially on Windows, but also on Linux,
# for a unknown reason. Nothing suspicious with Valgrind however
# if 'LERC_DEFLATE' in md['DMD_CREATIONOPTIONLIST']:
# tests.append((['COMPRESS=LERC_DEFLATE', 'ZLEVEL=1'],['COMPRESS=LERC_DEFLATE', 'ZLEVEL=9']))
if "WEBP" in md["DMD_CREATIONOPTIONLIST"]:
tests.append(
(["COMPRESS=WEBP", "WEBP_LEVEL=95"], ["COMPRESS=WEBP", "WEBP_LEVEL=15"])
)
if "JXL" in md["DMD_CREATIONOPTIONLIST"]:
tests.append(
(["COMPRESS=JXL", "JXL_LOSSLESS=YES"], ["COMPRESS=JXL", "JXL_LOSSLESS=NO"])
)
tests.append(
(
["COMPRESS=JXL", "JXL_LOSSLESS=YES", "JXL_EFFORT=3"],
["COMPRESS=JXL", "JXL_LOSSLESS=YES", "JXL_EFFORT=9"],
)
)
tests.append(
(
["COMPRESS=JXL", "JXL_LOSSLESS=NO", "JXL_DISTANCE=0.1"],
["COMPRESS=JXL", "JXL_LOSSLESS=NO", "JXL_DISTANCE=3"],
)
)
new_tests = []
for (before, after) in tests:
new_tests.append((before, after))
new_tests.append(
(
before + ["COPY_SRC_OVERVIEWS=YES", "TILED=YES", "NUM_THREADS=2"],
after + ["COPY_SRC_OVERVIEWS=YES", "TILED=YES", "NUM_THREADS=2"],
)
)
tests = new_tests
tmpfile = "/vsimem/test_tiff_write_compression_create.tif"
src_ds = gdal.Open("data/rgbsmall.tif")
data = src_ds.ReadRaster()
for (before, after) in tests:
ds = gdaltest.tiff_drv.Create(
tmpfile,
src_ds.RasterXSize,
src_ds.RasterYSize,
src_ds.RasterCount,
options=before,
)
ds.WriteRaster(0, 0, src_ds.RasterXSize, src_ds.RasterYSize, data)
ds = None
size_before = gdal.VSIStatL(tmpfile).size
ds = gdaltest.tiff_drv.Create(
tmpfile,
src_ds.RasterXSize,
src_ds.RasterYSize,
src_ds.RasterCount,
options=after,
)
ds.WriteRaster(0, 0, src_ds.RasterXSize, src_ds.RasterYSize, data)
ds = None
size_after = gdal.VSIStatL(tmpfile).size
assert size_after < size_before, (before, after, size_before, size_after)
print(before, after, size_before, size_after)
gdaltest.tiff_drv.CreateCopy(tmpfile, src_ds, options=before)
size_before = gdal.VSIStatL(tmpfile).size
gdaltest.tiff_drv.CreateCopy(tmpfile, src_ds, options=after)
size_after = gdal.VSIStatL(tmpfile).size
assert size_after < size_before, (before, after, size_before, size_after)
gdaltest.tiff_drv.Delete(tmpfile)
###############################################################################
# Attempt at creating a file with more tile arrays larger than 2 GB
def test_tiff_write_too_many_tiles():
src_ds = gdal.Open(
'<VRTDataset rasterXSize="40000000" rasterYSize="40000000"><VRTRasterBand dataType="Byte" band="1"/></VRTDataset>'
)
with gdaltest.error_handler():
assert not gdaltest.tiff_drv.CreateCopy(
"/vsimem/tmp.tif", src_ds, options=["TILED=YES"]
)
assert "File too large regarding tile size" in gdal.GetLastErrorMsg()
with gdaltest.tempfile(
"/vsimem/test_tiff_write_too_many_tiles.vrt",
'<VRTDataset rasterXSize="40000000" rasterYSize="40000000"><VRTRasterBand dataType="Byte" band="1"/></VRTDataset>',
):
src_ds = gdal.Open("/vsimem/test_tiff_write_too_many_tiles.vrt")
gdal.ErrorReset()
with gdaltest.config_option("GDAL_TIFF_OVR_BLOCKSIZE", "128"):
with gdaltest.error_handler():
src_ds.BuildOverviews("NEAR", [2])
assert "File too large regarding tile size" in gdal.GetLastErrorMsg()
###############################################################################
#
@pytest.mark.require_creation_option("GTiff", "JPEG")
def test_tiff_write_jpeg_incompatible_of_paletted():
src_ds = gdal.Open("data/test_average_palette.tif")
with gdaltest.error_handler():
assert not gdaltest.tiff_drv.CreateCopy(
"/vsimem/tmp.tif", src_ds, options=["COMPRESS=JPEG"]
)
gdal.Unlink("/vsimem/tmp.tif")
###############################################################################
# Test blocksize overriding while creating (internal) overviews
# on a newly created dataset
@pytest.mark.parametrize("blockSize,numThreads", [[64, None], [256, 8]])
def test_tiff_write_internal_ovr_blocksize(blockSize, numThreads):
src_ds = gdal.Open("../gdrivers/data/utm.tif")
fname = "tmp/tiff_write_internal_ovr_bs%d.tif" % blockSize
ds = gdal.GetDriverByName("GTiff").Create(
fname,
1024,
1024,
1,
options=["TILED=YES", "COMPRESS=LZW", "BLOCKXSIZE=512", "BLOCKYSIZE=512"],
)
data = src_ds.GetRasterBand(1).ReadRaster(0, 0, 512, 512, 1024, 1024)
ds.GetRasterBand(1).WriteRaster(0, 0, 1024, 1024, data)
opts = {"GDAL_TIFF_OVR_BLOCKSIZE": "%d" % blockSize}
if numThreads:
opts["GDAL_NUM_THREADS"] = str(numThreads)
with gdaltest.config_options(opts):
ds.BuildOverviews("AVERAGE", overviewlist=[2])
src_ds = None
ds = None
ds = gdal.Open(fname)
(bsx, bsy) = ds.GetRasterBand(1).GetOverview(0).GetBlockSize()
assert bsx == blockSize
assert bsy == blockSize
ds = None
gdaltest.tiff_drv.Delete(fname)
###############################################################################
# Test blocksize propagation while creating (internal) overviews
# on a newly created dataset
@pytest.mark.parametrize("blockSize,numThreads", [[64, None], [256, 8]])
def test_tiff_write_internal_ovr_default_blocksize(blockSize, numThreads):
src_ds = gdal.Open("../gdrivers/data/utm.tif")
fname = "tmp/tiff_write_internal_ovr_default_bs%d.tif" % blockSize
ds = gdal.GetDriverByName("GTiff").Create(
fname,
1024,
1024,
1,
options=[
"TILED=YES",
"COMPRESS=LZW",
"BLOCKXSIZE=%d" % blockSize,
"BLOCKYSIZE=%d" % blockSize,
],
)
data = src_ds.GetRasterBand(1).ReadRaster(0, 0, 512, 512, 1024, 1024)
ds.GetRasterBand(1).WriteRaster(0, 0, 1024, 1024, data)
opts = {}
if numThreads:
opts["GDAL_NUM_THREADS"] = str(numThreads)
with gdaltest.config_options(opts):
ds.BuildOverviews("AVERAGE", overviewlist=[2])
src_ds = None
ds = None
ds = gdal.Open(fname)
(bsx, bsy) = ds.GetRasterBand(1).GetOverview(0).GetBlockSize()
assert bsx == blockSize
assert bsy == blockSize
ds = None
gdaltest.tiff_drv.Delete(fname)
###############################################################################
# Test LERC compression with Float32/Float64
@pytest.mark.parametrize(
"gdalDataType,structType", [[gdal.GDT_Float32, "f"], [gdal.GDT_Float64, "d"]]
)
@pytest.mark.require_creation_option("GTiff", "LERC")
def test_tiff_write_lerc_float(gdalDataType, structType):
src_ds = gdal.GetDriverByName("MEM").Create("", 2, 1, 1, gdalDataType)
src_ds.GetRasterBand(1).WriteRaster(
0, 0, 2, 1, struct.pack(structType * 2, 0.5, 1.5)
)
filename = "/vsimem/test.tif"
gdaltest.tiff_drv.CreateCopy(filename, src_ds, options=["COMPRESS=LERC"])
ds = gdal.Open(filename)
assert struct.unpack(structType * 2, ds.ReadRaster()) == (0.5, 1.5)
ds = None
gdal.Unlink(filename)
###############################################################################
# Test LERC compression withFloat32/Float64 and nan
@pytest.mark.parametrize(
"gdalDataType,structType", [[gdal.GDT_Float32, "f"], [gdal.GDT_Float64, "d"]]
)
@pytest.mark.require_creation_option("GTiff", "LERC")
def test_tiff_write_lerc_float_with_nan(gdalDataType, structType):
src_ds = gdal.GetDriverByName("MEM").Create("", 2, 1, 1, gdalDataType)
src_ds.GetRasterBand(1).WriteRaster(
0, 0, 2, 1, struct.pack(structType * 2, 0.5, float("nan"))
)
filename = "/vsimem/test.tif"
gdaltest.tiff_drv.CreateCopy(filename, src_ds, options=["COMPRESS=LERC"])
ds = gdal.Open(filename)
got_data = struct.unpack(structType * 2, ds.ReadRaster())
assert got_data[0] == 0.5
assert math.isnan(got_data[1])
ds = None
gdal.Unlink(filename)
###############################################################################
# Test JXL compression
@pytest.mark.parametrize("lossless", ["YES", "NO", None])
@pytest.mark.parametrize("writeImageStructureMetadata", [True, False])
@pytest.mark.require_creation_option("GTiff", "JXL")
def test_tiff_write_jpegxl_byte_single_band(lossless, writeImageStructureMetadata):
outfile = "/vsimem/test_tiff_write_jpegxl_byte_single_band.tif"
options = ["COMPRESS=JXL"]
if lossless:
options += ["JXL_LOSSLESS=" + lossless]
if lossless == "NO":
options += ["JXL_DISTANCE=0.5", "JXL_EFFORT=4"]
with gdaltest.config_option(
"GTIFF_WRITE_IMAGE_STRUCTURE_METADATA",
"YES" if writeImageStructureMetadata else "NO",
):
gdaltest.tiff_drv.CreateCopy(
outfile, gdal.Open("data/byte.tif"), options=options
)
ds = gdal.Open(outfile)
if writeImageStructureMetadata:
assert ds.GetMetadataItem("JXL_LOSSLESS", "_DEBUG_") == (
"0" if lossless == "NO" else "1"
)
if lossless == "NO":
assert float(ds.GetMetadataItem("JXL_DISTANCE", "_DEBUG_")) == 0.5
assert ds.GetMetadataItem("JXL_EFFORT", "_DEBUG_") == "4"
else:
# Default values
assert ds.GetMetadataItem("JXL_LOSSLESS", "_DEBUG_") == "1"
assert float(ds.GetMetadataItem("JXL_DISTANCE", "_DEBUG_")) == 1.0
assert ds.GetMetadataItem("JXL_EFFORT", "_DEBUG_") == "5"
if writeImageStructureMetadata:
assert ds.GetMetadataItem("COMPRESSION_REVERSIBILITY", "IMAGE_STRUCTURE") == (
"LOSSY" if lossless == "NO" else "LOSSLESS"
)
elif gdal.GetDriverByName("JPEGXL") is not None:
assert ds.GetMetadataItem("COMPRESSION_REVERSIBILITY", "IMAGE_STRUCTURE") == (
"LOSSY" if lossless == "NO" else "LOSSLESS (possibly)"
)
cs = ds.GetRasterBand(1).Checksum()
if lossless == "NO":
assert cs != 0 and cs != 4672
else:
assert cs == 4672
ds = None
ds = gdal.Open(outfile, gdal.GA_Update)
if writeImageStructureMetadata:
assert ds.GetMetadataItem("JXL_LOSSLESS", "_DEBUG_") == (
"0" if lossless == "NO" else "1"
)
if writeImageStructureMetadata:
assert ds.GetMetadataItem("COMPRESSION_REVERSIBILITY", "IMAGE_STRUCTURE") == (
"LOSSY" if lossless == "NO" else "LOSSLESS"
)
elif gdal.GetDriverByName("JPEGXL") is not None:
assert ds.GetMetadataItem("COMPRESSION_REVERSIBILITY", "IMAGE_STRUCTURE") == (
"LOSSY" if lossless == "NO" else "LOSSLESS (possibly)"
)
ds = None
gdaltest.tiff_drv.Delete(outfile)
###############################################################################
# Test JXL compression
@pytest.mark.require_creation_option("GTiff", "JXL")
def test_tiff_write_jpegxl_byte_three_band():
ut = gdaltest.GDALTest("GTiff", "rgbsmall.tif", 1, 21212, options=["COMPRESS=JXL"])
return ut.testCreateCopy()
###############################################################################
# Test JXL compression
@pytest.mark.require_creation_option("GTiff", "JXL")
def test_tiff_write_jpegxl_uint16_single_band():
ut = gdaltest.GDALTest("GTiff", "uint16.tif", 1, 4672, options=["COMPRESS=JXL"])
return ut.testCreateCopy()
###############################################################################
# Test JXL_ALPHA_DISTANCE option
@pytest.mark.require_creation_option("GTiff", "JXL_ALPHA_DISTANCE")
def test_tiff_write_jpegxl_alpha_distance_zero():
drv = gdal.GetDriverByName("GTiff")
src_ds = gdal.Open("data/stefan_full_rgba.tif")
filename = "/vsimem/test_tiff_write_jpegxl_alpha_distance_zero.tif"
drv.CreateCopy(
filename,
src_ds,
options=["COMPRESS=JXL", "JXL_LOSSLESS=NO", "JXL_ALPHA_DISTANCE=0"],
)
ds = gdal.Open(filename)
assert float(ds.GetMetadataItem("JXL_ALPHA_DISTANCE", "IMAGE_STRUCTURE")) == 0
assert ds.GetRasterBand(1).Checksum() != src_ds.GetRasterBand(1).Checksum()
assert ds.GetRasterBand(4).Checksum() == src_ds.GetRasterBand(4).Checksum()
ds = None
gdal.Unlink(filename)
###############################################################################
# Test creating overviews with NaN nodata
def test_tiff_write_overviews_nan_nodata():
filename = "/vsimem/test_tiff_write_overviews_nan_nodata.tif"
ds = gdal.GetDriverByName("GTiff").Create(
filename, 32, 32, 1, gdal.GDT_Float32, options=["TILED=YES", "SPARSE_OK=YES"]
)
ds.GetRasterBand(1).SetNoDataValue(float("nan"))
ds.BuildOverviews("NONE", [2, 4])
ds = None
ds = gdal.Open(filename)
assert ds.GetRasterBand(1).GetOverviewCount() == 2
ds = None
gdal.Unlink(filename)
###############################################################################
# Test support for coordinate epoch
def test_tiff_write_coordinate_epoch():
ds = gdal.GetDriverByName("GTiff").Create(
"/vsimem/test_tiff_write_coordinate_epoch.tif", 1, 1
)
srs = osr.SpatialReference()
srs.ImportFromEPSG(4326)
srs.SetCoordinateEpoch(2021.3)
ds.SetGeoTransform([0, 1, 0, 0, 0, -1])
ds.SetSpatialRef(srs)
ds = None
ds = gdal.Open("/vsimem/test_tiff_write_coordinate_epoch.tif")
srs = ds.GetSpatialRef()
assert srs.GetCoordinateEpoch() == 2021.3
ds = None
gdal.Unlink("/vsimem/test_tiff_write_coordinate_epoch.tif")
###############################################################################
# Test scenario with multiple IFDs and directory rewriting
# https://github.com/OSGeo/gdal/issues/3746
@pytest.mark.parametrize("reopen", [True, False])
def test_tiff_write_multiple_ifds_directory_rewriting(reopen):
filename = "/vsimem/out.tif"
ds = gdal.GetDriverByName("GTiff").Create(
filename, 32, 32, options=["TILED=YES", "SPARSE_OK=YES"]
)
ds.BuildOverviews("NONE", [2])
if reopen:
ds = None
ds = gdal.Open(filename, gdal.GA_Update)
ds.GetRasterBand(1).GetOverview(0).Fill(2)
# Rewrite second IFD
ds.GetRasterBand(1).GetOverview(0).SetNoDataValue(0)
# Rewrite first IFD
ds.GetRasterBand(1).SetNoDataValue(3)
ds = None
ds = gdal.Open(filename)
mm = ds.GetRasterBand(1).GetOverview(0).ComputeRasterMinMax()
ds = None
gdal.Unlink(filename)
assert mm == (2, 2)
###############################################################################
# Test SetSpatialRef() on a read-only dataset
def test_tiff_write_setspatialref_read_only():
filename = "/vsimem/out.tif"
gdal.GetDriverByName("GTiff").Create(filename, 1, 1)
ds = gdal.Open(filename)
srs = osr.SpatialReference()
srs.ImportFromEPSG(4326)
assert ds.SetSpatialRef(srs) == gdal.CE_None
ds = None
assert gdal.VSIStatL(filename + ".aux.xml") is not None
ds = gdal.Open(filename)
got_srs = ds.GetSpatialRef()
assert got_srs
assert got_srs.GetAuthorityCode(None) == "4326"
ds = None
gdal.GetDriverByName("GTiff").Delete(filename)
###############################################################################
# Test SetSpatialRef() on a read-only dataset, overriding TIFF tags
def test_tiff_write_setspatialref_read_only_override_tifftags():
filename = "/vsimem/out.tif"
ds = gdal.GetDriverByName("GTiff").Create(filename, 1, 1)
srs = osr.SpatialReference()
srs.ImportFromEPSG(32631)
assert ds.SetSpatialRef(srs) == gdal.CE_None
ds = None
ds = gdal.Open(filename)
srs = osr.SpatialReference()
srs.ImportFromEPSG(4326)
assert ds.SetSpatialRef(srs) == gdal.CE_None
ds = None
assert gdal.VSIStatL(filename + ".aux.xml") is not None
ds = gdal.Open(filename)
got_srs = ds.GetSpatialRef()
assert got_srs
assert got_srs.GetAuthorityCode(None) == "4326"
ds = None
ds = gdal.Open(filename, gdal.GA_Update)
srs = osr.SpatialReference()
srs.ImportFromEPSG(32632)
assert ds.SetSpatialRef(srs) == gdal.CE_None
ds = None
assert gdal.VSIStatL(filename + ".aux.xml") is None
ds = gdal.Open(filename)
got_srs = ds.GetSpatialRef()
assert got_srs
assert got_srs.GetAuthorityCode(None) == "32632"
ds = None
gdal.GetDriverByName("GTiff").Delete(filename)
###############################################################################
# Test SetGeoTransform() on a read-only dataset
def test_tiff_write_setgeotransform_read_only():
filename = "/vsimem/out.tif"
gdal.GetDriverByName("GTiff").Create(filename, 1, 1)
ds = gdal.Open(filename)
gt = [2, 1, 0, 49, 0, -1]
assert ds.SetGeoTransform(gt) == gdal.CE_None
ds = None
assert gdal.VSIStatL(filename + ".aux.xml") is not None
ds = gdal.Open(filename)
got_gt = [x for x in ds.GetGeoTransform()]
assert got_gt == gt
ds = None
gdal.GetDriverByName("GTiff").Delete(filename)
###############################################################################
# Test SetGeoTransform() on a read-only dataset, overriding TIFF tags
def test_tiff_write_setgeotransform_read_only_override_tifftags():
filename = "/vsimem/out.tif"
ds = gdal.GetDriverByName("GTiff").Create(filename, 1, 1)
assert ds.SetGeoTransform([3, 1, 0, 50, 0, -1]) == gdal.CE_None
ds = None
ds = gdal.Open(filename)
gt = [2, 1, 0, 49, 0, -1]
assert ds.SetGeoTransform(gt) == gdal.CE_None
ds = None
assert gdal.VSIStatL(filename + ".aux.xml") is not None
ds = gdal.Open(filename)
got_gt = [x for x in ds.GetGeoTransform()]
assert got_gt == gt
ds = None
ds = gdal.Open(filename, gdal.GA_Update)
gt = [4, 1, 0, 51, 0, -1]
assert ds.SetGeoTransform(gt) == gdal.CE_None
ds = None
assert gdal.VSIStatL(filename + ".aux.xml") is None
ds = gdal.Open(filename)
got_gt = [x for x in ds.GetGeoTransform()]
assert got_gt == gt
ds = None
gdal.GetDriverByName("GTiff").Delete(filename)
###############################################################################
# Test SetGCPs() on a read-only dataset
def test_tiff_write_setgcps_read_only():
filename = "/vsimem/out.tif"
gdal.GetDriverByName("GTiff").Create(filename, 1, 1)
ds = gdal.Open(filename)
gcps = [gdal.GCP(0, 1, 2, 3, 4)]
srs = osr.SpatialReference()
srs.ImportFromEPSG(4326)
assert ds.SetGCPs(gcps, srs) == gdal.CE_None
ds = None
assert gdal.VSIStatL(filename + ".aux.xml") is not None
ds = gdal.Open(filename)
got_gcps = ds.GetGCPs()
assert len(got_gcps) == len(gcps)
assert got_gcps[0].GCPPixel == gcps[0].GCPPixel
assert got_gcps[0].GCPLine == gcps[0].GCPLine
assert got_gcps[0].GCPX == gcps[0].GCPX
assert got_gcps[0].GCPY == gcps[0].GCPY
got_srs = ds.GetGCPSpatialRef()
assert got_srs
assert got_srs.GetAuthorityCode(None) == "4326"
ds = None
gdal.GetDriverByName("GTiff").Delete(filename)
###############################################################################
# Test SetGCPs() on a read-only dataset, overriding TIFF tags
def test_tiff_write_setgcps_read_only_override_tifftags():
filename = "/vsimem/out.tif"
ds = gdal.GetDriverByName("GTiff").Create(filename, 1, 1)
gcps = [gdal.GCP(5, 6, 7, 8, 9)]
assert ds.SetGCPs(gcps, None) == gdal.CE_None
ds = None
ds = gdal.Open(filename)
gcps = [gdal.GCP(0, 1, 2, 3, 4)]
srs = osr.SpatialReference()
srs.ImportFromEPSG(4326)
assert ds.SetGCPs(gcps, srs) == gdal.CE_None
ds = None
assert gdal.VSIStatL(filename + ".aux.xml") is not None
ds = gdal.Open(filename)
got_gcps = ds.GetGCPs()
assert len(got_gcps) == len(gcps)
assert got_gcps[0].GCPPixel == gcps[0].GCPPixel
assert got_gcps[0].GCPLine == gcps[0].GCPLine
assert got_gcps[0].GCPX == gcps[0].GCPX
assert got_gcps[0].GCPY == gcps[0].GCPY
got_srs = ds.GetGCPSpatialRef()
assert got_srs
assert got_srs.GetAuthorityCode(None) == "4326"
ds = None
ds = gdal.Open(filename, gdal.GA_Update)
gcps = [gdal.GCP(10, 11, 12, 13, 14)]
assert ds.SetGCPs(gcps, None) == gdal.CE_None
ds = None
assert gdal.VSIStatL(filename + ".aux.xml") is None
ds = gdal.Open(filename)
got_gcps = ds.GetGCPs()
assert len(got_gcps) == len(gcps)
assert got_gcps[0].GCPPixel == gcps[0].GCPPixel
assert got_gcps[0].GCPLine == gcps[0].GCPLine
assert got_gcps[0].GCPX == gcps[0].GCPX
assert got_gcps[0].GCPY == gcps[0].GCPY
assert ds.GetGCPSpatialRef() is None
ds = None
gdal.GetDriverByName("GTiff").Delete(filename)
###############################################################################
# Test SetNoDataValue() and DeleteNoDataValue() on a read-only dataset
def test_tiff_write_nodata_read_only():
filename = "/vsimem/out.tif"
gdal.GetDriverByName("GTiff").Create(filename, 1, 1)
ds = gdal.Open(filename)
assert ds.GetRasterBand(1).SetNoDataValue(123) == gdal.CE_None
ds = None
assert gdal.VSIStatL(filename + ".aux.xml") is not None
ds = gdal.Open(filename)
assert ds.GetRasterBand(1).GetNoDataValue() == 123
assert ds.GetRasterBand(1).DeleteNoDataValue() == gdal.CE_None
ds = None
ds = gdal.Open(filename)
assert ds.GetRasterBand(1).GetNoDataValue() is None
ds = None
gdal.GetDriverByName("GTiff").Delete(filename)
###############################################################################
# Test SetNoDataValue() on a read-only dataset, overriding TIFF tags
def test_tiff_write_nodata_read_only_overriding_tifftags():
filename = "/vsimem/out.tif"
ds = gdal.GetDriverByName("GTiff").Create(filename, 1, 1)
assert ds.GetRasterBand(1).SetNoDataValue(0) == gdal.CE_None
ds = None
ds = gdal.Open(filename)
assert ds.GetRasterBand(1).SetNoDataValue(123) == gdal.CE_None
ds = None
assert gdal.VSIStatL(filename + ".aux.xml") is not None
ds = gdal.Open(filename)
assert ds.GetRasterBand(1).GetNoDataValue() == 123
ds = None
ds = gdal.Open(filename, gdal.GA_Update)
assert ds.GetRasterBand(1).SetNoDataValue(1) == gdal.CE_None
ds = None
ds = gdal.Open(filename)
assert ds.GetRasterBand(1).GetNoDataValue() == 1
ds = None
gdal.GetDriverByName("GTiff").Delete(filename)
###############################################################################
# Test Dataset SetMetadataItem() on a read-only dataset
def test_tiff_write_dataset_setmetadataitem_read_only():
filename = "/vsimem/out.tif"
gdal.GetDriverByName("GTiff").Create(filename, 1, 1)
ds = gdal.Open(filename)
assert ds.SetMetadataItem("FOO", "BAR", "BAZ") == gdal.CE_None
ds = None
assert gdal.VSIStatL(filename + ".aux.xml") is not None
ds = gdal.Open(filename)
assert ds.GetMetadataItem("FOO", "BAZ") == "BAR"
ds = None
gdal.GetDriverByName("GTiff").Delete(filename)
###############################################################################
# Test Dataset SetMetadata() on a read-only dataset
def test_tiff_write_dataset_setmetadata_read_only():
filename = "/vsimem/out.tif"
gdal.GetDriverByName("GTiff").Create(filename, 1, 1)
ds = gdal.Open(filename)
assert ds.SetMetadata({"FOO": "BAR"}, "BAZ") == gdal.CE_None
ds = None
assert gdal.VSIStatL(filename + ".aux.xml") is not None
ds = gdal.Open(filename)
assert ds.GetMetadataItem("FOO", "BAZ") == "BAR"
ds = None
gdal.GetDriverByName("GTiff").Delete(filename)
###############################################################################
# Test Band SetMetadataItem() on a read-only dataset
def test_tiff_write_band_setmetadataitem_read_only():
filename = "/vsimem/out.tif"
gdal.GetDriverByName("GTiff").Create(filename, 1, 1)
ds = gdal.Open(filename)
assert ds.GetRasterBand(1).SetMetadataItem("FOO", "BAR", "BAZ") == gdal.CE_None
ds = None
assert gdal.VSIStatL(filename + ".aux.xml") is not None
ds = gdal.Open(filename)
assert ds.GetRasterBand(1).GetMetadataItem("FOO", "BAZ") == "BAR"
ds = None
gdal.GetDriverByName("GTiff").Delete(filename)
###############################################################################
# Test Band SetMetadata() on a read-only dataset
def test_tiff_write_band_setmetadata_read_only():
filename = "/vsimem/out.tif"
gdal.GetDriverByName("GTiff").Create(filename, 1, 1)
ds = gdal.Open(filename)
assert ds.GetRasterBand(1).SetMetadata({"FOO": "BAR"}, "BAZ") == gdal.CE_None
ds = None
assert gdal.VSIStatL(filename + ".aux.xml") is not None
ds = gdal.Open(filename)
assert ds.GetRasterBand(1).GetMetadataItem("FOO", "BAZ") == "BAR"
ds = None
gdal.GetDriverByName("GTiff").Delete(filename)
###############################################################################
# Test SetColorTable() on a read-only dataset
def test_tiff_write_setcolortable_read_only():
filename = "/vsimem/out.tif"
gdal.GetDriverByName("GTiff").Create(filename, 1, 1)
ds = gdal.Open(filename)
ct = gdal.ColorTable()
ct.SetColorEntry(0, (1, 2, 3, 255))
assert ds.GetRasterBand(1).SetRasterColorTable(ct) == gdal.CE_None
assert ds.GetRasterBand(1).GetColorInterpretation() == gdal.GCI_PaletteIndex
ds = None
assert gdal.VSIStatL(filename + ".aux.xml") is not None
ds = gdal.Open(filename)
ct = ds.GetRasterBand(1).GetRasterColorTable()
assert ct is not None
assert ct.GetColorEntry(0) == (1, 2, 3, 255)
assert ds.GetRasterBand(1).GetColorInterpretation() == gdal.GCI_PaletteIndex
ds = None
gdal.GetDriverByName("GTiff").Delete(filename)
###############################################################################
# Test SetColorTable() on a read-only dataset, overriding TIFF tags
def test_tiff_write_setcolortable_read_only_overriding_tifftags():
filename = "/vsimem/out.tif"
ds = gdal.GetDriverByName("GTiff").Create(filename, 1, 1)
ct = gdal.ColorTable()
ct.SetColorEntry(0, (1, 2, 3, 255))
assert ds.GetRasterBand(1).SetRasterColorTable(ct) == gdal.CE_None
assert ds.GetRasterBand(1).GetColorInterpretation() == gdal.GCI_PaletteIndex
ds = None
ds = gdal.Open(filename)
ct = gdal.ColorTable()
ct.SetColorEntry(0, (4, 5, 6, 255))
assert ds.GetRasterBand(1).SetRasterColorTable(ct) == gdal.CE_None
assert ds.GetRasterBand(1).GetColorInterpretation() == gdal.GCI_PaletteIndex
ds = None
assert gdal.VSIStatL(filename + ".aux.xml") is not None
ds = gdal.Open(filename)
assert ct is not None
assert ct.GetColorEntry(0) == (4, 5, 6, 255)
assert ds.GetRasterBand(1).GetColorInterpretation() == gdal.GCI_PaletteIndex
ds = None
ds = gdal.Open(filename, gdal.GA_Update)
ct = gdal.ColorTable()
ct.SetColorEntry(0, (7, 8, 9, 255))
assert ds.GetRasterBand(1).SetRasterColorTable(ct) == gdal.CE_None
assert ds.GetRasterBand(1).GetColorInterpretation() == gdal.GCI_PaletteIndex
ds = None
assert gdal.VSIStatL(filename + ".aux.xml") is None
ds = gdal.Open(filename)
assert ct is not None
assert ct.GetColorEntry(0) == (7, 8, 9, 255)
assert ds.GetRasterBand(1).GetColorInterpretation() == gdal.GCI_PaletteIndex
ds = None
gdal.GetDriverByName("GTiff").Delete(filename)
###############################################################################
# Test setting incompatible settings for PREDICTOR
@pytest.mark.parametrize(
"dt, options",
[
(gdal.GDT_UInt16, ["PREDICTOR=2", "NBITS=12"]),
(gdal.GDT_UInt32, ["PREDICTOR=3"]),
(gdal.GDT_UInt16, ["PREDICTOR=invalid"]),
],
)
def test_tiff_write_incompatible_predictor(dt, options):
filename = "/vsimem/out.tif"
with gdaltest.error_handler():
assert (
gdal.GetDriverByName("GTiff").Create(
filename, 1, 1, 1, dt, options + ["COMPRESS=LZW"]
)
is None
)
###############################################################################
# Test PREDICTOR=2 with 64 bit samples
def test_tiff_write_predictor_2_float64():
md = gdal.GetDriverByName("GTiff").GetMetadata()
if md["LIBTIFF"] != "INTERNAL":
pytest.skip("libtiff > 4.3.0 or internal libtiff needed")
filename = "/vsimem/out.tif"
ds = gdal.GetDriverByName("GTiff").Create(
filename, 2, 1, 1, gdal.GDT_Float64, ["COMPRESS=LZW", "PREDICTOR=2"]
)
data = struct.pack("d" * 2, 1, 2)
ds.GetRasterBand(1).WriteRaster(0, 0, 2, 1, data)
ds = None
ds = gdal.Open(filename)
assert ds.GetMetadataItem("PREDICTOR", "IMAGE_STRUCTURE") == "2"
assert ds.ReadRaster() == data
ds = None
gdal.Unlink(filename)
###############################################################################
def test_tiff_write_uint64():
ut = gdaltest.GDALTest("GTiff", "gtiff/uint64_full_range.tif", 1, 1)
return ut.testCreateCopy()
###############################################################################
def test_tiff_write_uint64_nodata():
filename = "/vsimem/test_tiff_write_uint64_nodata.tif"
ds = gdal.GetDriverByName("GTiff").Create(filename, 1, 1, 1, gdal.GDT_UInt64)
val = (1 << 64) - 1
assert ds.GetRasterBand(1).SetNoDataValue(val) == gdal.CE_None
ds = None
filename_copy = "/vsimem/test_tiff_write_uint64_nodata_filename_copy.tif"
ds = gdal.Open(filename)
assert ds.GetRasterBand(1).GetNoDataValue() == val
ds = gdal.GetDriverByName("GTiff").CreateCopy(filename_copy, ds)
ds = None
ds = gdal.Open(filename_copy)
assert ds.GetRasterBand(1).GetNoDataValue() == val
ds = None
gdal.GetDriverByName("GTiff").Delete(filename)
gdal.GetDriverByName("GTiff").Delete(filename_copy)
###############################################################################
def test_tiff_write_int64():
ut = gdaltest.GDALTest("GTiff", "gtiff/int64_full_range.tif", 1, 65535)
return ut.testCreateCopy()
###############################################################################
def test_tiff_write_int64_nodata():
filename = "/vsimem/test_tiff_write_int64_nodata.tif"
ds = gdal.GetDriverByName("GTiff").Create(filename, 1, 1, 1, gdal.GDT_Int64)
val = -(1 << 63)
assert ds.GetRasterBand(1).SetNoDataValue(val) == gdal.CE_None
ds = None
filename_copy = "/vsimem/test_tiff_write_int64_nodata_filename_copy.tif"
ds = gdal.Open(filename)
assert ds.GetRasterBand(1).GetNoDataValue() == val
ds = gdal.GetDriverByName("GTiff").CreateCopy(filename_copy, ds)
ds = None
ds = gdal.Open(filename_copy)
assert ds.GetRasterBand(1).GetNoDataValue() == val
ds = None
gdal.GetDriverByName("GTiff").Delete(filename)
gdal.GetDriverByName("GTiff").Delete(filename_copy)
###############################################################################
# Check IsMaskBand() on an alpha band
def test_tiff_write_alpha_ismaskband():
filename = "/vsimem/out.tif"
ds = gdal.GetDriverByName("GTiff").Create(filename, 1, 1, 2)
ds.GetRasterBand(2).SetColorInterpretation(gdal.GCI_AlphaBand)
assert not ds.GetRasterBand(1).IsMaskBand()
assert ds.GetRasterBand(2).IsMaskBand()
ds = None
gdal.GetDriverByName("GTiff").Delete(filename)
###############################################################################
# Test scenario of https://github.com/OSGeo/gdal/issues/5580
def test_tiff_write_overview_building_and_approx_stats():
filename = "/vsimem/out.tif"
gdal.GetDriverByName("GTiff").Create(filename, 512, 512)
ds = gdal.Open(filename)
ds.BuildOverviews("NEAREST", [2, 4, 8])
ds.GetRasterBand(1).ComputeStatistics(1)
ds = None
gdal.GetDriverByName("GTiff").Delete(filename)
###############################################################################
# Test scenario of https://github.com/OSGeo/gdal/issues/6015
@pytest.mark.parametrize("setmetadata_before", [True, False])
def test_tiff_write_setgeotransform_and_setmetadata(setmetadata_before):
filename = "/vsimem/out.tif"
ds = gdal.GetDriverByName("GTiff").Create(filename, 1, 1)
ds.SetGeoTransform([1, 2, 3, 4, 5, -6])
ds = None
ds = gdal.Open(filename, gdal.GA_Update)
if setmetadata_before:
ds.SetMetadata([])
ds.SetGeoTransform([10, 20, 30, 40, 50, -60])
if not setmetadata_before:
ds.SetMetadata([])
ds = None
ds = gdal.Open(filename)
assert ds.GetGeoTransform() == (10, 20, 30, 40, 50, -60)
ds = None
gdal.GetDriverByName("GTiff").Delete(filename)
@pytest.mark.parametrize("getspatialref_before", [True, False])
def test_tiff_write_setgeotransform_and_getspatialref(getspatialref_before):
filename = "/vsimem/out.tif"
ds = gdal.GetDriverByName("GTiff").Create(filename, 1, 1)
ds.SetGeoTransform([1, 2, 3, 4, 5, -6])
ds = None
ds = gdal.Open(filename, gdal.GA_Update)
if getspatialref_before:
ds.GetSpatialRef()
ds.SetGeoTransform([10, 20, 30, 40, 50, -60])
if not getspatialref_before:
ds.GetSpatialRef()
ds = None
ds = gdal.Open(filename)
assert ds.GetGeoTransform() == (10, 20, 30, 40, 50, -60)
ds = None
gdal.GetDriverByName("GTiff").Delete(filename)
###############################################################################
# Test CreateCopy() on a source dataset that has an alpha band not in last
# band
@pytest.mark.parametrize("options", [["PROFILE=BASELINE"], []])
def test_tiff_write_createcopy_alpha_not_in_last_band(options):
tmpfilename = "/vsimem/test_tiff_write_createcopy_alpha_not_in_last_band.tif"
src_ds = gdal.GetDriverByName("MEM").Create("", 1, 1, 6)
src_ds.GetRasterBand(5).SetColorInterpretation(gdal.GCI_AlphaBand)
# Try with implied MINISBLACK photometric interpretation
gdal.GetDriverByName("GTiff").CreateCopy(tmpfilename, src_ds, options=options)
statBuf = gdal.VSIStatL(
tmpfilename + ".aux.xml",
gdal.VSI_STAT_EXISTS_FLAG | gdal.VSI_STAT_NATURE_FLAG | gdal.VSI_STAT_SIZE_FLAG,
)
assert statBuf is None, "did not expect PAM file"
ds = gdal.Open(tmpfilename)
assert ds.GetMetadataItem("TIFFTAG_EXTRASAMPLES", "_DEBUG_") == "0,0,0,2,0"
assert ds.GetRasterBand(1).GetColorInterpretation() == gdal.GCI_GrayIndex
assert ds.GetRasterBand(2).GetColorInterpretation() == gdal.GCI_Undefined
assert ds.GetRasterBand(3).GetColorInterpretation() == gdal.GCI_Undefined
assert ds.GetRasterBand(4).GetColorInterpretation() == gdal.GCI_Undefined
assert ds.GetRasterBand(5).GetColorInterpretation() == gdal.GCI_AlphaBand
assert ds.GetRasterBand(6).GetColorInterpretation() == gdal.GCI_Undefined
ds = None
# Try with explicit RGB photometric interpretation
gdal.GetDriverByName("GTiff").CreateCopy(
tmpfilename, src_ds, options=["PHOTOMETRIC=RGB"] + options
)
statBuf = gdal.VSIStatL(
tmpfilename + ".aux.xml",
gdal.VSI_STAT_EXISTS_FLAG | gdal.VSI_STAT_NATURE_FLAG | gdal.VSI_STAT_SIZE_FLAG,
)
assert statBuf is None, "did not expect PAM file"
ds = gdal.Open(tmpfilename)
assert ds.GetMetadataItem("TIFFTAG_EXTRASAMPLES", "_DEBUG_") == "0,2,0"
assert ds.GetRasterBand(1).GetColorInterpretation() == gdal.GCI_RedBand
assert ds.GetRasterBand(2).GetColorInterpretation() == gdal.GCI_GreenBand
assert ds.GetRasterBand(3).GetColorInterpretation() == gdal.GCI_BlueBand
assert ds.GetRasterBand(4).GetColorInterpretation() == gdal.GCI_Undefined
assert ds.GetRasterBand(5).GetColorInterpretation() == gdal.GCI_AlphaBand
assert ds.GetRasterBand(6).GetColorInterpretation() == gdal.GCI_Undefined
ds = None
# Try with implied RGB photometric interpretation
src_ds.GetRasterBand(1).SetColorInterpretation(gdal.GCI_RedBand)
src_ds.GetRasterBand(2).SetColorInterpretation(gdal.GCI_GreenBand)
src_ds.GetRasterBand(3).SetColorInterpretation(gdal.GCI_BlueBand)
gdal.GetDriverByName("GTiff").CreateCopy(tmpfilename, src_ds, options=options)
statBuf = gdal.VSIStatL(
tmpfilename + ".aux.xml",
gdal.VSI_STAT_EXISTS_FLAG | gdal.VSI_STAT_NATURE_FLAG | gdal.VSI_STAT_SIZE_FLAG,
)
assert statBuf is None, "did not expect PAM file"
ds = gdal.Open(tmpfilename)
assert ds.GetMetadataItem("TIFFTAG_EXTRASAMPLES", "_DEBUG_") == "0,2,0"
assert ds.GetRasterBand(1).GetColorInterpretation() == gdal.GCI_RedBand
assert ds.GetRasterBand(2).GetColorInterpretation() == gdal.GCI_GreenBand
assert ds.GetRasterBand(3).GetColorInterpretation() == gdal.GCI_BlueBand
assert ds.GetRasterBand(4).GetColorInterpretation() == gdal.GCI_Undefined
assert ds.GetRasterBand(5).GetColorInterpretation() == gdal.GCI_AlphaBand
assert ds.GetRasterBand(6).GetColorInterpretation() == gdal.GCI_Undefined
ds = None
gdal.GetDriverByName("GTiff").Delete(tmpfilename)
###############################################################################
# Test JXL compression
@pytest.mark.require_creation_option("GTiff", "JXL")
def test_tiff_write_jpegxl_band_combinations():
tmpfilename = "/vsimem/test_tiff_write_jpegxl_band_combinations.tif"
src_ds = gdal.GetDriverByName("MEM").Create("", 64, 64, 6)
for b in range(6):
bnd = src_ds.GetRasterBand(b + 1)
bnd.Fill(b + 1)
bnd.FlushCache()
assert bnd.Checksum() != 0, "bnd.Fill failed"
cilists = [
[gdal.GCI_RedBand],
[gdal.GCI_RedBand, gdal.GCI_Undefined],
[gdal.GCI_RedBand, gdal.GCI_AlphaBand],
[gdal.GCI_Undefined, gdal.GCI_AlphaBand],
[gdal.GCI_RedBand, gdal.GCI_GreenBand, gdal.GCI_BlueBand],
[gdal.GCI_RedBand, gdal.GCI_GreenBand, gdal.GCI_BlueBand, gdal.GCI_AlphaBand],
[
gdal.GCI_RedBand,
gdal.GCI_GreenBand,
gdal.GCI_BlueBand,
gdal.GCI_AlphaBand,
gdal.GCI_Undefined,
],
[
gdal.GCI_RedBand,
gdal.GCI_GreenBand,
gdal.GCI_BlueBand,
gdal.GCI_Undefined,
gdal.GCI_Undefined,
],
[
gdal.GCI_RedBand,
gdal.GCI_GreenBand,
gdal.GCI_BlueBand,
gdal.GCI_Undefined,
gdal.GCI_AlphaBand,
],
[
gdal.GCI_RedBand,
gdal.GCI_GreenBand,
gdal.GCI_AlphaBand,
gdal.GCI_Undefined,
gdal.GCI_BlueBand,
],
]
types = [
gdal.GDT_Byte,
gdal.GDT_UInt16,
]
creationOptions = [
["TILED=YES", "COMPRESS=JXL", "INTERLEAVE=BAND"],
["TILED=YES", "COMPRESS=JXL", "INTERLEAVE=PIXEL"],
]
jpegxl_drv = gdal.GetDriverByName("JPEGXL")
for dtype in types:
for copts in creationOptions:
for cilist in cilists:
bandlist = [idx + 1 for idx in range(len(cilist))]
vrtds = gdal.Translate(
"", src_ds, format="vrt", bandList=bandlist, outputType=dtype
)
for idx, ci in enumerate(cilist):
vrtds.GetRasterBand(idx + 1).SetColorInterpretation(ci)
ds = gdal.Translate(tmpfilename, vrtds, creationOptions=copts)
ds = None
# print(dtype, copts, cilist)
ds = gdal.Open(tmpfilename)
for idx in range(len(cilist)):
gdal.ErrorReset()
got_cs = ds.GetRasterBand(idx + 1).Checksum()
assert gdal.GetLastErrorMsg() == ""
assert got_cs == src_ds.GetRasterBand(idx + 1).Checksum(), (
dtype,
copts,
cilist,
idx,
)
# Check that color interpretation inside JXL data is properly encoded
if jpegxl_drv and "INTERLEAVE=PIXEL" in copts:
jxl_offset = ds.GetRasterBand(1).GetMetadataItem(
"BLOCK_OFFSET_0_0", "TIFF"
)
jxl_ds = gdal.Open(
"/vsisubfile/%s_-1,%s" % (jxl_offset, tmpfilename)
)
assert jxl_ds
for idx in range(len(cilist)):
got_cs = jxl_ds.GetRasterBand(idx + 1).Checksum()
assert got_cs == src_ds.GetRasterBand(idx + 1).Checksum(), (
dtype,
copts,
cilist,
idx,
)
if (
vrtds.RasterCount >= 3
and vrtds.GetRasterBand(1).GetColorInterpretation()
== gdal.GCI_RedBand
and vrtds.GetRasterBand(2).GetColorInterpretation()
== gdal.GCI_GreenBand
and vrtds.GetRasterBand(3).GetColorInterpretation()
== gdal.GCI_BlueBand
):
assert (
jxl_ds.GetRasterBand(1).GetColorInterpretation()
== gdal.GCI_RedBand
)
assert (
jxl_ds.GetRasterBand(2).GetColorInterpretation()
== gdal.GCI_GreenBand
)
assert (
jxl_ds.GetRasterBand(3).GetColorInterpretation()
== gdal.GCI_BlueBand
)
# Check that alpha band is preserved
for idx in range(len(cilist)):
if (
vrtds.GetRasterBand(idx + 1).GetColorInterpretation()
== gdal.GCI_AlphaBand
):
assert (
jxl_ds.GetRasterBand(idx + 1).GetColorInterpretation()
== gdal.GCI_AlphaBand
)
vrtds = None
ds = None
gdal.Unlink(tmpfilename)
###############################################################################
# Test turning on lossy WEBP compression if WEBP_LEVEL_OVERVIEW specified
@pytest.mark.require_creation_option("GTiff", "WEBP")
@pytest.mark.require_driver("WEBP")
def test_tiff_write_webp_overview_turn_on_lossy_if_webp_level():
tmpfilename = (
"/vsimem/test_tiff_write_webp_overview_turn_on_lossy_if_webp_level.tif"
)
ds = gdal.Translate(
tmpfilename,
"../gdrivers/data/small_world.tif",
options="-outsize 10 10 -co COMPRESS=WEBP -co WEBP_LOSSLESS=YES",
)
ds.BuildOverviews("NEAR", [2], options=["WEBP_LEVEL=50"])
ds = None
ds = gdal.Open(tmpfilename)
assert (
ds.GetMetadataItem("COMPRESSION_REVERSIBILITY", "IMAGE_STRUCTURE") == "LOSSLESS"
)
assert (
ds.GetRasterBand(1)
.GetOverview(0)
.GetDataset()
.GetMetadataItem("COMPRESSION_REVERSIBILITY", "IMAGE_STRUCTURE")
== "LOSSY"
)
ds = None
gdal.Unlink(tmpfilename)
###############################################################################
# Test lossless extraction of a JPEG compressed tile to JPEG
@pytest.mark.parametrize("extra_options", ["-co PHOTOMETRIC=YCBCR", ""])
@pytest.mark.require_creation_option("GTiff", "JPEG")
@pytest.mark.require_driver("JPEG")
def test_tiff_write_lossless_extraction_of_JPEG_tile(extra_options):
tmpfilename_gtiff = "/vsimem/test_tiff_write_lossless_extraction_of_JPEG_tile.tif"
gdal.Translate(
tmpfilename_gtiff,
"../gdrivers/data/small_world.tif",
options="-co TILED=YES -co BLOCKXSIZE=128 -co BLOCKYSIZE=128 -co COMPRESS=JPEG "
+ extra_options,
)
tmpfilename_jpg = "/vsimem/test_tiff_write_lossless_extraction_of_JPEG_tile.jpg"
gdal.Translate(
tmpfilename_jpg,
tmpfilename_gtiff,
options="-srcwin 0 0 128 128 -co LOSSLESS_COPY=YES",
)
gtiff_ds = gdal.Open(tmpfilename_gtiff)
jpeg_ds = gdal.Open(tmpfilename_jpg)
assert jpeg_ds.ReadRaster() == gtiff_ds.ReadRaster(0, 0, 128, 128)
gdal.Unlink(tmpfilename_gtiff)
gdal.Unlink(tmpfilename_jpg)
gdal.Unlink(tmpfilename_jpg + ".aux.xml")
###############################################################################
# Test lossless extraction of a JPEGXL compressed tile to JPEGXL
@pytest.mark.require_creation_option("GTiff", "JXL")
@pytest.mark.require_driver("JPEGXL")
def test_tiff_write_lossless_extraction_of_JPEGXL_tile():
tmpfilename_gtiff = "/vsimem/test_tiff_write_lossless_extraction_of_JPEGXL_tile.tif"
gdal.Translate(
tmpfilename_gtiff,
"../gdrivers/data/small_world.tif",
options="-co TILED=YES -co BLOCKXSIZE=128 -co BLOCKYSIZE=128 -co COMPRESS=JXL",
)
tmpfilename_jxl = "/vsimem/test_tiff_write_lossless_extraction_of_JPEGXL_tile.jxl"
gdal.Translate(
tmpfilename_jxl,
tmpfilename_gtiff,
options="-srcwin 128 0 128 128 -co LOSSLESS_COPY=YES -co LOSSLESS=NO",
)
assert gdal.VSIStatL(tmpfilename_jxl + ".aux.xml") is None
gtiff_ds = gdal.Open(tmpfilename_gtiff)
jpeg_ds = gdal.Open(tmpfilename_jxl)
assert (
jpeg_ds.GetGeoTransform()[0]
== gtiff_ds.GetGeoTransform()[0] + 128 * gtiff_ds.GetGeoTransform()[1]
)
assert jpeg_ds.ReadRaster() == gtiff_ds.ReadRaster(128, 0, 128, 128)
gdal.Unlink(tmpfilename_gtiff)
gdal.Unlink(tmpfilename_jxl)
def test_tiff_write_offset_in_GDAL_METADATA_tag_metadata_in_pam():
filename = "/vsimem/test_tiff_write_offset_in_GDAL_METADATA_tag_metadata_in_pam.tif"
ds = gdal.GetDriverByName("GTiff").Create(filename, 1, 1)
ds.GetRasterBand(1).SetScale(0.01)
ds = None
ds = gdal.Open(filename)
# this goes into PAM
ds.GetRasterBand(1).SetMetadataItem("foo", "bar")
ds = None
ds = gdal.Open(filename)
assert ds.GetRasterBand(1).GetScale() == 0.01
assert ds.GetRasterBand(1).GetMetadataItem("foo") == "bar"
ds = None
gdal.GetDriverByName("GTiff").Delete(filename)
def test_tiff_write_cleanup():
gdaltest.tiff_drv = None