Page 1 of 1

Help needed with implementing color profile support

Posted: 2015-06-11T04:26:09-07:00
by MTumrK
Hello!

I wish to implement color profile support in a simple bash script of mine which makes use of ImagMagick's convert.
The script currently looks as follows:

Code: Select all

    local ImgColorSpace=$(identify -format "%[colorspace]" "$InputDir/$Img")
    local ImgColorProfile="$sRGBColorProfile"
    if [ -n "$(identify -format "%[profile:icc]" "$InputDir/$Img")" ]; then
        convert "$InputDir/$Img" "$InputDir/$Img.icc"
        ImgColorProfile="$InputDir/$Img.icc"
    elif [ -n "$(identify -format "%[profile:icm]" "$InputDir/$Img")" ]; then
        convert "$InputDir/$Img" "$InputDir/$Img.icm"
        mv "$InputDir/$Img.icm" "$InputDir/$Img.icc"
        ImgColorProfile="$InputDir/$Img.icc"
    fi
    # Call to convert:
    convert "$InputDir/$Img" \
        -quality 100% \
        -depth 16 \
        -colorspace RGB \
        +sigmoidal-contrast 6.5 \
        -gravity Center -crop 'x4272+0+0>' +repage \
        -filter Mitchell -resize 'x4731<' \
        -background White -gravity Center -extent '3197x4803' +repage \
        -sigmoidal-contrast 6.5 \
        -colorspace "$ImgColorSpace" \
        "$InputDir/$Img.tmp"
and you may assume that "$InputDir/$Img" is an URI pointing to an existing image in portrait orientation (2848x4288) and that "$sRGBColorProfile" is an URI pointing to a generic sRGB ICC profile.

I have already consulted the documentation about how one should deal with color profiles and have come up with a solution (attempt), where I am replacing the convert-call with the following:

Code: Select all

    convert "$InputDir/$Img" \
        -quality 100% \
        -depth 16 \
        -profile "$sRGBColorProfile" \
        -colorspace RGB \
        +sigmoidal-contrast 6.5 \
        -gravity Center -crop 'x4272+0+0>' +repage \
        -filter Mitchell -resize 'x4731<' \
        -background White -gravity Center -extent '3197x4803' +repage \
        -sigmoidal-contrast 6.5 \
        -profile "$ImgColorProfile" \
        "$InputDir/$Img.tmp"
Now the following should happen:
If the image has no embedded profile, it will simply assign one without changing the pixels' values. It will then convert to linear RGB and do an upscaling transformation inspired by http://www.imagemagick.org/Usage/filter/nicolas/ (there is also some cropping and extending going on, but I do not think I have to explain the purpose of this for my question. The fact that those commands are present might be part of the problem, however) and then convert to the generic sRGB profile afterwards.
If, on the other hand, the image has an embedded profile, the first profile call will convert the pixels' values to what they should look like given the generic sRGB profile (in order to approximate what I get by -colorspace sRGB; as far as I understand, if I omit this step, the conversion to the linear RGB space should produce faulty values) and only then convert to linear RGB color space and proceed with the same transformations as above. Afterwards, it will convert from linear RGB color space back to the original color profile.
What happens in practice, is that the image will loose its color profile. However, a minimal example, where I am omitting the cropping, upsampling and extent-call, does work as expected.

During further research in the forums, I found out that one has to be careful with the command line options and should adhere to the structure described in http://www.imagemagick.org/script/comma ... essing.php. According to this page, the two +repage settings, are illegal, since they should be given before the operators. However, they have to be there for the script to work. And while I have encountered examples in the documentation that differ from the anatomy described in the above link (for example the -fill setting in the first example given in this very linked page), I do believe that this is the root cause of the problem.
In an attempt to solve the problem, I then tried to cluster the different parts (cropping, upsampling, extent-call) using composite (http://www.imagemagick.org/Usage/compose/), however I was not able to come up with a working solution. (That was some time ago and sadly I did not save my attempts, so I have nothing to show.)

I was hoping that one of you might be able to help me identify and solve the problem?

Re: Help needed with implementing color profile support

Posted: 2015-06-11T05:17:26-07:00
by snibgo
I'm not sure I understand the problem. However, I see you "-colorspace RGB" to convert to linear, but you don't "-colorspace sRGB" to convert back to non-linear. Perhaps this causes your problem?

Re: Help needed with implementing color profile support

Posted: 2015-06-11T09:52:35-07:00
by fmw42
You do not say what version of IM and platform you are using? Some older versions of IM used RGB to mean sRGB and vice versa.

Re: Help needed with implementing color profile support

Posted: 2015-06-11T12:06:54-07:00
by MTumrK
First of all, thank you for your replies!

fmw42: Thanks for reminding me! I am using ImageMagick 6.8.9-8 Q16 x86_64 (output from identify -version), so the -colorspace bug regarding sRGB and RGB is not present.

snibgo: Regarding the problem that I had: I had one base image and two JPEGs that were created from it: One, which was converted to Adobe RGB and had a matching embedded color profile, and one that was converted to sRGB IEC61966-2.1 and had a matching embedded color profile. In an image viewer that I used during testing and that can not handle color profiles, the two images did indeed look different, as was to be expected.
When resizing the Adobe RGB image using my script, the output had no embedded ICC profile and looked (in the viewer I mentioned above) just like the sRGB image, meaning that only the first -profile "$sRGBColorProfile" worked but not the operator that should have converted it back to Adobe RGB (and embedded the profile), which is what I wanted my script to do!

However, your guess that it had something to do with the fact that I have no -colorspace sRGB operator before the second -profile operator was correct! My guess is that the fact that I converted to linear RGB caused ImageMagick to disregard the "$sRGBColorProfile" profile. When afterwards trying to do a color conversion using -profile, that conversion failed because it probably needed a profile to exist for that. However, as I understand, ImageMagick should have then embedded the profile without converting. As I described above this has not happened. I believe that this is due to the fact it realized that there will be trouble if it assigns a profile working with the sRGB color space to an image in the linear RGB color space. (But I don't know for sure and would love to get some input from the devs on this!)
So indeed, the following code will work for my test images:

Code: Select all

    local ImgColorSpace=$(identify -format "%[colorspace]" "$InputDir/$Img")
    local ImgColorProfile="$sRGBColorProfile"
    if [ -n "$(identify -format "%[profile:icc]" "$InputDir/$Img")" ]; then
        convert "$InputDir/$Img" "$InputDir/$Img.icc"
        ImgColorProfile="$InputDir/$Img.icc"
    elif [ -n "$(identify -format "%[profile:icm]" "$InputDir/$Img")" ]; then
        convert "$InputDir/$Img" "$InputDir/$Img.icm"
        mv "$InputDir/$Img.icm" "$InputDir/$Img.icc"
        ImgColorProfile="$InputDir/$Img.icc"
    fi
    # Call to convert:
    convert "$InputDir/$Img" \
        -quality 100% \
        -depth 16 \
        -profile "$sRGBColorProfile" \
        -colorspace RGB \
        +sigmoidal-contrast 6.5 \
        -gravity Center -crop 'x4272+0+0>' +repage \
        -filter Mitchell -resize 'x4731<' \
        -background White -gravity Center -extent '3197x4803' +repage \
        -sigmoidal-contrast 6.5 \
        -colorspace sRGB \
        -profile "$sRGBColorProfile" \
        -profile "$ImgColorProfile" \
        "$InputDir/$Img.tmp"
As far as I understand color profiles, I am now able to convert images in sRGB color space and images in any color space, provided that those images have an embedded color profile. Meaning if I were to provide default profiles for other color spaces, I could also treat images in those color spaces with no embedded profile. (If I am deliberately assuming a specific profile and forcefully assigning it, there might of course be some errors, when the input has no embedded profile or the embedded profile got accidentally scrubbed, but that case is not relevant to me.)

One thing that still bothers me is that I am currently not able to convert to linear RGB using color profiles only. (As you can see, instead I am relying on "$sRGBColorProfile" to convert to a "default" sRGB space, namely sRGB IEC61966-2.1, and hope that from that sRGB space, the image will be indeed be in a linear color space after -colorspace RGB has been applied.)
Is there a way to do this using profiles alone and get rid of the -colorspace operators?

Re: Help needed with implementing color profile support

Posted: 2015-06-11T12:40:26-07:00
by snibgo
There are various profiles that claim to be linear RGB. I've never tried them because "-colorspace" works fine for me.

IM sometimes seems to forget that an image is encoded with an sRGB profile. It doesn't have this problem with other profiles. Perhaps it is over-enthusiastic about optimising storage requirements, but I haven't pinned down this issue.