libvips / php-vips

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

thumbnail_image converts CMYK image to RGB #138

Closed AdamGaskins closed 2 years ago

AdamGaskins commented 2 years ago

Hey, thanks so much for this project! It has been a pleasure to use so far.

I'm finding that these lines of code are outputting an RGB image, when my source is a CMYK with an embedded profile:

$image = VipsImage::newFromFile('input.jpeg');
$image = $image->thumbnail_image(1000);
$image->writeToFile('output.jpeg', [ 'Q' => 95 ]);

If I remove the thumbnail_image call, the output is CMYK. It looks like thumbnail_image may have import-profile and export-profile options? But I'm not sure what they do, or how to get the profile from the image. Is there some way to tell it to just keep the image in whatever color format it is in? RGB should stay RGB, and CMYK should stay CMYK.

jcupitt commented 2 years ago

Hi @AdamGaskins,

Yes, you need to set the output profile. By default, libvips will use an sRGB output profile, since CMYK profiles can be so large (eg. 500kb is not uncommon), and of course most people want thumbnails to be small.

You can do something like this:

$image = Vips\Image::new_from_file("something.jpg");
if ($image->interpretation == "cmyk") {
    $profile = "cmyk";
}
else if ($image->interpretation = "srgb") {
    $profile = "srgb";
}
else {
    unknown profile error
}

$thumbnail = Vips\Image::thumbnail("something.jpg", 1000, [
    "export-profile" => $profile
]);

Don't use thumbnail_image, it's only for emergencies. Plain thumbnail will be many times faster.

jcupitt commented 2 years ago

The main docs are here, in case you didn't see them:

https://www.libvips.org/API/current/libvips-resample.html#vips-thumbnail

AdamGaskins commented 2 years ago

Thanks for the response!! Here is the code I'm using based on yours:

    $image = VipsImage::newFromFile($input);
    $profile = 'srgb';
    if ($image->interpretation == 'cmyk') {
        $profile = 'cmyk';
    }

    $image = \Jcupitt\Vips\Image::thumbnail($input, 1000, [ 'export-profile' => $profile ]);
    $image->writeToFile($output, [ 'Q' => 95 ]);

It works fine for RGB images, but CMYK gives this warning:

(process:51830): VIPS-WARNING **: 08:49:44.160: profile incompatible with image

The output file is indeed in CMYK, but it has an incorrect profile and colors. (Here is the image I'm using)

In messing around I weirdly found this code seems to work, but I may be completely off and I would definitely prefer to use thumbnail since that seems to be the intended way:

            $image = VipsImage::newFromFile('input.jpeg');
            $image = $image->icc_import();
            $image = $image->thumbnail_image($pixelSize);
            $image = $image->icc_export();
            $image->writeToFile('output.jpeg', [ 'Q' => 95 ]);
jcupitt commented 2 years ago

Oooof, I think you've found a bug in thumbnail. I'll investigate.

jcupitt commented 2 years ago

OK, I think I fixed it. This improvement will be in 8.12.3, thanks for the report!

I now see:

$ vipsheader cmyk5.jpg 
cmyk5.jpg: 3654x4577 uchar, 4 bands, cmyk, jpegload
$ vipsthumbnail cmyk5.jpg --export-profile cmyk
$ vipsheader tn_cmyk5.jpg 
tn_cmyk5.jpg: 102x128 uchar, 4 bands, cmyk, jpegload

ie. the thumbnail is cmyk in this case.

Your embedded profile is 500kb, so it's a huge thumbnail image, which might not be what you want.

AdamGaskins commented 2 years ago

Ahh okay, thank you so much! Really impressed by the quick response and fix!!

Your embedded profile is 500kb, so it's a huge thumbnail image, which might not be what you want.

Yeah... that's what I told the user too, but they insisted they need the profile embedded 🤷🏻‍♂️