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

image() with pillow.Image.Image creates fake duplicates #139

Closed
the-yrr opened this issue Apr 28, 2021 · 5 comments
Closed

image() with pillow.Image.Image creates fake duplicates #139

the-yrr opened this issue Apr 28, 2021 · 5 comments

Comments

@the-yrr
Copy link

the-yrr commented Apr 28, 2021

The name of the image is used to check for duplicates

For pillow images this is str(name) (the "name" variable is the image)
the image name will be something like:

<PIL.WebPImagePlugin.WebPImageFile image mode=RGB size=2048x2803 at 0x1EA56628F40>

this identifier is not unique and created massive problems with random wrong images

I propose to change the code to something like this (works for me), maybe add a type check for pillow.Image.Image:

        if isinstance(name, str):
            img = None
        elif isinstance(name, io.BytesIO):
            name, img = hashlib.md5(name.getvalue()).hexdigest(), name
        else:
            name, img = hashlib.md5(name.tobytes()).hexdigest(), name # new changed code
            #name, img = str(name), name # old code
            ### CHANGED NAME TO HASH ###
@Lucas-C
Copy link
Member

Lucas-C commented Apr 28, 2021

This may be a duplicate of #131,
that had a fix released last week: https://github.com/PyFPDF/fpdf2/blob/master/CHANGELOG.md#233---2021-04-21

Could you provide the version of fpdf2 you are using please?

@the-yrr
Copy link
Author

the-yrr commented Apr 28, 2021

I use version 2.3.3, just updated it 2 days ago.
the code snip is from the "image" function in the "fpdf.py" file, the block starts at line 1720 in my file.

it is not quite a duplicate of #131, the ByteIO was fixed, but not the pillow.Image.Image error I encountered (as can be seen in the code snip). The problem itself is the same though.

after reading the changelog:
I tried to add an image using a BytesIO object containing a webp image (undecoded data, not pixel data), which didn't work. I am not sure whether this is supposed to work or not.

@Lucas-C
Copy link
Member

Lucas-C commented Apr 29, 2021

OK, thanks for the explanations.

There is the unit test validating that BytesIO are supported:
https://github.com/PyFPDF/fpdf2/blob/master/test/image/image_types/test_insert_images.py#L63

Could you provide some Python code reproducing your issue please?
How is your usage of FPDF.image different from this unit test?

@the-yrr
Copy link
Author

the-yrr commented Apr 29, 2021

this script (see below) should give a pdf with images containing row + column position, e.g.
00, 01, 02, 03
10, 11, 12, 13
...
tiels are added from left to right, then top to bottom (fill row by row)

I added a pdf generated by the script. As you can easily see, it does not work after the first line

duplicate.pdf

Edit:

the difference to the unit test is that I add multiple images in a loop. At most one image object exists at a time. Thus the different images can occupy a previously used space in memory, resulting in the same "str()" representation.

Edit 2:
this Problem should not occur for ByteIO images, since the hash is used as the image name. Only pillow images still use "str()" as the name.

from PIL import Image, ImageDraw, ImageFont # pillow package
from fpdf import FPDF # fpdf2 package (needs pillow)


pdf = FPDF(orientation = "P", unit = "mm", format = "A4")
pdf.set_auto_page_break(auto = False) # , margin = 20 (specified unit, default 2cm)
pdf.set_margin(0)
pdf.add_page()

fnt = ImageFont.truetype("arial.ttf", 40)

for y in range(5):
  for x in range(4):
    im = Image.new(mode = "RGB", size = (100, 100), color = (60, 255, 10))
    draw = ImageDraw.Draw(im)
    draw.text((20,20), "{0}{1}".format(y,x), fill = (0,0,0), font=fnt)
    
    pdf.image(im, x = x*50+5, y = y*50+5, w = 45)

pdf.close()
pdf.output('duplicate.pdf')

@Lucas-C
Copy link
Member

Lucas-C commented Apr 30, 2021

This was some excellent minimal code reproducing the issue!

This was fixed and released: https://github.com/PyFPDF/fpdf2/releases/tag/2.3.4

Thank you for reporting it 😉

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