Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

get_pixmap with alpha produce gray image for transparent white image #2593

Closed
mamome2021 opened this issue Aug 14, 2023 · 7 comments
Closed

Comments

@mamome2021
Copy link

Please provide all mandatory information!

Describe the bug (mandatory)

I have a 50% transparent white image in pdf file. I want to use Page.get_pixmap(alpha=True) to render the page as pixmap, convert pixmap to pillow image, and paste it on another image (as watermark, for example). But the pixmap I get is gray image.

To Reproduce (mandatory)

code snippet:

import fitz
from PIL import Image

doc=fitz.open('alpha.pdf')
page=doc[0]
pix=page.get_pixmap(alpha=True)
img=Image.frombytes('RGBA', [pix.width, pix.height], pix.samples)
img.show()
img.save('alpha.tiff')

example pdf:
alpha.pdf

Expected behavior (optional)

white image with transparency

Your configuration (mandatory)

  • Operating system, potentially version and bitness
  • Python version, bitness
  • PyMuPDF version, installation method (wheel or generated from source).

3.11.3 (main, Jun 5 2023, 09:32:32) [GCC 13.1.1 20230429]
linux

PyMuPDF 1.22.5: Python bindings for the MuPDF 1.22.2 library.
Version date: 2023-06-21 00:00:01.
Built for Python 3.11 on linux (64-bit).
PyMuPDF generated from source

Additional context (optional)

If I save pixmap with pix.save(), the saved image looks fine

@JorjMcKie
Copy link
Collaborator

This effect is caused by setting transparency to 50% for apparently all your drawings.

@mamome2021
Copy link
Author

mamome2021 commented Aug 15, 2023

Do you have suggestion for keeping the image white? I have tried

img=Image.open(BytesIO(pix.tobytes()))

as alternative, but this is 50 times slower.

EDIT: slightly faster method with numpy:

import fitz
from PIL import Image
import numpy

doc=fitz.open('alpha.pdf')
page=doc[0]
pix=page.get_pixmap(alpha=True)
img=Image.frombytes('RGBA', [pix.width, pix.height], pix.samples)
r,g,b,a=img.split()
rarr=numpy.array(r,dtype=numpy.uint32)
garr=numpy.array(g,dtype=numpy.uint32)
barr=numpy.array(b,dtype=numpy.uint32)
aarr=numpy.array(a,dtype=numpy.uint32)
rarr*=255
garr*=255
barr*=255
rarr=numpy.floor_divide(rarr,aarr,where=aarr!=0,out=numpy.zeros_like(rarr))
garr=numpy.floor_divide(garr,aarr,where=aarr!=0,out=numpy.zeros_like(garr))
barr=numpy.floor_divide(barr,aarr,where=aarr!=0,out=numpy.zeros_like(barr))
img=Image.merge('RGBA',(Image.fromarray(numpy.uint8(rarr)),Image.fromarray(numpy.uint8(garr)),Image.fromarray(numpy.uint8(barr)),a))
img.show()
img.save('alpha.tiff')

@JorjMcKie
Copy link
Collaborator

Do you have suggestion for keeping the image white? I have tried

img=Image.open(BytesIO(pix.tobytes()))

as alternative, but this is 50 times slower.

It also doesn't solve the problem or does it?
No, the error happened when the PDF was created. Each of the vector graphics objects refers to an /ExtGState object that looks like this:

<</CA 0.5
   /ca 0.5
>>

These instructions set 50% transparency for fill and stroke colors. Who did that and why ... who knows. Emptying these objects (i.e. setting them to empty dictionaries <<>>) would solve the problem - or of course talking to the creator of the PDF 😉.

@mamome2021
Copy link
Author

It also doesn't solve the problem or does it?

Yes it does. Here is code snippet:

import fitz
from PIL import Image
from io import BytesIO

doc=fitz.open('alpha.pdf')
page=doc[0]
pix=page.get_pixmap(alpha=True)
print('color of pixmap:',pix.pixel(300,200))
img=Image.frombytes('RGBA', [pix.width, pix.height], pix.samples)
print('color of Image.frombytes:',img.getpixel((300,200)))
img=Image.open(BytesIO(pix.tobytes()))
print('color of Image.open:',img.getpixel((300,200)))

Output:

color of pixmap: (127, 127, 127, 127)
color of Image.frombytes: (127, 127, 127, 127)
color of Image.open: (255, 255, 255, 127)

Color is converted to white when image is saved.

@JorjMcKie
Copy link
Collaborator

Well, that's some logic inside Pillow then.

@mamome2021
Copy link
Author

mamome2021 commented Aug 18, 2023

I read pillow documentation again and found the mistake. I chose wrong mode 'RGBA' for pillow, I should use ' RGBa' because the image is premultiplied alpha.

Here is the correct code snippet:

import fitz
from PIL import Image

doc=fitz.open('alpha.pdf')
page=doc[0]
pix=page.get_pixmap(alpha=True)
img=Image.frombytes('RGBa', [pix.width, pix.height], pix.samples)
img=img.convert('RGBA')
img.show()
img.save('alpha.tiff')

This colorspace difference is not mentioned in get_pixmap reference, and tutorial also use 'RGBA' mode. Probably the documentation should be updated?

@JorjMcKie
Copy link
Collaborator

Thanks for the hint!
Yes, we will include a remark in the get_pixmap() method.

This was referenced Aug 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants