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

Parameters for Image.open() #569

Closed
al45tair opened this issue Mar 25, 2014 · 10 comments
Closed

Parameters for Image.open() #569

al45tair opened this issue Mar 25, 2014 · 10 comments

Comments

@al45tair
Copy link
Contributor

There are a few file formats that would benefit from the ability to pass parameters through the Image.open() method. This needs to be thought about carefully because there are clearly some parameters that are generic (e.g. mode, size and dpi arguments, which could cause conversion or resizing, all of which can in some instances be supported directly by the image file plugin), while others are very format specific (e.g. the number of quality layers to load in a JPEG 2000 image).

As of today, some image file plugins are essentially relying on the laziness of PIL’s loading machinery so that the user can call open and subsequently set some properties on the returned object before load gets called. This is, IMO, pretty nasty.

(I might be up for fixing this myself, but I want to file a bug report before doing any coding because I want the opinions of others on how this should work.)

@aclark4life
Copy link
Member

I am +1, I think, but @wiredfool will need to comment. Any precedent in any other API for doing this?

@aclark4life aclark4life added this to the Future milestone Mar 25, 2014
@wiredfool
Copy link
Member

I want to look carefully at the code before endorsing an api change. I'm at a tentative +1.

@al45tair
Copy link
Contributor Author

@aclark4life The Image.save() API already has arguments; of course, in that case, you specify the format, so it’s obvious what they mean. Contrast with Image.open(), where you don't necessarily know the type of the file you’re loading; in that case, you may still wish to pass arguments that matter to you if the file turns out to be of a particular type, but we don’t want type-specific arguments to clash.

I was going to propose something like the following:

im = Image.open(fp, mode='r', size=None, format_args={})

We already have the mode argument; size would be a 2-tuple of pixel dimensions, while format_args is a dictionary mapping format names to format-specific-argument dictionaries. A JPEG 2000 themed example might be:

im = Image.open(fp, mode='r', format_args={ 'JPEG2000': { 'layers': 4 } })

the idea being that if fp turns out to be a JPEG 2000 file, the arguments in the relevant sub dictionary will apply. If it isn’t a JPEG 2000, it will be loaded without regard to those arguments. An alternative might be to use a flat dictionary with dot notation, e.g.

im = Image.open(fp, mode='r', format_args={ 'JPEG2000.layers': 4 })

Perhaps slightly easier to read and write?

Additionally, the size argument should always be passed to the plugin, because JPEG and JPEG 2000 are — in some cases — capable of loading and processing just enough data to obtain an image of the requested size.

@aclark4life aclark4life modified the milestones: 2.5.0, Future Apr 1, 2014
@aclark4life
Copy link
Member

Maybe this can go in 2.5.0 due in 3 months

@homm
Copy link
Member

homm commented Sep 15, 2015

We already have the mode argument

This is not truth. Mode is not "image mode", this is "file read mode" and it is always "r". First lines of open():

if mode != "r":
    raise ValueError("bad mode %r" % mode)

I strongly disagree about passing mode and size in constructor because:

There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.

Currently that way is opening image and calling draft(). This have many advantages: you can open image, check it dimensions, mode, some options and even verify sometimes before loading an image into memory.

I agree what there should be some way to configure decoder, but format_args={'JPEG2000': {'layers': 4}} looks too ugly. Maybe something like this?

i = Image.open(image)
i.draft(mode, size)
i.configure_decoder(jpeg2000={'layers': 4})

@al45tair
Copy link
Contributor Author

I'm not sure I understand your point about the mode argument. Maybe you’re confused and think I was proposing using it for the image mode, but indeed I was not.

As far as the draft method goes, it looks like you’re right that that’s the way to go here — however, this is not documented particularly well and the documentation could do with an overhaul in this regard. Right now there is code out there that is not using draft but instead pokes about directly in the Image object to set the desired mode and size.

I like the configure_decoder method also; it has less visual noise than using an explicit dictionary.

@radarhere
Copy link
Member

I created #1349 as a suggestion, but did not progress due to lack of a specific use for the API.

@Shivahk027
Copy link

Shivahk027 commented Jun 9, 2020

im = Image.open(fp, mode='r', format_args={ 'JPEG2000': { 'layers': 4 } })

in this what is fp? what is the value for fp? is that mandatory?

@radarhere
Copy link
Member

@Shivahk027 fp is short for 'file pointer'. It is one way of referencing the image that is being opened.

from PIL import Image
with open("Tests/images/hopper.png", "rb") as fp:
    im = Image.open(fp, mode='r', format_args={ 'JPEG2000': { 'layers': 4 } })

Another way is just to use the path of the image.

from PIL import Image
im = Image.open("Tests/images/hopper.png", mode='r', format_args={ 'JPEG2000': { 'layers': 4 } })

For more information, see https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.open

Note however that format_args is still under discussion here, and has not been implemented.

@hugovk
Copy link
Member

hugovk commented Jun 10, 2020

Let's close this issue as it's not really progressed in many years. We can reopen if necessary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants