微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

将ARGB32py开罗表面转换为PIL低图像-逆色?

如何解决将ARGB32py开罗表面转换为PIL低图像-逆色?

认为正在执行一些琐碎的标准任务:我正在将(py)cairo表面转换为PIL(低)图像。原始cairo表面使用ARGB模式。目标PIL图像使用RGBA,即我想保留所有颜色和Alpha通道。但是,转换过程中的事情真的很奇怪:看来cairo在内部将其数据存储为BGRA,所以我实际上需要在转换过程中交换颜色通道,请参见此处:

import cairo

import gi
gi.require_version('Rsvg','2.0')
from gi.repository import Rsvg

from PIL import Image

w,h = 600,600
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,w,h,)
ctx = cairo.Context(surface)

ctx.set_source_rgba(1.0,1.0,1.0) # explicitly draw white background
ctx.rectangle(0,h)
ctx.fill()

# tested with https://raw.githubusercontent.com/pleiszenburg/abgleich/v0.0.7/src/abgleich/share/icon.svg
layout = Rsvg.Handle.new_from_file('icon.svg')
layout.render_cairo(ctx)

# EXPORT TEST #1: cairo
surface.write_to_png('export_cairo.png') # ok,looks as expected

pil = Image.frombuffer(mode = 'RGBA',size = (w,h),data = surface.get_data(),)

b,g,r,a = pil.split() # Color swap,part 1: Splitting the channels
pil = Image.merge('RGBA',(r,b,a)) # Color swap,part 2: Rearranging the channels

# EXPORT TEST #2: PIL
pil.save('export_pil.png') # ok,looks as expected IF COLORS ARE REARRANGED AS ABOVE

以上测试使用rsvg,但也可以通过简单地使用cairo绘制一些彩色线条来复制它。

我是不是非常误解某件事,或者这实际上是正确的方法吗?

解决方法

从cairo文档(https://www.cairographics.org/manual/cairo-Image-Surfaces.html#cairo-format-t):

CAIRO_FORMAT_ARGB32

每个像素是32位的数量,高8位是alpha,然后是红色,然后是绿色,然后是蓝色。 32位数量存储为本地端。使用预乘alpha。 (也就是说,透明度为50%的红色是0x80800000,而不是0x80ff0000。)(从1.0开始)

所以,在小端上,我认为这实际上是PIL所谓的BGRA。

与您的问题没有直接关系,但这是预乘alpha。

根据https://pillow.readthedocs.io/en/stable/handbook/concepts.html#concept-modes,唯一具有预乘alpha的模式是'RGBa'

或者这实际上是正确的方法吗?

不知道“正确”是什么意思。但是,我的评论是:必须有某种方法可以完成此操作,而无需通过中间图像。

由于Pillow不支持cairo的图像模式,因此也许可以改用numpy-y进行转换。例如,pycairo的测试套件包含以下内容:https://github.com/dalembertian/pycairo/blob/22d29e0820d0dcbe070a6eb6f8f302e8c41b71a7/test/isurface_get_data.py#L37-L42

buf = surface.get_data()
a = numpy.ndarray (shape=(w,h,4),dtype=numpy.uint8,buffer=buf)

# draw a vertical line
a[:,40,0] = 255  # byte 0 is blue on little-endian systems
a[:,1] = 0
a[:,2] = 0

因此,要将BGRa(以枕语方式)转换为RGBa,您可以执行以下操作来交换红色和蓝色通道(其中a是与上述相似的缓冲区):

(a[:,:,0],a[:,2]) = (a[:,2],0])

如果这真的比您通过中间Image的方法要好...嗯,我不知道。您必须判断什么是最好的方法。至少您现在应该能够解释为什么这样做是必要的(cairo和PIL不支持通用的图像格式)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。