pyvips
pyvips copied to clipboard
dzsave: Can we generate map tiles with transparent background?
I create an image with transparent background and I want to do a pyramid of tiles out of this image. I do not know how to make the tiles transparent please. Is this possible?
In the code below I sample from the bivariate normal and save the scatter plot as a transparent png file. What I want to achieve is to keep this transparency when I generate the tiles. However I got a white background and black whenever padding is needed for the tile to be square, see attached
I understand that the black background is because I am setting to 0 but I cannot figure out how to set for a transparent background when padding is needed. It takes a vector of 1 or 5 elements
import numpy as np
import pyvips
import matplotlib.pyplot as plt
mu = [0, 0]
scale = 1
cov = scale ** 2 * np.eye(2)
x, y = np.random.multivariate_normal(mu, cov, 1000).T
plt.plot(x, y, 'ob')
plt.savefig(r'./demo.png', transparent=True)
zoom_levels = 4
dim = 256 * 2 ** zoom_levels
im = pyvips.Image.new_from_file('demo.png', access='sequential')
im = im.colourspace('srgb')
im = im.addalpha()
factor = dim / max(im.width, im.height)
im = im.resize(factor)
im.dzsave(r'./transparent_tiles', layout='google', suffix='.jpg', background=0, skip_blanks=0)
Hello @acycliq,
Do you mean you'd like the tiles in the pyramid to have a transparent background so you can overlay them on something else later? You'll need to use PNG for the tiles since JPG does not support transparency. You don't need the srgb or addalpha.
Try:
zoom_levels = 4
dim = 256 * 2 ** zoom_levels
im = pyvips.Image.new_from_file('demo.png', access='sequential')
factor = dim / max(im.width, im.height)
im = im.resize(factor)
im.dzsave(r'./transparent_tiles', layout='google', suffix='.png',
background=0, skip_blanks=0)
I see eg.
You also don't need to use a PNG intermediate file, you can pass the plot directly into pyvips, but you probably know. It would also be better to set a dpi in savefig rather than resizing in pyvips.
Oh yes, of course! It is the .jpg extension I got wrong. I thought It had to do with the alpha and I couldnt figure out how to set it. I did not understand your point about setting the dpi instead of resizing John. Can you please explain that?
Another question is about the background please. I thought that setting it as background=0
the extra space that is padded to the tile in order to be square would be black. It doesnt happen here, which is good! I want all the tiles to be fully transparent because I want to overlay them on another image as you correctly said in your reply. I just try to understand how it works please.
Thanks so much for all your help!
You're making a 640 x 400 pixel PNG, then upsizing to 4096 x 4096 using pyvips. Your edges will be fuzzy and a bit ugly. Instead, you can get matplotlib to generate the plot at 4096x4096 directly and remove the resize.
You don't need to save as PNG and then reload. Instead, matplotlib can make a big memory array which you can then load directly into pyvips. It'll be a lot quicker.
Try:
#!/usr/bin/python3
import io
import numpy as np
import pyvips
import matplotlib.pyplot as plt
mu = [0, 0]
scale = 1
cov = scale ** 2 * np.eye(2)
x, y = np.random.multivariate_normal(mu, cov, 1000).T
zoom_levels = 4
dim = 256 * 2 ** zoom_levels
plt.figure(figsize=(dim / 100, dim / 100), dpi=100)
plt.plot(x, y, 'ob')
io_buf = io.BytesIO()
plt.savefig(io_buf, transparent=True, dpi=100, format='raw')
im = pyvips.Image.new_from_memory(io_buf.getvalue(), dim, dim, 4, "uchar")
im.dzsave(r'./transparent_tiles', layout='google', suffix='.png',
background=0, skip_blanks=0)
Ah ok, I got it. Great! Many many thanks once again!