libvips/test/test-suite/test_foreign.py
John Cupitt b836749b75 close jpeg read early
The current behaviour (close input handles on unref) works for languages
like C / C++ / Python / Rust / etc. where things get unreffed automatically
when they go out of scope.

On languages like Ruby / C# / node / etc. where things are unreffed on GC,
files can stay open for a long time after you've finished with them. This
interacts in an unfortunate way with the Windows default of refusing to
remove open files.

This change closes file handles as soon as the scan of the input file
finishes, and therefore produces something closer to expected behaviour
for GCd languages on Windows.

see https://github.com/kleisauke/net-vips/issues/12
2018-08-16 15:47:48 +01:00

815 lines
29 KiB
Python

# vim: set fileencoding=utf-8 :
import gc
import os
import shutil
import tempfile
import pytest
import pyvips
from helpers import \
JPEG_FILE, SRGB_FILE, MATLAB_FILE, PNG_FILE, TIF_FILE, OME_FILE, \
ANALYZE_FILE, GIF_FILE, WEBP_FILE, EXR_FILE, FITS_FILE, OPENSLIDE_FILE, \
PDF_FILE, SVG_FILE, SVGZ_FILE, SVG_GZ_FILE, GIF_ANIM_FILE, DICOM_FILE, \
BMP_FILE, NIFTI_FILE, ICO_FILE, \
temp_filename, assert_almost_equal_objects, have, skip_if_no
class TestForeign:
tempdir = None
@classmethod
def setup_class(cls):
cls.tempdir = tempfile.mkdtemp()
cls.colour = pyvips.Image.jpegload(JPEG_FILE)
cls.mono = cls.colour.extract_band(1)
# we remove the ICC profile: the RGB one will no longer be appropriate
cls.mono.remove("icc-profile-data")
cls.rad = cls.colour.float2rad()
cls.rad.remove("icc-profile-data")
cls.cmyk = cls.colour.bandjoin(cls.mono)
cls.cmyk = cls.cmyk.copy(interpretation=pyvips.Interpretation.CMYK)
cls.cmyk.remove("icc-profile-data")
im = pyvips.Image.new_from_file(GIF_FILE)
cls.onebit = im > 128
@classmethod
def teardown_class(cls):
shutil.rmtree(cls.tempdir, ignore_errors=True)
# we have test files for formats which have a clear standard
def file_loader(self, loader, test_file, validate):
im = pyvips.Operation.call(loader, test_file)
validate(im)
im = pyvips.Image.new_from_file(test_file)
validate(im)
def buffer_loader(self, loader, test_file, validate):
with open(test_file, 'rb') as f:
buf = f.read()
im = pyvips.Operation.call(loader, buf)
validate(im)
im = pyvips.Image.new_from_buffer(buf, "")
validate(im)
def save_load(self, format, im):
x = pyvips.Image.new_temp_file(format)
im.write(x)
assert im.width == x.width
assert im.height == x.height
assert im.bands == x.bands
max_diff = (im - x).abs().max()
assert max_diff == 0
def save_load_file(self, format, options, im, thresh):
# yuk!
# but we can't set format parameters for pyvips.Image.new_temp_file()
filename = temp_filename(self.tempdir, format)
im.write_to_file(filename + options)
x = pyvips.Image.new_from_file(filename)
assert im.width == x.width
assert im.height == x.height
assert im.bands == x.bands
max_diff = (im - x).abs().max()
assert max_diff <= thresh
x = None
def save_load_buffer(self, saver, loader, im, max_diff=0, **kwargs):
buf = pyvips.Operation.call(saver, im, **kwargs)
x = pyvips.Operation.call(loader, buf)
assert im.width == x.width
assert im.height == x.height
assert im.bands == x.bands
assert (im - x).abs().max() <= max_diff
def save_buffer_tempfile(self, saver, suf, im, max_diff=0):
filename = temp_filename(self.tempdir, suf)
buf = pyvips.Operation.call(saver, im)
f = open(filename, 'wb')
f.write(buf)
f.close()
x = pyvips.Image.new_from_file(filename)
assert im.width == x.width
assert im.height == x.height
assert im.bands == x.bands
assert (im - x).abs().max() <= max_diff
def test_vips(self):
self.save_load_file(".v", "", self.colour, 0)
# check we can save and restore metadata
filename = temp_filename(self.tempdir, ".v")
self.colour.write_to_file(filename)
x = pyvips.Image.new_from_file(filename)
before_exif = self.colour.get("exif-data")
after_exif = x.get("exif-data")
assert len(before_exif) == len(after_exif)
for i in range(len(before_exif)):
assert before_exif[i] == after_exif[i]
x = None
@skip_if_no("jpegload")
def test_jpeg(self):
def jpeg_valid(im):
a = im(10, 10)
assert_almost_equal_objects(a, [6, 5, 3])
profile = im.get("icc-profile-data")
assert len(profile) == 1352
assert im.width == 1024
assert im.height == 768
assert im.bands == 3
self.file_loader("jpegload", JPEG_FILE, jpeg_valid)
self.save_load("%s.jpg", self.mono)
self.save_load("%s.jpg", self.colour)
self.buffer_loader("jpegload_buffer", JPEG_FILE, jpeg_valid)
self.save_load_buffer("jpegsave_buffer", "jpegload_buffer",
self.colour, 80)
# see if we have exif parsing: our test image has this field
x = pyvips.Image.new_from_file(JPEG_FILE)
if x.get_typeof("exif-ifd0-Orientation") != 0:
# we need a copy of the image to set the new metadata on
# otherwise we get caching problems
# can set, save and load new orientation
x = pyvips.Image.new_from_file(JPEG_FILE)
x = x.copy()
x.set("orientation", 2)
filename = temp_filename(self.tempdir, '.jpg')
x.write_to_file(filename)
x = pyvips.Image.new_from_file(filename)
y = x.get("orientation")
assert y == 2
# can remove orientation, save, load again, orientation
# has reset
x.remove("orientation")
filename = temp_filename(self.tempdir, '.jpg')
x.write_to_file(filename)
x = pyvips.Image.new_from_file(filename)
y = x.get("orientation")
assert y == 1
# autorotate load works
x = pyvips.Image.new_from_file(JPEG_FILE)
x = x.copy()
x.set("orientation", 6)
filename = temp_filename(self.tempdir, '.jpg')
x.write_to_file(filename)
x1 = pyvips.Image.new_from_file(filename)
x2 = pyvips.Image.new_from_file(filename, autorotate=True)
assert x1.width == x2.height
assert x1.height == x2.width
# can set, save and reload ASCII string fields
x = pyvips.Image.new_from_file(JPEG_FILE)
x = x.copy()
x.set_type(pyvips.GValue.gstr_type,
"exif-ifd0-ImageDescription", "hello world")
filename = temp_filename(self.tempdir, '.jpg')
x.write_to_file(filename)
x = pyvips.Image.new_from_file(filename)
y = x.get("exif-ifd0-ImageDescription")
# can't use == since the string will have an extra " (xx, yy, zz)"
# format area at the end
assert y.startswith("hello world")
# can set, save and reload UTF16 string fields ... pyvips is
# utf8, but it will be coded as utf16 and back for the XP* fields
x = pyvips.Image.new_from_file(JPEG_FILE)
x = x.copy()
x.set_type(pyvips.GValue.gstr_type, "exif-ifd0-XPComment", u"йцук")
filename = temp_filename(self.tempdir, '.jpg')
x.write_to_file(filename)
x = pyvips.Image.new_from_file(filename)
y = x.get("exif-ifd0-XPComment")
# can't use == since the string will have an extra " (xx, yy, zz)"
# format area at the end
assert y.startswith(u"йцук")
# can set/save/load UserComment, a tag which has the
# encoding in the first 8 bytes ... though libexif only supports
# ASCII for this
x = pyvips.Image.new_from_file(JPEG_FILE)
x = x.copy()
x.set_type(pyvips.GValue.gstr_type,
"exif-ifd2-UserComment", "hello world")
filename = temp_filename(self.tempdir, '.jpg')
x.write_to_file(filename)
x = pyvips.Image.new_from_file(filename)
y = x.get("exif-ifd2-UserComment")
# can't use == since the string will have an extra " (xx, yy, zz)"
# format area at the end
assert y.startswith("hello world")
@skip_if_no("pngload")
def test_png(self):
def png_valid(im):
a = im(10, 10)
assert_almost_equal_objects(a, [38671.0, 33914.0, 26762.0])
assert im.width == 290
assert im.height == 442
assert im.bands == 3
self.file_loader("pngload", PNG_FILE, png_valid)
self.buffer_loader("pngload_buffer", PNG_FILE, png_valid)
self.save_load_buffer("pngsave_buffer", "pngload_buffer", self.colour)
self.save_load("%s.png", self.mono)
self.save_load("%s.png", self.colour)
@skip_if_no("tiffload")
def test_tiff(self):
def tiff_valid(im):
a = im(10, 10)
assert_almost_equal_objects(a, [38671.0, 33914.0, 26762.0])
assert im.width == 290
assert im.height == 442
assert im.bands == 3
self.file_loader("tiffload", TIF_FILE, tiff_valid)
self.buffer_loader("tiffload_buffer", TIF_FILE, tiff_valid)
if pyvips.at_least_libvips(8, 5):
self.save_load_buffer("tiffsave_buffer",
"tiffload_buffer",
self.colour)
self.save_load("%s.tif", self.mono)
self.save_load("%s.tif", self.colour)
self.save_load("%s.tif", self.cmyk)
self.save_load("%s.tif", self.onebit)
self.save_load_file(".tif", "[squash]", self.onebit, 0)
self.save_load_file(".tif", "[miniswhite]", self.onebit, 0)
self.save_load_file(".tif", "[squash,miniswhite]", self.onebit, 0)
self.save_load_file(".tif",
"[profile={0}]".format(SRGB_FILE),
self.colour, 0)
self.save_load_file(".tif", "[tile]", self.colour, 0)
self.save_load_file(".tif", "[tile,pyramid]", self.colour, 0)
self.save_load_file(".tif",
"[tile,pyramid,compression=jpeg]", self.colour, 80)
self.save_load_file(".tif", "[bigtiff]", self.colour, 0)
self.save_load_file(".tif", "[compression=jpeg]", self.colour, 80)
self.save_load_file(".tif",
"[tile,tile-width=256]", self.colour, 10)
filename = temp_filename(self.tempdir, '.tif')
x = pyvips.Image.new_from_file(TIF_FILE)
x = x.copy()
x.set("orientation", 2)
x.write_to_file(filename)
x = pyvips.Image.new_from_file(filename)
y = x.get("orientation")
assert y == 2
filename = temp_filename(self.tempdir, '.tif')
x = pyvips.Image.new_from_file(TIF_FILE)
x = x.copy()
x.set("orientation", 2)
x.write_to_file(filename)
x = pyvips.Image.new_from_file(filename)
y = x.get("orientation")
assert y == 2
x.remove("orientation")
filename = temp_filename(self.tempdir, '.tif')
x.write_to_file(filename)
x = pyvips.Image.new_from_file(filename)
y = x.get("orientation")
assert y == 1
filename = temp_filename(self.tempdir, '.tif')
x = pyvips.Image.new_from_file(TIF_FILE)
x = x.copy()
x.set("orientation", 6)
x.write_to_file(filename)
x1 = pyvips.Image.new_from_file(filename)
x2 = pyvips.Image.new_from_file(filename, autorotate=True)
assert x1.width == x2.height
assert x1.height == x2.width
# OME support in 8.5
x = pyvips.Image.new_from_file(OME_FILE)
assert x.width == 439
assert x.height == 167
page_height = x.height
x = pyvips.Image.new_from_file(OME_FILE, n=-1)
assert x.width == 439
assert x.height == page_height * 15
x = pyvips.Image.new_from_file(OME_FILE, page=1, n=-1)
assert x.width == 439
assert x.height == page_height * 14
x = pyvips.Image.new_from_file(OME_FILE, page=1, n=2)
assert x.width == 439
assert x.height == page_height * 2
x = pyvips.Image.new_from_file(OME_FILE, n=-1)
assert x(0, 166)[0] == 96
assert x(0, 167)[0] == 0
assert x(0, 168)[0] == 1
filename = temp_filename(self.tempdir, '.tif')
x.write_to_file(filename)
x = pyvips.Image.new_from_file(filename, n=-1)
assert x.width == 439
assert x.height == page_height * 15
assert x(0, 166)[0] == 96
assert x(0, 167)[0] == 0
assert x(0, 168)[0] == 1
# pyr save to buffer added in 8.6
x = pyvips.Image.new_from_file(TIF_FILE)
buf = x.tiffsave_buffer(tile=True, pyramid=True)
filename = temp_filename(self.tempdir, '.tif')
x.tiffsave(filename, tile=True, pyramid=True)
with open(filename, 'rb') as f:
buf2 = f.read()
assert len(buf) == len(buf2)
a = pyvips.Image.new_from_buffer(buf, "", page=2)
b = pyvips.Image.new_from_buffer(buf2, "", page=2)
assert a.width == b.width
assert a.height == b.height
assert a.avg() == b.avg()
# region-shrink added in 8.7
x = pyvips.Image.new_from_file(TIF_FILE)
buf = x.tiffsave_buffer(tile=True, pyramid=True, region_shrink="mean")
buf = x.tiffsave_buffer(tile=True, pyramid=True, region_shrink="mode")
buf = x.tiffsave_buffer(tile=True, pyramid=True, region_shrink="median")
@skip_if_no("magickload")
def test_magickload(self):
def bmp_valid(im):
a = im(100, 100)
assert_almost_equal_objects(a, [227, 216, 201])
assert im.width == 1419
assert im.height == 1001
self.file_loader("magickload", BMP_FILE, bmp_valid)
self.buffer_loader("magickload_buffer", BMP_FILE, bmp_valid)
# we should have rgb or rgba for svg files ... different versions of
# IM handle this differently
im = pyvips.Image.magickload(SVG_FILE)
assert im.bands == 3 or im.bands == 4
# density should change size of generated svg
im = pyvips.Image.magickload(SVG_FILE, density='100')
width = im.width
height = im.height
im = pyvips.Image.magickload(SVG_FILE, density='200')
# This seems to fail on travis, no idea why, some problem in their IM
# perhaps
# assert im.width == width * 2
# assert im.height == height * 2
# all-frames should load every frame of the animation
# (though all-frames is deprecated)
im = pyvips.Image.magickload(GIF_ANIM_FILE)
width = im.width
height = im.height
im = pyvips.Image.magickload(GIF_ANIM_FILE, all_frames=True)
assert im.width == width
assert im.height == height * 5
# page/n let you pick a range of pages
# 'n' param added in 8.5
if pyvips.at_least_libvips(8, 5):
im = pyvips.Image.magickload(GIF_ANIM_FILE)
width = im.width
height = im.height
im = pyvips.Image.magickload(GIF_ANIM_FILE, page=1, n=2)
assert im.width == width
assert im.height == height * 2
page_height = im.get("page-height")
assert page_height == height
# should work for dicom
im = pyvips.Image.magickload(DICOM_FILE)
assert im.width == 128
assert im.height == 128
# some IMs are 3 bands, some are 1, can't really test
# assert im.bands == 1
# added in 8.7
self.save_load_file(".bmp", "", self.colour, 0)
self.save_load_buffer("magicksave_buffer", "magickload_buffer",
self.colour, 0, format="BMP")
self.save_load("%s.bmp", self.colour)
# libvips has its own sniffer for ICO, test that
with open(ICO_FILE, 'rb') as f:
buf = f.read()
im = pyvips.Image.new_from_buffer(buf, "")
assert im.width == 16
assert im.height == 16
@skip_if_no("webpload")
def test_webp(self):
def webp_valid(im):
a = im(10, 10)
assert_almost_equal_objects(a, [71, 166, 236])
assert im.width == 550
assert im.height == 368
assert im.bands == 3
self.file_loader("webpload", WEBP_FILE, webp_valid)
self.buffer_loader("webpload_buffer", WEBP_FILE, webp_valid)
self.save_load_buffer("webpsave_buffer", "webpload_buffer",
self.colour, 60)
self.save_load("%s.webp", self.colour)
# test lossless mode
im = pyvips.Image.new_from_file(WEBP_FILE)
buf = im.webpsave_buffer(lossless=True)
im2 = pyvips.Image.new_from_buffer(buf, "")
assert im.avg() == im2.avg()
# higher Q should mean a bigger buffer
b1 = im.webpsave_buffer(Q=10)
b2 = im.webpsave_buffer(Q=90)
assert len(b2) > len(b1)
# try saving an image with an ICC profile and reading it back ... if we
# can do it, our webp supports metadata load/save
buf = self.colour.webpsave_buffer()
im = pyvips.Image.new_from_buffer(buf, "")
if im.get_typeof("icc-profile-data") != 0:
# verify that the profile comes back unharmed
p1 = self.colour.get("icc-profile-data")
p2 = im.get("icc-profile-data")
assert p1 == p2
# add tests for exif, xmp, ipct
# the exif test will need us to be able to walk the header,
# we can't just check exif-data
# we can test that exif changes change the output of webpsave
# first make sure we have exif support
z = pyvips.Image.new_from_file(JPEG_FILE)
if z.get_typeof("exif-ifd0-Orientation") != 0:
x = self.colour.copy()
x.set("orientation", 6)
buf = x.webpsave_buffer()
y = pyvips.Image.new_from_buffer(buf, "")
assert y.get("orientation") == 6
@skip_if_no("analyzeload")
def test_analyzeload(self):
def analyze_valid(im):
a = im(10, 10)
assert pytest.approx(a[0]) == 3335
assert im.width == 128
assert im.height == 8064
assert im.bands == 1
self.file_loader("analyzeload", ANALYZE_FILE, analyze_valid)
@skip_if_no("matload")
def test_matload(self):
def matlab_valid(im):
a = im(10, 10)
assert_almost_equal_objects(a, [38671.0, 33914.0, 26762.0])
assert im.width == 290
assert im.height == 442
assert im.bands == 3
self.file_loader("matload", MATLAB_FILE, matlab_valid)
@skip_if_no("openexrload")
def test_openexrload(self):
def exr_valid(im):
a = im(10, 10)
assert_almost_equal_objects(a, [0.124512, 0.159668,
0.040375, 1.0],
threshold=0.00001)
assert im.width == 610
assert im.height == 406
assert im.bands == 4
self.file_loader("openexrload", EXR_FILE, exr_valid)
@skip_if_no("fitsload")
def test_fitsload(self):
def fits_valid(im):
a = im(10, 10)
assert_almost_equal_objects(a, [-0.165013, -0.148553, 1.09122,
-0.942242], threshold=0.00001)
assert im.width == 200
assert im.height == 200
assert im.bands == 4
self.file_loader("fitsload", FITS_FILE, fits_valid)
self.save_load("%s.fits", self.mono)
@skip_if_no("niftiload")
def test_niftiload(self):
def nifti_valid(im):
a = im(30, 26)
assert_almost_equal_objects(a, [131])
assert im.width == 91
assert im.height == 9919
assert im.bands == 1
print("NIFTI_FILE =", NIFTI_FILE)
im = pyvips.Operation.call("niftiload", NIFTI_FILE)
print("width = ", im.width)
im = pyvips.Operation.call("niftiload", "test/images/avg152T1_LR_nifti.nii.gz")
print("width = ", im.width)
self.file_loader("niftiload", NIFTI_FILE, nifti_valid)
self.save_load("%s.nii.gz", self.mono)
@skip_if_no("openslideload")
def test_openslideload(self):
def openslide_valid(im):
a = im(10, 10)
assert_almost_equal_objects(a, [244, 250, 243, 255])
assert im.width == 2220
assert im.height == 2967
assert im.bands == 4
self.file_loader("openslideload", OPENSLIDE_FILE, openslide_valid)
@skip_if_no("pdfload")
def test_pdfload(self):
def pdf_valid(im):
a = im(10, 10)
assert_almost_equal_objects(a, [35, 31, 32, 255])
assert im.width == 1133
assert im.height == 680
assert im.bands == 4
self.file_loader("pdfload", PDF_FILE, pdf_valid)
self.buffer_loader("pdfload_buffer", PDF_FILE, pdf_valid)
im = pyvips.Image.new_from_file(PDF_FILE)
x = pyvips.Image.new_from_file(PDF_FILE, scale=2)
assert abs(im.width * 2 - x.width) < 2
assert abs(im.height * 2 - x.height) < 2
im = pyvips.Image.new_from_file(PDF_FILE)
x = pyvips.Image.new_from_file(PDF_FILE, dpi=144)
assert abs(im.width * 2 - x.width) < 2
assert abs(im.height * 2 - x.height) < 2
@skip_if_no("gifload")
def test_gifload(self):
def gif_valid(im):
a = im(10, 10)
assert_almost_equal_objects(a, [33])
assert im.width == 159
assert im.height == 203
assert im.bands == 1
self.file_loader("gifload", GIF_FILE, gif_valid)
self.buffer_loader("gifload_buffer", GIF_FILE, gif_valid)
# 'n' param added in 8.5
if pyvips.at_least_libvips(8, 5):
x1 = pyvips.Image.new_from_file(GIF_ANIM_FILE)
x2 = pyvips.Image.new_from_file(GIF_ANIM_FILE, n=2)
assert x2.height == 2 * x1.height
page_height = x2.get("page-height")
assert page_height == x1.height
x2 = pyvips.Image.new_from_file(GIF_ANIM_FILE, n=-1)
assert x2.height == 5 * x1.height
x2 = pyvips.Image.new_from_file(GIF_ANIM_FILE, page=1, n=-1)
assert x2.height == 4 * x1.height
@skip_if_no("svgload")
def test_svgload(self):
def svg_valid(im):
a = im(10, 10)
# some old rsvg versions are way, way off
assert abs(a[0] - 79) < 2
assert abs(a[1] - 79) < 2
assert abs(a[2] - 132) < 2
assert abs(a[3] - 255) < 2
assert im.width == 288
assert im.height == 470
assert im.bands == 4
self.file_loader("svgload", SVG_FILE, svg_valid)
self.buffer_loader("svgload_buffer", SVG_FILE, svg_valid)
self.file_loader("svgload", SVGZ_FILE, svg_valid)
self.buffer_loader("svgload_buffer", SVGZ_FILE, svg_valid)
self.file_loader("svgload", SVG_GZ_FILE, svg_valid)
im = pyvips.Image.new_from_file(SVG_FILE)
x = pyvips.Image.new_from_file(SVG_FILE, scale=2)
assert abs(im.width * 2 - x.width) < 2
assert abs(im.height * 2 - x.height) < 2
im = pyvips.Image.new_from_file(SVG_FILE)
x = pyvips.Image.new_from_file(SVG_FILE, dpi=144)
assert abs(im.width * 2 - x.width) < 2
assert abs(im.height * 2 - x.height) < 2
def test_csv(self):
self.save_load("%s.csv", self.mono)
def test_matrix(self):
self.save_load("%s.mat", self.mono)
@skip_if_no("ppmload")
def test_ppm(self):
self.save_load("%s.ppm", self.mono)
self.save_load("%s.ppm", self.colour)
@skip_if_no("radload")
def test_rad(self):
self.save_load("%s.hdr", self.colour)
self.save_buffer_tempfile("radsave_buffer", ".hdr",
self.rad, max_diff=0)
@skip_if_no("dzsave")
def test_dzsave(self):
# dzsave is hard to test, there are so many options
# test each option separately and hope they all function together
# correctly
# default deepzoom layout ... we must use png here, since we want to
# test the overlap for equality
filename = temp_filename(self.tempdir, '')
self.colour.dzsave(filename, suffix=".png")
# test horizontal overlap ... expect 256 step, overlap 1
x = pyvips.Image.new_from_file(filename + "_files/10/0_0.png")
assert x.width == 255
y = pyvips.Image.new_from_file(filename + "_files/10/1_0.png")
assert y.width == 256
# the right two columns of x should equal the left two columns of y
left = x.crop(x.width - 2, 0, 2, x.height)
right = y.crop(0, 0, 2, y.height)
assert (left - right).abs().max() == 0
# test vertical overlap
assert x.height == 255
y = pyvips.Image.new_from_file(filename + "_files/10/0_1.png")
assert y.height == 256
# the bottom two rows of x should equal the top two rows of y
top = x.crop(0, x.height - 2, x.width, 2)
bottom = y.crop(0, 0, y.width, 2)
assert (top - bottom).abs().max() == 0
# there should be a bottom layer
x = pyvips.Image.new_from_file(filename + "_files/0/0_0.png")
assert x.width == 1
assert x.height == 1
# 10 should be the final layer
assert not os.path.isdir(filename + "_files/11")
# default google layout
filename = temp_filename(self.tempdir, '')
self.colour.dzsave(filename, layout="google")
# test bottom-right tile ... default is 256x256 tiles, overlap 0
x = pyvips.Image.new_from_file(filename + "/2/2/3.jpg")
assert x.width == 256
assert x.height == 256
assert not os.path.exists(filename + "/2/2/4.jpg")
assert not os.path.exists(filename + "/3")
x = pyvips.Image.new_from_file(filename + "/blank.png")
assert x.width == 256
assert x.height == 256
# google layout with overlap ... verify that we clip correctly
# overlap 1, 510x510 pixels, 256 pixel tiles, should be exactly 2x2
# tiles, though in fact the bottom and right edges will be white
filename = temp_filename(self.tempdir, '')
self.colour.crop(0, 0, 510, 510).dzsave(filename, layout="google",
overlap=1, depth="one")
x = pyvips.Image.new_from_file(filename + "/0/1/1.jpg")
assert x.width == 256
assert x.height == 256
assert not os.path.exists(filename + "/0/2/2.jpg")
# with 511x511, it'll fit exactly into 2x2 -- we we actually generate
# 3x3, since we output the overlaps
filename = temp_filename(self.tempdir, '')
self.colour.crop(0, 0, 511, 511).dzsave(filename, layout="google",
overlap=1, depth="one")
x = pyvips.Image.new_from_file(filename + "/0/2/2.jpg")
assert x.width == 256
assert x.height == 256
assert not os.path.exists(filename + "/0/3/3.jpg")
# default zoomify layout
filename = temp_filename(self.tempdir, '')
self.colour.dzsave(filename, layout="zoomify")
# 256x256 tiles, no overlap
assert os.path.exists(filename + "/ImageProperties.xml")
x = pyvips.Image.new_from_file(filename + "/TileGroup0/2-3-2.jpg")
assert x.width == 256
assert x.height == 256
# test zip output
filename = temp_filename(self.tempdir, '.zip')
self.colour.dzsave(filename)
assert os.path.exists(filename)
assert not os.path.exists(filename + "_files")
assert not os.path.exists(filename + ".dzi")
# test compressed zip output
filename2 = temp_filename(self.tempdir, '.zip')
self.colour.dzsave(filename2, compression=-1)
assert os.path.exists(filename2)
assert os.path.getsize(filename2) < os.path.getsize(filename)
# test suffix
filename = temp_filename(self.tempdir, '')
self.colour.dzsave(filename, suffix=".png")
x = pyvips.Image.new_from_file(filename + "_files/10/0_0.png")
assert x.width == 255
# test overlap
filename = temp_filename(self.tempdir, '')
self.colour.dzsave(filename, overlap=200)
y = pyvips.Image.new_from_file(filename + "_files/10/1_1.jpeg")
assert y.width == 654
# test tile-size
filename = temp_filename(self.tempdir, '')
self.colour.dzsave(filename, tile_size=512)
y = pyvips.Image.new_from_file(filename + "_files/10/0_0.jpeg")
assert y.width == 513
assert y.height == 513
# test save to memory buffer
filename = temp_filename(self.tempdir, '.zip')
base = os.path.basename(filename)
root, ext = os.path.splitext(base)
self.colour.dzsave(filename)
with open(filename, 'rb') as f:
buf1 = f.read()
buf2 = self.colour.dzsave_buffer(basename=root)
assert len(buf1) == len(buf2)
# we can't test the bytes are exactly equal -- the timestamps will
# be different
# added in 8.7
buf = self.colour.dzsave_buffer(region_shrink="mean")
buf = self.colour.dzsave_buffer(region_shrink="mode")
buf = self.colour.dzsave_buffer(region_shrink="median")
if __name__ == '__main__':
pytest.main()