libvips / php-vips

php binding for libvips
MIT License
619 stars 25 forks source link

Q: How best to avoid icc colour profile issues? #82

Closed derklempner closed 2 years ago

derklempner commented 5 years ago

Hi,

Thanks for all the work on this great library. I am slowly learning how to use it.

When converting colourspace to 'b-w' to threshold an image, I sometimes get an error when calling $image->writeToFile()

e.g. profile 'icc': 1000000h: invalid rendering intent in console and in PHP error log PHP Fatal error: Uncaught Jcupitt\Vips\Exception: vips2png: unable to write...

The only way so far I have managed to get around this one is calling strip in cli. vips copy in.jpg out.jpg[strip]

How does one achieve the [strip] equivalent / ignore all colour profile info in PHP?

PHP 7.2.8 / Vips library version 8.7.3 / php-vips 1.0.4

Cheers

jcupitt commented 5 years ago

Hello @derklempner,

The PNG writer is supposed to automatically drop incompatible profiles. Do you have an example image where this fails?

You can set strip in write_to_file with:

$image->writeToFile("somename.png", ["strip" => true]);
jcupitt commented 5 years ago

... though stripping the profile isn't always a great idea. It would be better to find out what's triggering this error.

If you can find a sample image and a scrap of PHP that reproduces it, I'll investigate.

derklempner commented 5 years ago

Ahh, thanks John. That's the ticket! I tried setting strip on load which of course failed, should've thought of on write.

Here are two images with different niggles. The first one has a CMYK profile and fails with the vips_colourspace: no known route from 'cmyk' to 'b-w' error that I see there are some other issues for that looks sort of solved now (?). This image fails even with the strip command unless I do a copy with interpretation initially, something like this:

// CMYK profile error
$image = Vips\Image::newFromFile($in);
$image = $image->copy(['interpretation' => 'srgb']);  // Avoids no route to b-w error
$image = $image->colourspace(Interpretation::B_W);
$image = $image->relational_const('more', 128);
$image->writeToFile("/tmp/out.png", ["strip" => true]);

team-1

The clown image gives the profile 'icc': 1000000h: invalid rendering intent error. Similar PHP as above but this time the $image->copy() step isn't required, but 'strip'=>true is. One difference is that it has an extra conversion back into srgb in it for further processing:

// Invalid rendering intent error
$image = Vips\Image::newFromFile($in);
$image = $image->copy(['interpretation' => 'srgb']);    // Not needed to work
$image = $image->colourspace(Interpretation::B_W);
$image = $image->relational_const('more', 128);
$image = $image->colourspace(Interpretation::SRGB);
$image->writeToFile("/tmp/out.png");  //["strip" => true] allows save

lets_play_original

Cheers

jcupitt commented 5 years ago

Yes, with current libvips you need to detect CMYK images and use icc_import before the colourspace. libvips 8.8 has better CMYK handling and this problem should just go away.

Your image#2 will give me nightmares. I'll see if I can reproduce it here.

jcupitt commented 5 years ago

For image#1 I would do:

#!/usr/bin/php 
<?php

require __DIR__ . '/vendor/autoload.php';
use Jcupitt\Vips;

$x = Vips\Image::newFromFile($argv[1], ["access" => "sequential"]);

# a fallback CMYK profile to use if a CMYK image has no embedded profile
$fallback_cmyk_profile = "/usr/share/color/icc/colord/FOGRA28L_webcoated.icc";

# cmyk images need to be imported from device space
if ($x->interpretation == "cmyk") {
  # input-profile will be used if the image has no embedded profile
  # after this, x will be in float CIELAB
  $x = $x->icc_import(["embedded" => true, 
                       "input_profile" => $fallback_cmyk_profile]);
}

# b-w is 8-bit, one band
$x = $x->colourspace("b-w");

$x->more(128)->writeToFile($argv[2]);

Then:

$ ./thresh.php ~/pics/cmyk2.jpg x.png
(banana:7671): VIPS-WARNING **: 11:40:15.010: profile incompatible with image

I'd ignore the warning. It's removed in the next version.

jcupitt commented 5 years ago

Looks like that works for your clown image too. I'm not sure why you saw that error.

For a fallback profile, I'd recommend:

https://github.com/libvips/nip2/blob/master/share/nip2/data/cmyk.icm

Public domain, high-quality, nice results with most CMYK images. It's the one that will be built into libvips 8.8.

With 8.8 you can just write:

$x = Vips\Image::newFromFile($argv[1], ["access" => "sequential"]);

$x->colourspace("b-w")->more(128)->writeToFile($argv[2]);

ie. colourspace has this logic built in.

derklempner commented 5 years ago

Super, that has cleared up that CMYK niggle. Thanks for looking into it :)

For the nightmare clown in order to avoid the profile 'icc': 1000000h: invalid rendering intent error it still requires saving with strip=true if a subsequent colourspace conversion to srgb takes place afterb-w.

The clown will save with just the warning when saved straight after b-w, regardless of setting the fallback profile or not.

Maybe it's just a nutty image, although I don't have an extensive test set, only about 100 images. For now I'm doing a bit of an icky try/catch to try save with/without the profile.

SPhu commented 5 years ago

For a fallback profile, I'd recommend:

https://github.com/libvips/nip2/blob/master/share/nip2/data/cmyk.icm

Public domain, high-quality, nice results with most CMYK images. It's the one that will be built into libvips 8.8.

@jcupitt Is there any ETA on 8.8? This would solve our main issue with vips right now as we actively trying to use it to replace imagick.

jcupitt commented 5 years ago

It's due in spring, I think. There's one planned feature still to go in (being able to thumbnail complete animations), but otherwise it's done.