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

Use RGBX rawmode for RGB JPEG images #1989

Merged

Conversation

homm
Copy link
Member

@homm homm commented Jun 26, 2016

libjpeg-turbo supports different output formats.
We are choosing Pillow's native format (3 color bytes + 1 padding) to avoid extra conversion in Unpack.c.

This speeds up JPEG loading by 19% and saving by 14%.

JCS_RGB (master) JCS_EXT_RGBX
libjpeg-turbo 1.3.0
Load 133.80 Mpx/s 160.04 Mpx/s
Save 145.08 Mpx/s 166.38 Mpx/s
libjpeg-turbo 1.5.80 (dev branch)
Load 141.53 Mpx/s 168.21 Mpx/s
Save 172.14 Mpx/s 200.08 Mpx/s

@homm
Copy link
Member Author

homm commented Jun 27, 2016

Don't understand why tiff loading fails in Travis environment. Investigating.

@homm homm added this to the 3.4.0 milestone Jun 29, 2016
@wiredfool
Copy link
Member

Well, it's a jpeg encoded tiff, so at least there's some basis for why it's failing.

This is im.tile from that image:
[('jpeg', (0, 0, 128, 32), 8, ('RGB', '')), ('jpeg', (0, 32, 128, 64), 4445, ('RGB', '')), ('jpeg', (0, 64, 128, 96), 8722, ('RGB', '')), ('jpeg', (0, 96, 128, 128), 12726, ('RGB', ''))]

@homm homm removed this from the 3.4.0 milestone Sep 25, 2016
@aclark4life aclark4life added this to the 3.5.0 milestone Oct 3, 2016
@aclark4life
Copy link
Member

@homm 3.5.0 then?

@homm
Copy link
Member Author

homm commented Oct 3, 2016

Sure

@homm homm force-pushed the jpeg-loading-without-convertion branch from 4b79592 to a926d2e Compare October 12, 2016 20:25
@homm
Copy link
Member Author

homm commented Oct 13, 2016

As always, weird bug. I don't have it on Ubuntu 14.04, so I installed Ubuntu 12.04.

stock libjpeg-turbo 1.1.90, no modifications: no problems
recent libjpeg-turbo 1.5.1, no modifications: broken data stream
stock libjpeg-turbo 1.1.90, JCS_EXT_RGB for RGB: broken data stream
recent libjpeg-turbo 1.5.1, JCS_EXT_RGB for RGB: broken data stream
stock libjpeg-turbo 1.1.90, JCS_EXT_RGBX for RGBX: broken data stream
recent libjpeg-turbo 1.5.1, JCS_EXT_RGBX for RGBX: broken data stream

It is absolutely unclear how JCS_RGB differ from JCS_EXT_RGB and why libjpeg-turbo 1.5.1 also leads to the error.

@homm
Copy link
Member Author

homm commented Oct 13, 2016

After night debugging I can say what is going on.

First, libjpeg-turbo 1.5.1 fails due to compilation issue, not relevant to this case.

The real problem was that the TIFF file is in RGB colorspace, while all other JPEGs for tests are YCbCr (or maybe CMYK). On Ubuntu 12.04. LTS the default libjpeg-turbo version is 1.1.90. And it doesn't support RGBRGB transformations, including JCS_EXT_RGB which should be equivalent for JCS_RGB. See source code

Starting from 1.2.1 libjpeg-turbo supports all JCS_EXT_* transformations for YCbCr, Gray and RGB colorspaces. See changelog and source code

So before implementing this small feature, we need to do the following:

  • Propagate errors from libjpeg (any version) to python exception. It is a key to understanding issues.
  • Add tests for all JPEG input colorspaces. It is luck that we fail with TIFF.
  • Add one build on Travis with recent libjpeg-turbo version.

As for solution: in theory, we can do not switch to RGBX in the case when the source file is in RGB colorspace and libjpeg-turbo version < 1.2.1. But we need to make a decision in PyImaging_JpegDecoderNew, where we don't have information about colorspace (this happens only in ImagingJpegDecode). So in my opinion it is better to use RGBX only with libjpeg-turbo >= 1.2.1.

@radarhere radarhere modified the milestones: 4.1.0, 4.0.0 Jan 7, 2017
@wiredfool wiredfool modified the milestones: 4.1.0, 4.2.0 Apr 1, 2017
@homm homm modified the milestones: 4.3.0, 4.2.0 Aug 9, 2017
@homm
Copy link
Member Author

homm commented Aug 10, 2017

Unfortunately, this not so easy to detect current libjpeg-turbo version: libjpeg-turbo/libjpeg-turbo#166

@homm homm removed the Do Not Merge label Aug 10, 2017
@python-pillow python-pillow deleted a comment from codecov bot Aug 10, 2017
@homm
Copy link
Member Author

homm commented Aug 11, 2017

Resolved the libjpeg-turbo version issue.
Implementing the same approach for saving.
Updated benchmarks.

@@ -189,6 +218,10 @@ ImagingJpegDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
context->cinfo.out_color_space = JCS_GRAYSCALE;
else if (strcmp(context->rawmode, "RGB") == 0)
context->cinfo.out_color_space = JCS_RGB;
#ifdef JCS_EXTENSIONS
Copy link
Member Author

Choose a reason for hiding this comment

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

This simple check is enough because anything else is checked when rawmode is set to RGBX.

int use_jcs_extensions = 0;
#ifdef JCS_EXTENSIONS
#if defined(LIBJPEG_TURBO_VERSION_NUMBER)
#if LIBJPEG_TURBO_VERSION_NUMBER >= 1002010
Copy link
Member Author

Choose a reason for hiding this comment

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

LIBJPEG_TURBO_VERSION_NUMBER is defined starting from 1.5.0 (1005000). Compare it one more time to be sure.

#endif
#else
if (libjpeg_turbo_version) {
use_jcs_extensions = strcmp(libjpeg_turbo_version, "1.2.1") >= 0;
Copy link
Member Author

Choose a reason for hiding this comment

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

this literally means:

use_jcs_extensions = (libjpeg_turbo_version >= "1.2.1")

@homm
Copy link
Member Author

homm commented Aug 17, 2017

@wiredfool Could you review this. I've added explanations for all significant lines.

@homm homm mentioned this pull request Aug 26, 2017
@wiredfool
Copy link
Member

wiredfool commented Aug 28, 2017

How are you feeling about the three bullet points above? (#1989 (comment))

  • Fedora 26 has version 1.5.1. (this provides libjpeg, which is what we're requesting in our Dockerfile)

I'm not sure about the status of the other bullets.

(edit: do you want to rebase to pull in the .travis.yml that runs against Fedora?)

@homm
Copy link
Member Author

homm commented Aug 28, 2017

How are you feeling about the three bullet points above?

Not for this release, unfortunately.

The most important thing is "Add tests for all JPEG input colorspaces" but as I can see, we had pil_sample_cmyk.jpg in tests at least from 24 may 2016 and I don't know why we hadn't hit the issue with it.

@homm
Copy link
Member Author

homm commented Aug 28, 2017

Both Fedoras passed

@wiredfool wiredfool modified the milestones: 4.4.0, 4.3.0 Aug 31, 2017
@homm
Copy link
Member Author

homm commented Aug 31, 2017

@wiredfool I meant that I'm not ready to implement bullets, «Propagate errors from libjpeg», for example. As of this PR, I think it is ready and relatively safe for all systems.

@wiredfool
Copy link
Member

Ok, fair enough.

@wiredfool wiredfool merged commit 9797e7b into python-pillow:master Aug 31, 2017
@wiredfool wiredfool modified the milestones: 4.3.0, 4.4.0 Aug 31, 2017
@homm homm deleted the jpeg-loading-without-convertion branch August 31, 2017 14:28
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

Successfully merging this pull request may close these issues.

4 participants