A little background: I wanted to use Python to dynamically generate some interesting random backgrounds, and I came across geopatterns:
https://github.com/bryanveloso/geopatterns
The library is a port of a Ruby version. I'm no expert at CSS or SVGs, but it seems like the library creates an SVG string that you can use in CSS and then CSS will magically tile/pattern the SVG onto the background of a DOM element to make big backgrounds like this:
Now, I don't want to use this library for web development, I actually want to generate a static image, preferably with control over the height and width of the image. How can I do this?
If I just use the geopatterns example code:
import cairosvg # https://stackoverflow.com/a/60220855/11741232 for problems
from geopatterns import GeoPattern
pattern = GeoPattern('A string for your consideration.', generator='xes')
cairosvg.svg2png(bytestring=pattern.svg_string, write_to="output.png")
I found this similar question: https://stackoverflow.com/a/73078937/11741232, and modified their code a bit, but my svg string did not work with Skia, Code for that attempt:
from geopatterns import GeoPattern
from PIL import Image
import skia
import io
# Generate the pattern as an SVG string
pattern = GeoPattern('A string for your consideration.', generator='xes')
svg_string = pattern.svg_string
print(svg_string)
def image_from_svg(svg, element_size):
stream = skia.MemoryStream()
stream.setMemory(bytes(svg, 'UTF-8'))
svg = skia.SVGDOM.MakeFromStream(stream)
width, height = svg.containerSize()
surface = skia.Surface(element_size, element_size)
with surface as canvas:
canvas.scale(element_size / width, element_size / height)
svg.render(canvas)
return surface.makeImageSnapshot()
def pattern(canvas, image_element, rotation):
matrix = skia.Matrix()
matrix.preRotate(rotation)
canvas.drawPaint({
'Shader': image_element.makeShader(
skia.TileMode.kRepeat,
skia.TileMode.kRepeat,
matrix,
)
})
def pattern_image_with_title(image_element, width, height, rotation):
surface = skia.Surface(width, height)
with surface as canvas:
pattern(canvas, image_element, rotation)
return surface.makeImageSnapshot()
def write_png(file_name, skia_image):
with io.BytesIO(skia_image.encodeToData()) as f:
pil_image = Image.open(f)
pil_image.save(file_name, 'PNG')
img = image_from_svg(svg_string, 50)
img = pattern_image_with_title(img, 300, 300, 0)
write_png('result.png', img)
Error:
AttributeError: 'NoneType' object has no attribute 'containerSize'