Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
Typicon image files have all-or-nothing transparency when loaded
-
When I load a Typicon file, e.g. the house picture, all the partial transparency (antialiasing) is removed:
This is how it looks once I'm done with it:
and this is how it should look:
Here is my code:
from PIL import Image as ImageP import io import base64 import clipboard import ui appsize = (120, 120) typsize = (96, 96) offset = [(appsize[i] - typsize[i])/2 for i in range(2)] master = ImageP.new('RGBA', (120, 120), (50, 50, 50, 255)) home = ImageP.open("Typicons96_Home") home.show() # it is broken here, even before converting. home = home.convert('RGBA') r, g, b, a = home.split() home = ImageP.merge("RGB", (r, g, b)) mask = ImageP.merge("L", (a,)) master.paste(home, tuple(offset), mask) with io.BytesIO() as bIO: master.save(bIO, 'PNG') img = ui.Image.from_data(bIO.getvalue()) bytes = img.to_png() clipboard.set(base64.b64encode(bytes))
Curiously, this seems to happen only with the Typicon files and nothing else.
-
Fixed it. I just load it as a ui.Image first and then convert it to a PIL image. At the moment I'm using the clipboard, which is a pretty hacky solution so I'm open to ideas….
-
You can convert from a
ui.Image
to a PILImage
without using the clipboard like this:import ui import Image from io import BytesIO ui_img = ui.Image.named('Typicon96_Home') data = BytesIO(ui_img.to_png()) img = Image.open(data) img.show()
-
Thank you! I was using that to convert the other way around, I'm surprised I didn't think of it earlier.
My new code:
from PIL import Image as PILImage from ui import Image as UIImage import io appsize = (120, 120) typsize = (96, 96) offset = [(appsize[i] - typsize[i])/2 for i in range(2)] def makegradient(c1, c2, size): img = PILImage.new('RGB', size, c1) d = tuple(c2[i]-c1[i] for i in range(3)) pixels = img.load() h = appsize[1] for i in range(h): c = tuple(c1[a] + d[a]*i/h for a in range(3)) for j in range(appsize[0]): pixels[j, i] = c return img def composite(top, bottom, offset): bottom = bottom.copy() top = top.convert('RGBA') r, g, b, a = top.split() top = PILImage.merge("RGB", (r, g, b)) mask = PILImage.merge("L", (a,)) bottom.paste(top, tuple(offset), mask) return bottom def makeicon(c1, c2, name): gradient = makegradient(c1, c2, appsize) # hack to support partial transparency uii = UIImage.named(name) data = io.BytesIO(uii.to_png()) top = PILImage.open(data) icon = composite(top, gradient, offset) data.close() with io.BytesIO() as bIO: icon.save(bIO, 'PNG') img = UIImage.from_data(bIO.getvalue()) return img