#!/usr/bin/env pytest # -*- coding: utf-8 -*- ############################################################################### # $Id$ # # Project: GDAL/OGR Test Suite # Purpose: Test read/write functionality for GeoTIFF format. # Author: Frank Warmerdam # ############################################################################### # Copyright (c) 2003, Frank Warmerdam # Copyright (c) 2008-2013, Even Rouault # # 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 = '' 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(" 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( """ """ ) 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([""], "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") == [ "\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") == [ "\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(" 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("", "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] == "" ############################################################################### # 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( """ data/byte.tif 1 non_existing 1 """ ) 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( """ data/byte.tif 1 data/byte.tif 1 data/byte.tif 1 """ ) 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( """ data/byte.tif 1 data/byte.tif 1 data/byte.tif 1 data/rgbsmall.tif 1 """ ) 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( '' ) 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", '', ): 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