Принятая версия не работает правильно, если:
- Ваше изображение имеет цвета
- Ваше изображение не непрозрачно
- Ваше изображение в режиме, отличном от RGB (A)
В каирских цветах изображения их значение предварительно умножается на значение альфа, и они хранятся в виде 32-битного слова с использованием собственного порядкового номера ЦП. Это означает, что изображение PIL:
r1 g1 b1 a1 r2 g2 b2 a2 ...
хранится в Каире в процессоре с прямым порядком байтов как:
b1*a1 g1*a1 r1*a1 a1 b2*a2 g2*a2 r2*a2 a2 ...
и в процессоре с прямым порядком байтов как:
a1 r1*a1 b1*a1 g1*a1 a2 r2*a2 g2*a2 b2*a2 ...
Вот версия, которая корректно работает на машине с прямым порядком байтов без зависимости NumPy:
def pil2cairo(im):
"""Transform a PIL Image into a Cairo ImageSurface."""
assert sys.byteorder == 'little', 'We don\'t support big endian'
if im.mode != 'RGBA':
im = im.convert('RGBA')
s = im.tostring('raw', 'BGRA')
a = array.array('B', s)
dest = cairo.ImageSurface(cairo.FORMAT_ARGB32, im.size[0], im.size[1])
ctx = cairo.Context(dest)
non_premult_src_wo_alpha = cairo.ImageSurface.create_for_data(
a, cairo.FORMAT_RGB24, im.size[0], im.size[1])
non_premult_src_alpha = cairo.ImageSurface.create_for_data(
a, cairo.FORMAT_ARGB32, im.size[0], im.size[1])
ctx.set_source_surface(non_premult_src_wo_alpha)
ctx.mask_surface(non_premult_src_alpha)
return dest
Здесь я делаю предварительное умножение с помощью Каира. Я также попытался выполнить предварительное умножение с помощью NumPy, но результат оказался медленнее. Эта функция требует от моего компьютера (Mac OS X, Intel Core 2 Duo 2,13 ГГц) ~ 1 с для преобразования изображения 6000x6000 пикселей и 5 мс для преобразования изображения 500x500 пикселей.