Page 1 of 1

conversion w. ICC-Profiles behave different on dif. machines

Posted: 2014-04-07T02:13:58-07:00
by horst
Hello,

I use cms with ICC-Profiles with Imagick on my local windows and it works really fine. Input can be any file regardless of colordepth, colorspace and if it has an embedded profile or not.

Input is the embedded profile or a config-defined default profile per colorspace (rgb gray cmyk).

As workspace I use 16bit AdobeRGB (or 16bit ECI-RGB) and destination after all manipulations is 8bit sRGB.


Now I have uploaded this to an online shared host and got a bad surprise: all CMS stuff do not work on that machine. All color images are multiple times to bright. The colortransfer via profiles do not work, not one single case.

On my local windows machine I use ImageMagick 6.8.8-4 Q16 x86 2014-01-29

The online ubuntu machine has ImageMagick 6.6.9-7 2014-03-06 Q16

Methods I use is (simplyfied):

Code: Select all

            $im->profileImage('icc', $imageMetadata['icc']);  // assign the individual profile
            $im->profileImage('icc', $iccWorkspace);
            $im->setImageColorspace(Imagick::COLORSPACE_RGB);
Any ideas why it doesn't work on the second machine?

You can see output from my local machine here: https://processwire.com/talk/topic/5889 ... entry58679
and the online machine is here: http://images.pw.nogajski.de/imagick-re ... ms-visual/

Re: conversion w. ICC-Profiles behave different on dif. mach

Posted: 2014-04-09T05:32:49-07:00
by horst
Hi,
regarding my first post, is this an issue with the version being 6.6.9 or do you need more information?
I don't wanted to paste a whole bunch of code into my first post.
Also it is obvious that the code (can) work, at least with the version 6.8.8, so, I have provided example output.
As I'm new to ImageMagick & Imagick and also new to this forums, it would be nice to get an answer, also if this is the first time that that behave occurs and nobody knows nor has a clue why. - I'm actually a little helpless on this. We want to use this within a PHP CMF/CMS so I need to know where and why this work or work not. :)

Re: conversion w. ICC-Profiles behave different on dif. mach

Posted: 2014-04-09T09:35:08-07:00
by fmw42
If it works on the newer version and not on the older version, it is likely a bug in the older version or you have different delegate versions. If you are using cms (lcms), that may be an issue, though I am not sure why it would affect profiles. Version 6.6.9 is 200 versions old. It may be best to upgrade.

Check your versions of your delegate libraries.

try

convert -list format

and see what versions are being used.

Also

convert -list configure

and see what DELEGATES are being used.

Or check the delegates and their versions directly.

Re: conversion w. ICC-Profiles behave different on dif. mach

Posted: 2014-04-11T06:32:07-07:00
by horst
Many thanks for helping out, Fred.

I have checked the configure and delegates files, both versions have listed lcms, but nothing about a version of lcms.
Also lcms is listed in configure.xml as a delegate lib, but in the delegates.xml ist isn't present (it's the same in both installations).

Also the problem cannot be solved with updating the version, because we want to use this in a CMF/CMS that is used on many different servers by different users. I have to write that module that it detects what is possible on the server it is running on and if ICC-CMS could not be used, have a fallback for older versions.

Also actually I don't really know some differences between available functions in Imagick. It would be useful if there is some tutorial or write up that explains for example when to use setColorspace or setImageColorspace especially in different versions. I have read about older versions that don't have the setImage*** functions but only set***. It would be useful to know how the versions do handle this. Actually it is a bit confusing to me. So with the newer version I think I mostly have understand how it works and set it up mostly right. But maybe my code isn't good and only the newer image magick version are more fault-tolerant? Maybe I should post some code here?

Re: conversion w. ICC-Profiles behave different on dif. mach

Posted: 2014-04-11T10:03:03-07:00
by fmw42
I am sorry, I don't think I can help much further. I am not a PHP / Imagick expert. You may have to dig further into your directories to find where LCMS is located to find the version.

Some issue with IM cannot be fixed without upgrading. I am not sure if that is your problem or not. But 6.6.9 is very old and I have seen other bugs that people have reported for that version.

Re: conversion w. ICC-Profiles behave different on dif. mach

Posted: 2014-04-12T08:21:22-07:00
by horst
Hi, regarding to old versions, I can tell you that the hoster holds 3 different (major) versions:

Code: Select all

Pfad zu ImageMagick 4.2.9: /usr/bin/ImageMagick_4.2.9/ (für Typo3)
Pfad zu ImageMagick 5.5.4: /usr/bin/
Pfad zu ImageMagick 6.2.6: /usr/bin/ImageMagick_6.2.6/bin/
But the named 6.2.6 actually is the 6.6.9 versions I have to use.

For now we have solved it in that way that we only use the ICC-conversion method if the user has manually enabled it. This may be changed after we have collected more informations about usable versions.

But also I have had some quirks code. Before, I have used mixed functions: individual ICC-conversion and some from the more generic color management. That must have screwed up the images. The newer ImageMagick versions indeed seem to be more fault-tolerant by handling inaccurate code. GOOD WORK GUYS! :)

So, on the 6.6.9 server the ICC-conversion now is working fine.
The basic conversion only need to be enhanced to support cmyk too. But we are glad to have the first working version of our new module.

I post the code here, if someone is interested. It is a part from our new module, so not working out of the box, but hopefully a good starting point:

Code: Select all

        // start image magick
        $this->im = new Imagick();

        // should we use the ICC-CMS ?
        $this->useCMS = $this->data['useCMS'] ? true : false;

        // set the working colorspace: COLORSPACE_RGB or COLORSPACE_SRGB    ( whats about COLORSPACE_GRAY ??)
        $this->workspaceColorspace = $this->useCMS ? Imagick::COLORSPACE_RGB : Imagick::COLORSPACE_SRGB;
        $this->im->setColorspace($this->workspaceColorspace);

        // load the image
        if(!$this->im->readImage($this->destFilename)) {  // actually we get a filecopy from origFilename to destFilename from PageImage
            $this->release();
            throw new WireException(sprintf(__("Imagick cannot load imagefile: %s", basename($this->destFilename))));
            return false;
        }

        // check validity against image magick
        if(!$this->im->valid()) {
            throw new WireException(sprintf(__("loaded file '%s' is not a valid image", basename($this->destFilename))));
            return false;
        }

        // get image format
        $this->imageFormat = $this->im->getImageFormat();

        // check validity against PW
        if(!in_array($this->imageFormat, $this->validSourceImageFormats())) {
            throw new WireException(sprintf(__("loaded file '%s' is not in the list of valid images", basename($this->destFilename))));
            return false;
        }

        // check and retrieve different image parts and information: ICC, Colorspace, Colordepth, Metadata, etc
        $this->imageColorspace = $this->im->getImageColorspace();
        $this->workspaceColorspace = IMAGICK::COLORSPACE_GRAY == $this->imageColorspace ? IMAGICK::COLORSPACE_GRAY : $this->workspaceColorspace;
        $this->im->setColorspace($this->workspaceColorspace);
        $this->imageMetadata = $this->im->getImageProfiles('*');
        if(!is_array($this->imageMetadata)) $this->imageMetadata = array();
        $this->hasICC = array_key_exists('icc', $this->imageMetadata);
        $this->hasIPTC = array_key_exists('iptc', $this->imageMetadata);
        $this->hasEXIF = array_key_exists('exif', $this->imageMetadata);
        $this->hasXMP = array_key_exists('xmp', $this->imageMetadata);
        $this->imageType = $this->im->getImageType();
        $this->imageDepth = $this->im->getImageDepth();

        // remove not wanted / needed Metadata
        foreach(array_keys($this->imageMetadata) as $k) {
            if('icc'==$k) continue;  // we keep embedded icc profiles
            if('iptc'==$k) continue;  // we keep embedded iptc data
            if('exif'==$k && $this->data['keepEXIF']) continue; // we have to keep exif data too
            if('xmp'==$k && $this->data['keepXMP']) continue; // we have to keep xmp data too
            $this->im->profileImage("$k", null); // remove this one
        }

        $this->im->setImageDepth(16);
        if($this->useCMS) {
            $this->useCMS = $this->iccCmsStart();
        }

// now do all manipulations here ...

        // manipulations are finished, prepare for saving
        if($this->useCMS) {
            $this->iccCmsFinish();
        }
        $this->im->setImageDepth(($this->imageDepth > 8 ? 8 : $this->imageDepth));

        // should we strip ICC-Profiles?
        if(!$this->data['keepICC']) {
            $this->im->setImageProfile('icc', null);
        }

        $this->im->setImageFormat($this->imageFormat);
        $this->im->setImageType($this->imageType);
        if(in_array(strtoupper($this->imageFormat), array('JPG', 'JPEG'))) {
            $this->im->setImageCompressionQuality($this->quality);
            $this->im->setImageCompression(IMAGICK::COMPRESSION_JPEG);
        }
        else {
            $this->im->setImageCompressionQuality($this->quality);
        }

        // save to file
        if(!$this->im->writeImage($this->destFilename)) {
            $this->release();
            return false;
        }

        return true;

The methods for the icc-conversions are:

Code: Select all

    protected function iccCmsStart() {
        if(!$this->useCMS) {
            return false;
        }

        // check if we have an ICC Workspaceprofile and a RGB-Targetprofile
        $tmpName = dirname(__FILE__) . '/icc/targetprofiles/' . $this->data['rgbOutProfile'];
        if(is_file($tmpName) && 'icc'==strtolower(pathinfo($tmpName, PATHINFO_EXTENSION))) {
            $this->iccRgbOut = file_get_contents($tmpName);
        }
        $this->useICC = isset($this->iccRgbOut) ? true : false;
        $tmpName = dirname(__FILE__) . '/icc/workspaceprofiles/' . $this->data['workspaceProfile'];
        if($this->useICC && is_file($tmpName) && 'icc'==strtolower(pathinfo($tmpName, PATHINFO_EXTENSION))) {
            $this->iccWorkspace = file_get_contents($tmpName);
        }
        else {
            $this->useICC = false;
        }
        unset($tmpName);
        $this->useGray = false;


        if($this->useICC && $this->hasICC) {
            if(IMAGICK::COLORSPACE_GRAY == $this->imageColorspace) {
                $tmpName = dirname(__FILE__) . '/icc/grayscaleprofiles/' . $this->data['grayOutProfile'];
                if(is_file($tmpName) && 'icc'==strtolower(pathinfo($tmpName, PATHINFO_EXTENSION))) {
                    $this->iccGrayOut = file_get_contents($tmpName);
                }
                unset($tmpName);
                $this->useGray = isset($this->iccGrayOut) ? true : false;
            }
            #$this->im->profileImage('icc', $this->imageMetadata['icc']);  // that profile is the embedded one from the image, seems we don't need to process that here
            $this->im->profileImage('icc', $this->iccWorkspace);
            $this->im->setImageColorspace(Imagick::COLORSPACE_RGB);
            return true;
        }
        elseif($this->useICC && !$this->hasICC) {
            if(in_array($this->imageColorspace, array(IMAGICK::COLORSPACE_SRGB, IMAGICK::COLORSPACE_RGB))) {
                $tmpName = dirname(__FILE__) . '/icc/targetprofiles/' . $this->data['rgbInProfile'];
                if(is_file($tmpName) && 'icc'==strtolower(pathinfo($tmpName, PATHINFO_EXTENSION))) {
                    $this->iccRgbIn = file_get_contents($tmpName);
                }
                if(!isset($this->iccRgbIn)) {
                    $tmpName = dirname(__FILE__) . '/icc/workspaceprofiles/' . $this->data['rgbInProfile'];
                    if(is_file($tmpName) && 'icc'==strtolower(pathinfo($tmpName, PATHINFO_EXTENSION))) {
                        $this->iccRgbIn = file_get_contents($tmpName);
                    }
                }
                if(isset($this->iccRgbIn)) {
                    $this->im->profileImage('icc', $this->iccRgbIn);  // assign the RGB default profile
                    $this->im->profileImage('icc', $this->iccWorkspace);
                    return true;
                }
            }
            elseif(IMAGICK::COLORSPACE_CMYK == $this->imageColorspace) {
                $tmpName = dirname(__FILE__) . '/icc/cmykprofiles/' . $this->data['cmykInProfile'];
                if(is_file($tmpName) && 'icc'==strtolower(pathinfo($tmpName, PATHINFO_EXTENSION))) {
                    $this->iccCmykIn = file_get_contents($tmpName);
                    $this->im->profileImage('icc', $this->iccCmykIn);  // assign the default cmyk profile
                    $this->im->profileImage('icc', $this->iccWorkspace);
                    return true;
                }
            }
            elseif(IMAGICK::COLORSPACE_GRAY == $this->imageColorspace) {
                $tmpName = dirname(__FILE__) . '/icc/grayscaleprofiles/' . $this->data['grayOutProfile'];
                if(is_file($tmpName) && 'icc'==strtolower(pathinfo($tmpName, PATHINFO_EXTENSION))) {
                    $this->iccGrayOut = file_get_contents($tmpName);
                }
                $this->useGray = isset($this->iccGrayOut) ? true : false;
                $tmpName = dirname(__FILE__) . '/icc/grayscaleprofiles/' . $this->data['grayInProfile'];
                if($this->useGray && is_file($tmpName) && 'icc'==strtolower(pathinfo($tmpName, PATHINFO_EXTENSION))) {
                    $this->iccGrayIn = file_get_contents($tmpName);
                    $this->im->profileImage('icc', $this->iccGrayIn);  // assign the default grayscale profile
                    $this->im->profileImage('icc', $this->iccWorkspace);
                    return true;
                }
            }
        }

        return false;
    }


    protected function iccCmsFinish() {
        if(!$this->useCMS) return false;
        if(!$this->useICC) return false;
        // transition into Targetcolorspace
        if($this->useGray) {
            $this->im->profileImage('icc', $this->iccGrayOut);
        }
        else {
            $this->im->profileImage('icc', $this->iccRgbOut);
        }
    }