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

RFC: Pure Python Decoder objects #1938

Merged
merged 23 commits into from
Mar 12, 2017

Conversation

wiredfool
Copy link
Member

File format decoders are currently complicated to put together.

  1. There's no registry, we're just doing a getattr on the image.core object. This PR adds a registry, then falls back to the current method.
  2. The decoders are all in C, a fast but unsafe language. Python is significantly slower, but safe. This is a tradeoff that we should be able to make. (in either direction)
  3. Currently, if we do implement a decoder in python, the load phase is stuffed into the open phase. This breaks the convention of open being a relatively quick operation and by deferring the heavy work to the load phase. As an added bonus, parsing errors here will no longer lead to "cannot identify image file" errors.

This pr builds on the Python fd changes from #1934, but the underlying concept doesn't need to rely on that. It's still likely that the interface chosen there will change, requiring changes here.

Changes proposed in this pull request:

  • Add Image.register_decoder and Image.register_encoder to map decoder name -> a callable that returns a de/encoder.
  • Adds the ImageFile.PyDecoder class that implements the interface used by the C layer decoder object. (Undone, an encoder object)
  • Refactors the DDS image Plugin to use the new registry and decoder class.

@wiredfool
Copy link
Member Author

Looking at merging this soon after 3.3

@homm
Copy link
Member

homm commented Jun 30, 2016

Don't forget to rebase.

@wiredfool
Copy link
Member Author

yeah. and docs.

@aclark4life
Copy link
Member

I'm going to assume since rebasing and documentation are still needed that this one will have to wait for 3.5.

@aclark4life aclark4life modified the milestones: 3.5.0, 3.4.0 Oct 3, 2016
@wiredfool
Copy link
Member Author

Yeah, the case study got converted to C. So, either we ship it as an example, but with no actual use case, or ... I'm not sure. I'd like to have a set of example code in here somewhere.

@wiredfool
Copy link
Member Author

Now includes #2384, and a re-implementation of the Msp Decoder in python.

@wiredfool wiredfool mentioned this pull request Feb 21, 2017
PIL/Image.py Outdated
:param encoder: A callable(mode, args) that returns an
ImageFile.PyEncoder object

.. versionadded:: 3.3.0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bump

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right.

Copy link
Member

@hugovk hugovk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

About docs/example/DdsImagePlugin.py

Is it the same as the one in PIL? Can we instead refer to the live file? A copy in docs will be unmaintained and may at some point stop working or be a misleading example.

def register_decoder(name, decoder):
"""
Registers an image decoder. This function should not be
used in application code.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this function shouldn't be used in application code, should it begin with an underscore?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scroll up. This is the same as register_extension/save/open/mime/foo. It's not for application code, it's for plugin developers.

def register_encoder(name, encoder):
"""
Registers an image encoder. This function should not be
used in application code.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this function shouldn't be used in application code, should it begin with an underscore?

@@ -433,6 +440,11 @@ def _getencoder(mode, encoder_name, args, extra=()):
args = (args,)

try:
encoder = ENCODERS[encoder_name]
return encoder(mode, *args + extra)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line isn't covered by tests.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we don't have a pure python encoder yet.


.. versionadded:: 4.1.0
"""
ENCODERS[name] = encoder
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line isn't covered by tests.

PIL/ImageFile.py Outdated

@property
def handles_eof(self):
return self._handles_eof
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line isn't covered by tests.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That property was removed in 4.0 anyway

@@ -1,8 +1,12 @@
from helper import unittest, PillowTestCase, hopper

from PIL import Image, MspImagePlugin
from PIL import Image, ImageFile, MspImagePlugin
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ImageFile imported but unused

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. You imported it to get the LOAD_TRUNCATED_IMAGES variable.

@@ -1,6 +1,5 @@
#
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file contains tabs and spaces. Let's remove tabs.

attributes. To be able to load the file, the method must also create a list of
:py:attr:`tile` descriptors. The class must be explicitly registered, via a
call to the :py:mod:`~PIL.Image` module.
A image plug-in should contain a format handler derived from the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-> "An image"

:py:attr:`~PIL.Image.Image.size` attributes. To be able to load the
file, the method must also create a list of :py:attr:`tile`
descriptors, which contain a decoder name, extents of the tile, and
any decoder specific data. The format handler class must be explicitly
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-> "decoder-specific data"

decode method. File decoders should be registered using
:py:meth:`PIL.Image.register_decoder`. As in the C implementation of
the file decoders, there are three stages in the lifetime of a Python
based file decoder:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-> "Python-based"

@wiredfool
Copy link
Member Author

Ok, I think this is tested as much as I can get.

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

Successfully merging this pull request may close these issues.

5 participants