py2cairo/tests/test_surface.py

718 lines
22 KiB
Python

# -*- coding: utf-8 -*-
import io
import os
import sys
import array
import tempfile
import struct
import sysconfig
import platform
import cairo
import pytest
def test_context_manager():
with cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) as surface:
surface.show_page()
with pytest.raises(cairo.Error) as excinfo:
surface.show_page()
assert excinfo.value.status == cairo.Status.SURFACE_FINISHED
def test_surface_cmp_hash():
main = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
ctx = cairo.Context(main)
assert ctx.get_target() == main
assert not ctx.get_target() != main
assert main != object()
assert hash(ctx.get_target()) == hash(main)
# we implement some hackery to change the underlying object after unmap
# which would change the hash. Make sure this type is unhashable.
mapped = main.map_to_image(None)
with pytest.raises(TypeError):
hash(mapped)
assert mapped == mapped
main.unmap_image(mapped)
def test_surface_map_to_image():
main = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
image = main.map_to_image(None)
with pytest.raises(TypeError):
type(image)()
other = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
with pytest.raises(ValueError):
other.unmap_image(image)
with pytest.raises(TypeError):
main.unmap_image(other)
with pytest.raises(RuntimeError):
image.finish()
main.unmap_image(image)
with pytest.raises(RuntimeError):
main.unmap_image(image)
# from here on everything should fail
with pytest.raises(cairo.Error):
cairo.Context(image)
with pytest.raises(TypeError):
main.map_to_image(object())
with pytest.raises(TypeError):
main.map_to_image()
gced = main.map_to_image(None)
del gced
def test_surface_map_to_image_context_manager():
main = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
with main.map_to_image(None) as image:
pass
with pytest.raises(RuntimeError):
main.unmap_image(image)
with pytest.raises(cairo.Error) as excinfo:
image.show_page()
assert excinfo.value.status == cairo.Status.SURFACE_FINISHED
with pytest.raises(RuntimeError):
with image:
pass
def test_surface_map_to_image_data():
main = cairo.ImageSurface(cairo.Format.RGB24, 2, 1)
main.flush()
assert bytes(main.get_data()) == b"\x00\x00\x00\x00\x00\x00\x00\x00"
image = main.map_to_image(None)
ctx = cairo.Context(image)
ctx.set_source_rgb(1, 1, 1)
ctx.paint()
main.unmap_image(image)
main.flush()
assert bytes(main.get_data()) == b"\xff\xff\xff\xff\xff\xff\xff\xff"
main = cairo.ImageSurface(cairo.Format.RGB24, 2, 1)
image = main.map_to_image(cairo.RectangleInt(0, 0, 1, 1))
ctx = cairo.Context(image)
ctx.set_source_rgb(1, 1, 1)
ctx.paint()
main.unmap_image(image)
main.flush()
assert bytes(main.get_data()) == b"\xff\xff\xff\xff\x00\x00\x00\x00"
@pytest.mark.skipif(not cairo.HAS_TEE_SURFACE, reason="no tee surface")
def test_tee_surface():
main = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
tee = cairo.TeeSurface(main)
assert isinstance(tee, cairo.TeeSurface)
with pytest.raises(TypeError):
cairo.TeeSurface(object())
with pytest.raises(TypeError):
tee.add(object())
with pytest.raises(TypeError):
tee.remove(object())
with pytest.raises(TypeError):
tee.index(object())
# the API is horrible, passing a wrong arg sets the surface to an error
# state instead of returning the status.
s1 = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
tee.add(s1)
assert tee.index(0)
assert tee.index(1)
tee.remove(s1)
@pytest.mark.skipif(not hasattr(sys, "getrefcount"), reason="PyPy")
def test_image_surface_get_data_refcount():
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
assert sys.getrefcount(surface) == 2
d = surface.get_data()
assert sys.getrefcount(surface) == 3
del d
assert sys.getrefcount(surface) == 2
def test_image_surface_get_data_crasher():
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
try:
assert 0, surface.get_data()
except Exception:
pass
def test_surface_get_content():
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
assert surface.get_content() == cairo.Content.COLOR_ALPHA
assert isinstance(surface.get_content(), cairo.Content)
def test_surface_get_format():
surface = cairo.ImageSurface(cairo.Format.ARGB32, 10, 10)
assert surface.get_format() == cairo.Format.ARGB32
assert isinstance(surface.get_format(), cairo.Format)
def test_pdf_get_versions():
versions = cairo.PDFSurface.get_versions()
assert isinstance(versions, list)
assert all(isinstance(v, cairo.PDFVersion) for v in versions)
def test_pdf_set_size():
fileobj = io.BytesIO()
surface = cairo.PDFSurface(fileobj, 128, 128)
surface.set_size(10, 10)
with pytest.raises(TypeError):
surface.set_size(10, object())
@pytest.mark.skipif(not hasattr(cairo.PDFSurface, "set_page_label"),
reason="too old cairo")
def test_pdf_set_page_label():
fileobj = io.BytesIO()
with cairo.PDFSurface(fileobj, 128, 128) as surface:
surface.set_page_label("foo")
surface.set_page_label("bar")
with pytest.raises(cairo.Error):
surface.set_page_label("bar")
@pytest.mark.skipif(not hasattr(cairo.PDFSurface, "set_metadata"),
reason="too old cairo")
def test_pdf_set_metadata():
fileobj = io.BytesIO()
with cairo.PDFSurface(fileobj, 128, 128) as surface:
surface.set_metadata(cairo.PDFMetadata.TITLE, "title")
surface.set_metadata(cairo.PDFMetadata.TITLE, "title")
surface.set_metadata(cairo.PDFMetadata.AUTHOR, "author")
with pytest.raises(cairo.Error):
surface.set_metadata(cairo.PDFMetadata.AUTHOR, "author")
@pytest.mark.skipif(not hasattr(cairo.PDFSurface, "add_outline"),
reason="too old cairo")
def test_pdf_add_outline():
fileobj = io.BytesIO()
with cairo.PDFSurface(fileobj, 128, 128) as surface:
res = surface.add_outline(
cairo.PDF_OUTLINE_ROOT, "foo", "page=3 pos=[3.1 6.2]",
cairo.PDFOutlineFlags.OPEN)
assert isinstance(res, int)
@pytest.mark.skipif(not hasattr(cairo.PDFSurface, "set_thumbnail_size"),
reason="too old cairo")
def test_pdf_set_thumbnail_size():
fileobj = io.BytesIO()
with cairo.PDFSurface(fileobj, 128, 128) as surface:
surface.set_thumbnail_size(10, 10)
surface.set_thumbnail_size(0, 0)
surface.set_thumbnail_size(1, 1)
with pytest.raises(cairo.Error):
surface.set_thumbnail_size(0, 0)
@pytest.mark.skipif(
sysconfig.get_platform().startswith("win"), reason="msvc fixme")
def test_pdf_surface():
fd, fname = tempfile.mkstemp()
os.close(fd)
try:
cairo.PDFSurface(fname, 10, 10).finish()
finally:
os.unlink(fname)
with pytest.raises(TypeError):
cairo.PDFSurface()
with pytest.raises((ValueError, TypeError)):
cairo.PDFSurface("\x00")
with pytest.raises(TypeError):
cairo.PDFSurface(object(), 100, 100)
def test_svg_version_to_string():
ver = cairo.SVGSurface.version_to_string(cairo.SVG_VERSION_1_1)
assert ver and isinstance(ver, str)
with pytest.raises(ValueError):
cairo.SVGSurface.version_to_string(-1)
with pytest.raises(TypeError):
cairo.SVGSurface.version_to_string(object())
@pytest.mark.skipif(not hasattr(cairo.SVGSurface, "get_document_unit"),
reason="too old cairo")
def test_svg_surface_get_document_unit():
with cairo.SVGSurface(None, 10, 10) as surface:
assert surface.get_document_unit() == cairo.SVGUnit.PT
surface.set_document_unit(cairo.SVGUnit.PX)
assert surface.get_document_unit() == cairo.SVGUnit.PX
with pytest.raises(cairo.Error):
surface.set_document_unit(cairo.SVGUnit.PX)
def test_svg_surface_restrict_to_version():
surface = cairo.SVGSurface(None, 10, 10)
surface.restrict_to_version(cairo.SVG_VERSION_1_1)
surface.finish()
with pytest.raises(cairo.Error):
surface.restrict_to_version(cairo.SVG_VERSION_1_2)
with pytest.raises(TypeError):
surface.restrict_to_version(object())
@pytest.mark.skipif(
sysconfig.get_platform().startswith("win"), reason="msvc fixme")
def test_pdf_surface_restrict_to_version():
surface = cairo.PDFSurface(None, 10, 10)
surface.restrict_to_version(cairo.PDF_VERSION_1_4)
surface.finish()
with pytest.raises(cairo.Error):
surface.restrict_to_version(cairo.PDF_VERSION_1_5)
with pytest.raises(TypeError):
surface.restrict_to_version(object())
def test_pdf_version_to_string():
ver = cairo.PDFSurface.version_to_string(cairo.PDF_VERSION_1_4)
assert ver and isinstance(ver, str)
with pytest.raises(ValueError):
cairo.PDFSurface.version_to_string(-1)
with pytest.raises(TypeError):
cairo.PDFSurface.version_to_string(object())
def test_ps_surface_misc():
surface = cairo.PSSurface(None, 10, 10)
surface.dsc_begin_page_setup()
surface.dsc_begin_setup()
def test_ps_surface_dsc_comment():
surface = cairo.PSSurface(None, 10, 10)
surface.dsc_comment("%%Title: My excellent document")
with pytest.raises(cairo.Error):
surface.dsc_comment("")
with pytest.raises(TypeError):
surface.dsc_comment(object())
def test_ps_get_eps():
surface = cairo.PSSurface(None, 10, 10)
assert isinstance(surface.get_eps(), bool)
surface.set_eps(True)
assert surface.get_eps()
with pytest.raises(TypeError):
surface.set_eps(object())
def test_ps_set_size():
surface = cairo.PSSurface(None, 10, 10)
surface.set_size(10, 10)
with pytest.raises(TypeError):
surface.set_size(10, object())
def test_ps_restrict_to_level():
surface = cairo.PSSurface(None, 10, 10)
surface.restrict_to_level(cairo.PSLevel.LEVEL_2)
with pytest.raises(TypeError):
surface.restrict_to_level(object())
@pytest.mark.skipif(
sysconfig.get_platform().startswith("win"), reason="msvc fixme")
def test_ps_surface_level_to_string():
level_id = cairo.PSSurface.level_to_string(cairo.PS_LEVEL_2)
assert isinstance(level_id, str)
assert cairo.PSSurface.ps_level_to_string(cairo.PS_LEVEL_2) == level_id
with pytest.raises(ValueError):
cairo.PSSurface.level_to_string(-1)
with pytest.raises(TypeError):
cairo.PSSurface.level_to_string(object())
def test_ps_surface_get_levels():
levels = cairo.PSSurface.get_levels()
assert isinstance(levels, list)
assert all(isinstance(v, cairo.PSLevel) for v in levels)
def test_ps_surface():
assert isinstance(cairo.PSSurface(None, 10, 10), cairo.PSSurface)
fd, fname = tempfile.mkstemp()
os.close(fd)
try:
cairo.PSSurface(fname, 10, 10).finish()
finally:
os.unlink(fname)
with pytest.raises(TypeError):
cairo.PSSurface()
with pytest.raises((ValueError, TypeError)):
cairo.PSSurface("\x00", 100, 100)
with pytest.raises(TypeError):
cairo.PSSurface(object(), 100, 100)
def test_scg_surface():
fd, fname = tempfile.mkstemp()
os.close(fd)
try:
cairo.SVGSurface(fname, 10, 10).finish()
finally:
os.unlink(fname)
with pytest.raises(TypeError):
cairo.SVGSurface()
with pytest.raises((ValueError, TypeError)):
cairo.SVGSurface("\x00", 10, 10)
with pytest.raises(TypeError):
cairo.SVGSurface(object(), 100, 100)
def test_svg_surface_get_versions():
versions = cairo.SVGSurface.get_versions()
assert isinstance(versions, list)
assert all(isinstance(v, cairo.SVGVersion) for v in versions)
def test_surface_get_device_scale():
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
device_scale = surface.get_device_scale()
assert all(isinstance(s, float) for s in device_scale)
def test_surface_set_device_scale():
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
ret = surface.set_device_scale(5.0, 3.0)
assert ret is None
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 100, 100)
with pytest.raises(cairo.Error):
surface.set_device_scale(1, 0)
with pytest.raises(TypeError):
surface.set_device_scale(1, object())
def test_surface_create_for_rectangle():
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 100, 100)
new = surface.create_for_rectangle(0, 0, 10, 10)
assert new
assert isinstance(new, cairo.Surface)
with pytest.raises(cairo.Error) as excinfo:
surface.create_for_rectangle(0, 0, 10, -1)
assert excinfo.value.status == cairo.STATUS_INVALID_SIZE
with pytest.raises(TypeError):
surface.create_for_rectangle(0, 0, 10, object())
def test_surface_create_similar_image():
surface = cairo.PDFSurface(None, 1, 1)
image = surface.create_similar_image(cairo.FORMAT_ARGB32, 24, 42)
assert image
assert isinstance(image, cairo.ImageSurface)
del surface
assert image.get_width() == 24
assert image.get_height() == 42
surface = cairo.PDFSurface(None, 1, 1)
with pytest.raises(TypeError):
surface.create_similar_image(cairo.FORMAT_ARGB32, 24, object())
def test_surface_get_set_mime_data():
surface = cairo.ImageSurface(cairo.FORMAT_RGB24, 1, 1)
assert surface.get_mime_data("foo") is None
assert surface.get_mime_data(cairo.MIME_TYPE_JPEG) is None
surface.set_mime_data("foo", b"bar")
assert surface.get_mime_data("foo") == b"bar"
surface.set_mime_data("foo", None)
assert surface.get_mime_data("foo") is None
surface.set_mime_data(cairo.MIME_TYPE_JPEG, b"\x00quux\x00")
assert surface.get_mime_data(cairo.MIME_TYPE_JPEG)[:] == b"\x00quux\x00"
surface.set_mime_data(cairo.MIME_TYPE_JPEG, None)
assert surface.get_mime_data(cairo.MIME_TYPE_JPEG) is None
with pytest.raises(TypeError):
surface.set_mime_data(cairo.MIME_TYPE_JPEG, object())
with pytest.raises(TypeError):
surface.get_mime_data(object())
def test_supports_mime_type():
surface = cairo.PDFSurface(None, 3, 3)
assert surface.supports_mime_type(cairo.MIME_TYPE_JPEG)
assert not surface.supports_mime_type("nope")
with pytest.raises(TypeError):
surface.supports_mime_type(object())
# https://bitbucket.org/pypy/pypy/issues/2751
@pytest.mark.skipif(platform.python_implementation() == "PyPy", reason="PyPy")
def test_image_surface_create_for_data_array():
width, height = 255, 255
data = array.array('B', [0] * width * height * 4)
for y in range(height):
for x in range(width):
offset = (x + (y * width)) * 4
alpha = y
b = int(x * alpha / 255.0)
g = int(y * alpha / 255.0)
# cairo.FORMAT_ARGB32 uses pre-multiplied alpha
data[offset:offset + 4] = array.array(
"B", struct.pack("=I", b | g << 8 | alpha << 24))
surface = cairo.ImageSurface.create_for_data(
data, cairo.FORMAT_ARGB32, width, height)
# for debugging
fd, filename = tempfile.mkstemp(prefix='pycairo_', suffix='.png')
os.close(fd)
surface.write_to_png(filename)
os.unlink(filename)
def test_image_surface_write_to_png_filename_and_obj_compare():
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 128, 128)
fd, filename = tempfile.mkstemp(prefix='pycairo_', suffix='.png')
os.close(fd)
surface.write_to_png(filename)
fileobj = io.BytesIO()
surface.write_to_png(fileobj)
with open(filename, "rb") as h:
assert h.read() == fileobj.getvalue()
os.unlink(filename)
def test_image_surface_png_obj_roundtrip():
fileobj = io.BytesIO()
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 128, 128)
surface.write_to_png(fileobj)
fileobj.seek(0)
new_surface = cairo.ImageSurface.create_from_png(fileobj)
assert surface.get_data() == new_surface.get_data()
with pytest.raises(TypeError):
cairo.ImageSurface.create_from_png()
with pytest.raises((ValueError, TypeError)):
cairo.ImageSurface.create_from_png("\x00")
with pytest.raises(TypeError):
cairo.ImageSurface.create_from_png(object())
def test_image_surface_png_file_roundtrip():
fd, filename = tempfile.mkstemp(prefix='pycairo_', suffix='.png')
os.close(fd)
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 128, 128)
surface.write_to_png(filename)
new_surface = cairo.ImageSurface.create_from_png(filename)
assert surface.get_data() == new_surface.get_data()
os.unlink(filename)
def test_image_surface_write_to_png_error():
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 128, 128)
with pytest.raises(TypeError):
surface.write_to_png(42)
with pytest.raises((ValueError, TypeError)):
surface.write_to_png("\x00")
def test_surface_from_stream_closed_before_finished():
for Kind in [cairo.PDFSurface, cairo.PSSurface, cairo.SVGSurface]:
fileobj = io.BytesIO()
surface = cairo.PDFSurface(fileobj, 128, 128)
fileobj.close()
with pytest.raises(IOError):
surface.finish()
def test_script_surface():
f = io.BytesIO()
dev = cairo.ScriptDevice(f)
surface = cairo.ScriptSurface(dev, cairo.Content.COLOR_ALPHA, 42, 10)
assert isinstance(surface, cairo.ScriptSurface)
cairo.Context(surface).paint()
dev.flush()
assert b"42" in f.getvalue()
assert b"paint" in f.getvalue()
with pytest.raises(TypeError):
cairo.ScriptSurface()
def test_script_device_device_ref():
f = io.BytesIO()
dev = cairo.ScriptDevice(f)
surface = cairo.ScriptSurface(dev, cairo.Content.COLOR_ALPHA, 42, 10)
del dev
for i in range(10):
surface.get_device()
def test_script_surface_create_for_target():
# paint the script proxy
f = io.BytesIO()
dev = cairo.ScriptDevice(f)
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
script = cairo.ScriptSurface.create_for_target(dev, surface)
with pytest.raises(TypeError):
cairo.ScriptSurface.create_for_target(dev, object())
assert isinstance(script, cairo.ScriptSurface)
ctx = cairo.Context(script)
ctx.set_source_rgb(0.25, 0.5, 1.0)
ctx.paint()
assert b"paint" in f.getvalue()
surface.flush()
image_data = bytes(surface.get_data())
# check if the result is the same
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
ctx = cairo.Context(surface)
ctx.set_source_rgb(0.25, 0.5, 1.0)
ctx.paint()
surface.flush()
assert bytes(surface.get_data()) == image_data
def test_misc():
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
surface.copy_page()
surface.mark_dirty()
surface.show_page()
@pytest.fixture
def surface():
return cairo.ImageSurface(cairo.Format.ARGB32, 10, 10)
@pytest.fixture
def image_surface():
return cairo.ImageSurface(cairo.Format.ARGB32, 10, 10)
def test_create_similar(surface):
similar = surface.create_similar(cairo.Content.COLOR, 10, 10)
assert isinstance(similar, cairo.Surface)
with pytest.raises(TypeError):
surface.create_similar()
def test_get_device_offset(surface):
surface.set_device_offset(1, 1)
assert surface.get_device_offset() == (1, 1)
with pytest.raises(TypeError):
surface.set_device_offset(1, object())
def test_get_fallback_resolution(surface):
surface.set_fallback_resolution(42, 42)
assert surface.get_fallback_resolution() == (42, 42)
with pytest.raises(TypeError):
surface.set_fallback_resolution(42, object())
def test_mark_dirty_rectangle(surface):
surface.mark_dirty_rectangle(0, 0, 10, 10)
with pytest.raises(TypeError):
surface.mark_dirty_rectangle(0, 0, 10, object())
def test_write_to_png(image_surface):
with pytest.raises(TypeError):
image_surface.write_to_png()
with pytest.raises((ValueError, TypeError)) as excinfo:
image_surface.write_to_png("\x00")
excinfo.match(r'.* (null|NUL) .*')
with pytest.raises(TypeError):
image_surface.write_to_png(object())
def test_image_surface():
with pytest.raises(TypeError):
cairo.ImageSurface(cairo.FORMAT_ARGB32, 3, object())
def test_image_surface_create_for_data():
format_ = cairo.FORMAT_ARGB32
surface = cairo.ImageSurface(format_, 3, 3)
ctx = cairo.Context(surface)
ctx.paint()
surface.flush()
buf = surface.get_data()
new = cairo.ImageSurface.create_for_data(buf, format_, 3, 3)
assert new.get_data() == buf
with pytest.raises(ValueError):
cairo.ImageSurface.create_for_data(buf, format_, 3, -1)
with pytest.raises(ValueError):
cairo.ImageSurface.create_for_data(buf, format_, -1, 3)
with pytest.raises(ValueError):
cairo.ImageSurface.create_for_data(buf, format_, 0, 0, -1)
with pytest.raises(cairo.Error) as excinfo:
cairo.ImageSurface.create_for_data(buf, format_, 3, 3, 3)
assert excinfo.value.status == cairo.STATUS_INVALID_STRIDE
with pytest.raises(TypeError):
cairo.ImageSurface.create_for_data(buf, format_, 3, object())
def test_image_surface_stride_for_width():
v = cairo.ImageSurface.format_stride_for_width(cairo.Format.ARGB32, 10)
assert v == 40
with pytest.raises(TypeError):
cairo.ImageSurface.format_stride_for_width(
cairo.Format.ARGB32, object())
def test_image_surface_get_stride(image_surface):
assert image_surface.get_stride() == 40
def test_recording_surface():
with pytest.raises(TypeError):
cairo.RecordingSurface(cairo.CONTENT_COLOR, object())
with pytest.raises(TypeError):
cairo.RecordingSurface()
surface = cairo.RecordingSurface(cairo.CONTENT_COLOR, None)
assert surface.ink_extents() == (0.0, 0.0, 0.0, 0.0)