-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
Add support for BLP file format #3007
Conversation
src/PIL/BlpImagePlugin.py
Outdated
|
||
|
||
Image.register_open("BLP", BlpImageFile) | ||
Image.register_extension("BLP", ".blp") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi. Would you be interested in replacing "BLP"
with BlpImageFile.format
in these two lines, to avoid duplication, as per #1333?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@radarhere any idea why i'm getting "Cannot identify..." errors? |
Tests/test_file_blp.py
Outdated
def test_load_blp2_dxt1(self): | ||
im = Image.open("Tests/images/blp2_dxt1.blp") | ||
target = Image.open("Tests/images/blp2_dxt1.png") | ||
self.assert_image_similar(im, target.convert("RGBA"), 15) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my testing, I find that .convert("RGBA")
causes an error, and the test passes once it is removed.
Adding your plugin to the list in https://github.com/python-pillow/Pillow/blob/master/src/PIL/__init__.py fixes the error for Python 3. However, in Python 2, the error persists, because of
|
CHANGES.rst
Outdated
@@ -35,6 +35,9 @@ Changelog (Pillow) | |||
- Docs: Changed documentation references to 2.x to 2.7 #2921 | |||
[radarhere] | |||
|
|||
- Add a loader for the BLP format from Warcraft and World of Warcraft #3007 | |||
[jleclanche] | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PRs do not usually have their CHANGES entry as part of them - this is inviting merge conflicts for your PR if another PR is merged first. Whoever merges it in will add the entry.
All issues fixed and ready to merge. |
@radarhere good to go? |
While I'm able to provide comments and help with problems, I'd like to leave it up to a longer standing member of Pillow team to do the final review and merge. |
Paging @wiredfool @hugovk |
Paging @wiredfool @hugovk again. Can this land please? or is there anything blocking it? |
Since this has been approved, anything blocking merging it? :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the source/license of the test images? They're not from WoW are they?
Other than that, and the _open
issue, I think this is reasonable.
format = "BLP" | ||
format_description = "Blizzard Mipmap Format" | ||
|
||
def _open(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_open
should not be doing the decoding work, it should only be setting up tiles and deferring to a decoder.
See https://github.com/python-pillow/Pillow/blob/master/docs/example/DdsImagePlugin.py
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know it can be improved using the bcn decoder, but I wanted to at least land the exhaustive tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The example above uses the python decoder framework to split the _open
and load
phases in pure python. It's a upgrade of your old DDS plugin (which was then obsoleted by the C version)
blp2_dxt1 and blp2_raw are not copyrightable but other than that, the images are © Blizzard Entertainment. They just need a copyright notice, but I wasn't sure where to put it. Is it ok in the Tests/images/blp folder? |
We can't use them if they're copyright Blizzard, unless there's a very specific license that does give us that ability. Depending on the actual license, we may need to add them to the extra images in the depends repo rather than in this repo. |
Fair use applies here, as the assets are copyrighted but:
I was careful to avoid picking any asset that could potentially not be usable (logos, recognizable textures, etc). So I think a copyright notice should be enough, but I'm fine moving them to a separate repo if you prefer, just let me know how. Btw @wiredfool are you still on freenode? I pinged you there but no answer. |
So, no license. That's not going to fly with Debian legal (who has patched out an sRGB icc profile because it contained a copyright string), and it's not nearly open enough to distribute. Fair Use isn't a license, it's a potential defense. |
Why are the tests distributed in the packaged versions? Edit: Either way as I said just let me know how to move them to a separate repo, I'm fine with that. |
Tests are distributed in the source version, which is the canonical reference for all of the distro packagers. There have to be open source licensed images of this format somewhere, or they should be possible to create from non-copyrighted images. |
The two files I mentioned above are non-copyrightable, but I wanted to make sure to have coverage for all the variations of blp1 and blp2 (most of which the various blp encoders on the market can't generate right now). I'd rather move these wherever is more appropriate to avoid having it in the source. |
@wiredfool I'm a little overwhelmed on fixing the _open issue you pointed out. The PIL API isn't exactly obvious... (even though I've written several decoders I still don't understand it). Is this a merge-blocking issue? The plugin works as is. Regarding the blp files, please advise. |
Yes. The example I linked is your original DDS encoder, redone with the pydecoder interface. Unfortunately, the online diff between it and the original got lost in the move and the conversion of the original into a C form. However, the basics are here: def _open():
...
if fourcc == b"DXT1":
self.decoder = "DXT1"
codec = _dxt1
elif fourcc == b"DXT5":
self.decoder = "DXT5"
codec = _dxt5
else:
raise NotImplementedError("Unimplemented pixel format %r" % fourcc)
self.tile = [
(self.decoder, (0, 0) + self.size, 0, (self.mode, 0, 1))
]
and one of the sample decoders: class DXT1Decoder(ImageFile.PyDecoder):
_pulls_fd = True
def decode(self, buffer):
try:
self.set_as_raw(_dxt1(self.fd, self.state.xsize, self.state.ysize))
except struct.error:
raise IOError("Truncated DDS file")
return 0, 0 If you're reading from the fd yourself, then you want to set the _pulls_fd, and manage the buffer yourself.
In your case, def _open(self):
self.magic = self.fp.read(4)
self._read_blp_header()
if self.magic == b"BLP1":
decoder = 'BLP1'
elif self.magic == b"BLP2":
decoder = 'BLP2'
else:
raise BLPFormatError("Bad BLP magic %r" % (self.magic))
self.tile = [
(decoder, (0, 0) + self.size, 0, (self.mode, 0, 1))
] (though, I think you'd have to hoist the Then you'd need two pydecoders that basically defer to the _open_blp* functions, and call self.set_as_raw on the returned bytestream. |
This seems a little silly given that BLP is a container format for DXT and JPG in the first place... it should be pulling in the bcn decoder as I said. Now don't get me wrong, I'm all for this better interface that doesn't fully read the file on open(), but here's the thing: You're one of the only people in the world who understands that API. Pillow, as I've ranted several times in the past, is extremely hard to understand (I say that having contracted on refactoring 10 year old million-line python codebases), with obscure incantations and voodoo attribute names all over the place. I get that this isn't your fault, but as it is, you're asking me to spend a lot of time understanding and refactoring this BLP plugin, when you can open just about almost any of the other plugins and find a million much worse offenders; and as far as I can see, only two of them use the PyDecoder interface, making example usage extremely sparse. The DXT decoder you linked in example docs does not seem to even work (self.fd isn't a thing on decoders). Feel free to do this; I made sure to have exhaustive tests so it can be done in the future (as I said, this should use the c decoder, not the python one), and the plugin itself is as clean as I could make it. But I'd like to merge in the current version as soon as you let me know where to push the sample images to. |
That example was the workpiece for the PyDecoder. it was ready to merge when you converted the decoders it was based on to C. I assure you that it works, and some of the changes, such as self.fd, are there specifically because the API was hard to work with. So, here you go, 1 hour while the kids are having stories. wiredfool@196717f#diff-ba00046598bc3bd2e09dd786d7f74950L252 I'm not 100% happy with it due to code duplication, and the format detection probably could be pushed back into the _open method, and then delegate directly to the raw, jpeg, and other decoders in self.tile. |
@wiredfool Forgot to ping back! Thank you for the help with this. I have rebased it against master. Now what do we do about the images? If moving them to another repo is a problem then I'll drop the copyrighted ones just to get this landed; but I'd rather they live somewhere. |
@wiredfool poke |
@jleclanche Have a look at test_images in https://github.com/python-pillow/pillow-depends and how, for example, the picins dir is skipped https://github.com/python-pillow/Pillow/search?utf8=%E2%9C%93&q=picins&type=. It would be good to have at least some redistributable ones in this repo. |
I've thought about this some more, and I don't think we should be adding images that are Copyright Blizzard in that repo either. The ones that are there are there are included from other test image archives and have unclear licenses or licenses that wouldn't pass Debian Legal. This is a different case, and we shouldn't be hosting these in one of our repos. |
Sounds reasonable, then let's try and find or create "free" replacements for the copyright ones. |
I've removed the copyrighted images. The three that remain are good to go. |
Ping for a merge @wiredfool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Still needs documentation and release notes #3018 |
@jleclanche I realise it's been a long time since this PR, but you actually have added four images here, not three. Should the fourth one, blp1_jpeg.blp, be removed, or are we ok to use it for testing from a copyright perspective? |
Everything I added here is ok to use yep |
Thanks very much for the reply. |
This actually uses a custom python decoder for dxt1/3/5 which is... silly, given that we added a cpython decoder in #1652. But this is some very old work I happen to be able to backport now, and I just tested to be working, so I really want to land it even if the decoder could be ported to use the bcn decoder for better performance.