libvips / libvips

A fast image processing library with low memory needs.
https://libvips.github.io/libvips/
GNU Lesser General Public License v2.1
9.79k stars 677 forks source link

vips_colourspace: no known route between 'cmyk' and 'srgb' #152

Closed ferryfax closed 6 years ago

ferryfax commented 10 years ago

Quick question. To avoid this message from vipsthumbnail do I need to supply an appropriate icc profile?

jcupitt commented 10 years ago

This is a bug :( sorry. Fixed with this patch:

https://github.com/jcupitt/libvips/commit/ce428ffa9474949c7a07b8807ab3119c43de3e2f#diff-14bcd9a8c36df55ab0a47dff46affdacR426

ie. import CMYK images right at the start.

It'll be in 7.40.5, due rsn.

ferryfax commented 10 years ago

Hey John, I tried VipsThumbnail from 7.40.5-1 under Windows and got the same error.

Did the fix make it into that version?

jcupitt commented 10 years ago

You'll still get the error if the image has no ICC profile embedded in it. In that case you'll need to provide a profile for vipsthumbnail to use to import the image.

It should now do the right thing if the image does have an embedded profile.

jeromegv commented 10 years ago

Hi, I'm using vips: stable 7.40.10 and I get this error. Is that normal? The image is here: https://infinitely-production.s3.amazonaws.com/uploads/assets/attachment/5187ae04f3317f2f1f00164a/Jacinto_Lirio_kwaderno.jpg

Here's the full metadata of the image

identify -verbose Jacinto_Lirio_kwaderno.jpg

Image: Jacinto_Lirio_kwaderno.jpg Format: JPEG (Joint Photographic Experts Group JFIF format) Mime type: image/jpeg Class: DirectClass Geometry: 4961x3508+0+0 Resolution: 300x300 Print size: 16.5367x11.6933 Units: PixelsPerInch Type: ColorSeparation Endianess: Undefined Colorspace: CMYK Depth: 8-bit Channel depth: cyan: 8-bit magenta: 8-bit yellow: 8-bit black: 8-bit Channel statistics: Pixels: 17403188 Cyan: min: 0 (0) max: 100 (0.392157) mean: 3.0409 (0.0119251) standard deviation: 16.4575 (0.0645393) kurtosis: 25.6952 skewness: 5.25657 Magenta: min: 0 (0) max: 135 (0.529412) mean: 4.28151 (0.0167902) standard deviation: 23.1797 (0.0909008) kurtosis: 25.6952 skewness: 5.25664 Yellow: min: 0 (0) max: 255 (1) mean: 8.29823 (0.0325421) standard deviation: 44.9226 (0.176167) kurtosis: 25.6945 skewness: 5.25658 Black: min: 0 (0) max: 49 (0.192157) mean: 1.50316 (0.00589474) standard deviation: 8.13645 (0.0319076) kurtosis: 25.6944 skewness: 5.2565 Image statistics: Overall: min: 0 (0) max: 255 (1) mean: 4.28095 (0.016788) standard deviation: 26.8905 (0.105453) kurtosis: 61.5876 skewness: 7.59952 Total ink density: 209.02% Rendering intent: Perceptual Gamma: 0.454545 Chromaticity: red primary: (0.64,0.33) green primary: (0.3,0.6) blue primary: (0.15,0.06) white point: (0.3127,0.329) Background color: cmyk(255,255,255,0) Border color: cmyk(223,223,223,0) Matte color: cmyk(189,189,189,0) Transparent color: cmyk(0,0,0,0) Interlace: None Intensity: Undefined Compose: Over Page geometry: 4961x3508+0+0 Dispose: Undefined Iterations: 0 Compression: JPEG Quality: 99 Orientation: Undefined Properties: date:create: 2014-10-04T12:55:45-04:00 date:modify: 2013-05-06T09:20:13-04:00 jpeg:colorspace: 4 jpeg:sampling-factor: 1x1,1x1,1x1,1x1 signature: e2bee6d037910f0b23db5881471ba9e735bfa6e1ac26fad8a6eda20a1b277ed2 Profiles: Profile-8bim: 28 bytes Profile-icc: 557168 bytes Artifacts: filename: Jacinto_Lirio_kwaderno.jpg verbose: true Tainted: False Filesize: 2.595MB Number pixels: 17.4M Pixels per second: 47.04MB User time: 0.370u Elapsed time: 0:01.370 Version: ImageMagick 6.8.9-7 Q16 x86_64 2014-08-31 http://www.imagemagick.org

jcupitt commented 10 years ago

It should work, I see this:

$ vipsthumbnail --vips-info Jacinto_Lirio_kwaderno.jpg 
info: vipsthumbnail: thumbnailing Jacinto_Lirio_kwaderno.jpg
info: vipsthumbnail: selected loader is VipsForeignLoadJpegFile
info: vipsthumbnail: loading jpeg with factor 8 pre-shrink
info: vipsthumbnail: importing with embedded profile
info: vipsthumbnail: converting to processing space srgb
info: vipsthumbnail: integer shrink by 2
info: vipsthumbnail: anti-alias, sigma 1.28125
info: vipsthumbnail: residual scale by 0.412903
info: vipsthumbnail: bicubic interpolation
info: vipsthumbnail: converting to sRGB
info: vipsthumbnail: sharpening thumbnail
info: vipsthumbnail: thumbnailing Jacinto_Lirio_kwaderno.jpg as ./tn_Jacinto_Lirio_kwaderno.jpg
$ vipsthumbnail --vips-version
libvips 7.40.10-Sun Oct  5 09:29:34 BST 2014

What command did you run?

jeromegv commented 10 years ago

I'm using sharp https://github.com/lovell/sharp, which is using libvips

jcupitt commented 10 years ago

Sorry, then I don't know. Have you tried opening an issue there?

tomasc commented 8 years ago

First, @jcupitt, congratulations on the fantastic library!

I am running into the vips_colourspace: no known route between 'cmyk' and 'srgb' issue with libvips 8.3.3 on debian 8.5.

I am trying to convert a page from a PDF to JPG. The conversion works fine with the same file and same libvips version on OS X.

The exact command:

vipsthumbnail my.pdf[page=5] -o out.jpg -s 595x842

The errors:

vipsthumbnail: unable to thumbnail my.pdf[page=5]
vips_colourspace: no known route between 'cmyk' and 'srgb'

Is it possible I am missing a library handling this conversion on the server? (I checked and I do have both liblcms2-2:amd64 as well as liblcms2-dev:amd64 installed.)

Thank you for your help.

jcupitt commented 8 years ago

Hi @tomasc, libvips now has two ways to import PDF files, I think your two installs are using different paths.

The old way is via libMagick. This uses (in turn) gs to import CMYK PDFs as true CMYK images, so you'll need to get a profile from somewhere if you want to convert to sRGB for save.

The new way is via libpoppler and the pdfload operation. This is much, much faster and more memory efficient, but it always generates an sRGB image, it cannot make CMYK.

Unless you really need exact CMYK values, I would suggest the new libpoppler route. I would check for poppler-glib on the linux server.

tomasc commented 8 years ago

hi @jcupitt thanks a lot for getting back to me so quickly. i saw your posts re poppler & pdf so i took care to install libpoppler-glib-dev, libpoppler-glib8 etc. and indeed i have libmagic installed as well. could it be that the libmagic takes precedence? is there a way to enforce the use of poppler or do i simply need to uninstall everythig related to libmagic?

jcupitt commented 8 years ago

libMagick will always come last. Check the output of configure and make sure you have something like:

PDF import with poppler-glib:       yes
  (requires poppler-glib 0.16.0 or later)

near the end. You can verify that poppler really is being used to read your PDFs with vipsheader. You should see:

$ vipsheader nipguide.pdf 
nipguide.pdf: 595x841 uchar, 4 bands, srgb, pdfload

ie. the libpoppler pdfload operation was used to load the image. You'll see something like:

$ vipsheader dicom_test_image.dcm 
dicom_test_image.dcm: 128x128 ushort, 1 band, grey16, magickload

if it's libMagick.

tomasc commented 8 years ago

@jcupitt you're right!

595x842 ushort, 4 bands, cmyk, magickload

I will try to recompile, hope that solves the issue.

jcupitt commented 8 years ago

Yes, you must reconfigure vips after installing libpoppler-glib-dev.

tomasc commented 8 years ago

@jcupitt thanks again for help, i compiled libpoppler from source (there is no >= 0.3 version package for debian jessie for example), recompiled vips and eveything now works perfectly.

jcupitt commented 8 years ago

Good to hear!

I noticed your dragonfly with vips, it looks nice. Did you consider using ruby-vips rather than a command-line interface? It should be possible to get a useful speedup by calling the library directly.

tomasc commented 8 years ago

Interesting!

What the dragonfly gems do is that they chain processing of files -- they convert one tempfile into another. Intuitively I thought command line would be fastest for this (esp. knowing ruby is not particularly known for its performance). Besides wouldn't I have to reimplement all the nice work you did for vipsthumbnail? Why do you think that using the ruby-vips would be more performant?

jcupitt commented 8 years ago

It depends what you are doing. For thumbnailing, ruby-vips would be no faster, but if you are doing more complex processing, like watermarking or adding a drop shadow, ruby-vips will be a lot quicker.

The command-line interface runs operations one after the other, with a lengthy read phase and write phase between each one as images are written to temp files and then immediately read back in.

ruby-vips can use the libvips chaining mechanism. If you run a sequence of operations in ruby-vips, perhaps:

im = Vips::Image.new_from_file "test.tif", :access => :sequential
text = Vips::Image.text "Hello world!", :dpi => 300
text = (text * 0.3).cast(:uchar)
text = text.embed 100, 100, text.width + 200, text.height + 200
text = text.replicate 1 + im.width / text.width, 1 + im.height / text.height
text = text.crop 0, 0, im.width, im.height
im = text.ifthenelse [255, 0, 0], im, :blend => true
im.write_to_file "out.tif"

(the watermarking example), ruby-vips will not actually execute any of the operations until you reach the final .write_to_file, it just constructs an image-processing pipeline. When you execute the final write, the whole pipeline runs at the same time, all in parallel. This gives a huge speedup on systems with many cores. Moreover, there's no load/save between operations, which gives another big speedup. And finally the images are streamed, ie. they pass through the pipeline in small 128x128 pixel chunks, so there's an enormous memory saving too.

I'll try a command-line version of that thing and time it, hang on.

jcupitt commented 8 years ago

Here's watermarking in sh and ruby-vips:

#!/usr/bin/ruby

require 'vips'

im = Vips::Image.new_from_file ARGV[0], :access => :sequential
text = Vips::Image.text ARGV[2], :dpi => 300
text = (text * 0.3).cast(:uchar)
text = text.embed 100, 100, text.width + 200, text.height + 200
text = text.replicate 1 + im.width / text.width, 1 + im.height / text.height
text = text.crop 0, 0, im.width, im.height
im = text.ifthenelse [255, 0, 0], im, :blend => true
im.write_to_file ARGV[1]
#!/bin/bash

infile=$1
outfile=$2
str="$3"

# make text mask
vips text t1.v "$str" --dpi 300
vips linear t1.v t2.v 0.3 0
vips cast t2.v t1.v uchar

text_width=$(vipsheader -f width t1.v)
text_height=$(vipsheader -f height t1.v)

text_width=$((text_width + 200))
text_height=$((text_height + 200))
vips embed t1.v t2.v 100 100 $text_width $text_height

im_width=$(vipsheader -f width $infile)
im_height=$(vipsheader -f height $infile)

across=$((1 + im_width / text_width))
down=$((1 + im_height / text_height))

vips replicate t2.v t1.v $across $down
vips crop t1.v text.v 0 0 $im_width $im_height

# make solid colour
vips black t1.v 1 1
vips linear t1.v t2.v 1 "255 0 0"
vips cast t2.v t1.v uchar
vips embed t1.v colour.v 0 0 $im_width $im_height --extend copy

# combine
vips ifthenelse text.v colour.v $infile $outfile --blend

With a large image on my little two-core laptop, I see:

$ time ./watermark.rb ~/pics/wtc.jpg x.tif "hello world"
real    0m2.006s
user    0m3.852s
sys 0m0.280s
$ time ./watermark.sh ~/pics/wtc.jpg x.tif "hello world"
real    0m3.867s
user    0m4.384s
sys 0m1.340s

So about a 2x speedup. It would be more on a larger machine, I expect.

jcupitt commented 8 years ago

Last post: of course you could keep shelling out to run vipsthumbnail, but implement other stuff in ruby-vips, perhaps.

tomasc commented 8 years ago

I see, that's very good, solid performance gain. I will def. switch over to ruby for some more complex operations. Thanks a lot for the explanation.

BTW I thought it would be very nice to have some of the image magick's geometry behaviour implemented in the vipsthumbnail – for example ability to specify width or height only (NNx and xNN) and no resize when source is larger or smaller (NNxNN> and NNxNN<) – see http://www.imagemagick.org/script/command-line-processing.php#geometry

Would you be open for adding these? I wrote the necessary calculations here in Ruby https://github.com/tomasc/dragonfly_libvips/blob/master/lib/dragonfly_libvips/dimensions.rb and would like to help to get them included vipsthumbnail as these seem to be frequently used when generating image thumbnails.

jcupitt commented 8 years ago

Sure, why not, open a new issue and tag it as an enhancement.

tomasc commented 8 years ago

Great, I posted as #503 but can't seem to be able to add labels. Let me know if I can help implementing this.

andrews05 commented 6 years ago

Run into this problem myself for a cmyk image with no profile. Is the some way I can tell it to use a default profile or something? I mean, if I don't know in advance whether the image has a profile or not, how can I provide a default profile without overriding any existing one?

jcupitt commented 6 years ago

Hello @andrews05, sure, you can give a fallback profile to thumbnail:

http://jcupitt.github.io/libvips/API/current/libvips-resample.html#vips-thumbnail

From the command-line, for example:

$ vips thumbnail cmyk.tif x.jpg 128 --import-profile generic-cmyk.icm

And it'll use the generic profile you specify if the TIFF file does not have oine embedded.

jcupitt commented 6 years ago

In case anyone stumbles across this old issue -- thanks to work by tomasc, since libvips 8.5 you can give geometry specifications like 128x> or '99x99!tovipsthumbnail`.

andrews05 commented 6 years ago

Thank you. Is it possible to use thumbnail without changing the colorspace? Just keep a cmyk image as cmyk, without having to specify any profiles.

[edit] To clarify, here's how things are working to the best of my understanding: If I thumbnail a cymk image with a profile, output is cmyk. If it has no profile, it complains about "no known route". If I provide a cmyk import profile, output is rgb. If I provide both an import and an export profile, output is cmyk, but this will throw errors if the input was actually rgb. My ideal world: A single set of options that can thumbnail all images, with either a) all retaining their colorspace, or b) all being converted to rgb. Sorry, I don't understand a whole lot about this stuff, all I know is imagemagick never required me to specify profiles :)

jcupitt commented 6 years ago

Hello again, it does the shrinking in RGB colourspace, so CMYK images are actually processed as CMYK -> RGB -> CMYK. This is because CMYK is very non-linear and simply averaging pixels gives ugly results.

You're right, to get the behaviour you want at the moment you need a separate command for CMYK images.

I'll have a think, perhaps this can be improved.

jcupitt commented 6 years ago

I think I found an improvement! icc_import was not attaching the fallback profile to the output image if it used it, so thumbnail was unable to get back to CMYK. I've added a thing to 8.6 to fix this and I now see:

john@kiwi:~/pics$ vipsthumbnail cmyk-no-profile.jpg 
vipsthumbnail: unable to thumbnail cmyk-no-profile.jpg
vips_colourspace: no known route from 'cmyk' to 'srgb'
john@kiwi:~/pics$ vipsthumbnail cmyk-no-profile.jpg --iprofile ~/GIT/nip2/share/nip2/data/cmyk.icm 
john@kiwi:~/pics$ vipsheader tn_cmyk-no-profile.jpg 
tn_cmyk-no-profile.jpg: 128x85 uchar, 4 bands, cmyk, jpegload

So it's picking up the fallback profile to get back to CMYK again after the thumbnail operation.

This change will be in 8.6.3, due in a few days. Thanks!

andrews05 commented 6 years ago

Sounds great, that should be a big help.

gertcuykens commented 6 years ago

Testfile: https://drive.google.com/file/d/1b7FzZZKJhrLnlb-5bYsUwuzRSEhKltBA/view?usp=sharing Version: vips-8.6.4-Wed Jun 13 15:24:52 UTC 2018

cli command: vips colourspace test_CMYK.jpg rgb.jpeg srgb vips_colourspace: no known route from 'cmyk' to 'srgb'

Did I do something wrong to convert to srgb or rgb?

jcupitt commented 6 years ago

Hello, convert CMYK jpg images to sRGB like this:

$ vips icc_transform cmyk.jpg x.jpg /usr/share/color/icc/colord/sRGB.icc 

That's assuming your jpg image has an embedded CMYK profile.

libvips does not have a built-in CMYK -> $x converter, you need to use lcms via the icc_import / icc_export / icc_transform operations.

gertcuykens commented 6 years ago

Ok thx both cli's are working

vips icc_transform test_CMYK.jpg rgb.jpg ../icc/RGB/AppleRGB.icc

and

vips icc_import test_CMYK.jpg rgb.jpg --input-profile icc/CMYK/USWebCoatedSWOP.icc

icc_import replaces the color profile selected but also to color space RGB, i expected it would have kept the CMYK color space?

jcupitt commented 6 years ago

icc_import takes the image to PCS (CIELAB by default). When you write a CIELAB image to JPG, libvips uses an internal converter to make sRGB for you. Try:

john@yingna ~/pics $ vips icc_import cmyk.jpg x.v
john@yingna ~/pics $ vipsheader -a x.v
x.v: 1419x1001 float, 3 bands, lab, jpegload
width: 1419
height: 1001
bands: 3
format: float
coding: none
interpretation: lab
xoffset: 0
yoffset: 0
xres: 11.808
yres: 11.808
filename: x.v
vips-loader: jpegload
jpeg-multiscan: 0
jpeg-chroma-subsample: 4:4:4:4
exif-data: 186 bytes of binary data
resolution-unit: in
...
icc-profile-data: 961644 bytes of binary data

So the vips format image still has the CMYK profile, it's the implicit conversion to RGB on jpg write that drops it.

gertcuykens commented 6 years ago

Thx ps is their a way to get the vipsheader output when using govips that you can tell at first look ?

https://godoc.org/github.com/davidbyttow/govips/pkg/vips

Or do I need to find a other go wrap library specifically for vipsheader?

jcupitt commented 6 years ago

Sorry, I don't know, I didn't make govips, you would need to ask there. In Python, for example, it's image.get('icc-profile-data'). Maybe something similar?

Please open a new issue if you have a new question: it'll make it easier for others to find answers.

adityapatadia commented 6 years ago

@jcupitt I am checking if this bug also affected icc_transform. Currently, nodejs library Sharp is using it and I see error vips_colourspace: no known route from 'srgb' to 'cmyk' when I try to convert to CMYK with that library.

Sharp is currently not using 8.6.3 so just checking if updating libvips will solve issue for sharp.

jcupitt commented 6 years ago

Please don't post on closed issues, it just causes confusion.

It's not really a bug -- colourspace just can't convert to CMYK. Use icc_transform plus a profile instead.

adityapatadia commented 6 years ago

Sorry I missed your last comment. I will create new one if I need further information.