Get Image ICC Profile with PHP or Imagick
Asked Answered
E

1

9

I have been struggling all day with this issue and surprised that can't find any documentation!

I am uploading images to a website & would like to extract the name of each images ICC profile & use it in the image description. So far, standard PHP produces no results. I have checked the images with Photoshop, Bridge & Exiftool & each has identified the profile embedded.

<?php 
$info = exif_read_data($image);
echo 'ICC Profile: '.$info['ICC_Profile'].'<br>';
echo 'ICC Profile: '.$info['CurrentICCProfile'].'<br>';
echo 'ICC Profile: '.$info['ColorSpace'].'<br>';
?>

Imagick produced the best results with:

$imagick = new Imagick();
$imagick->readImage($image);
print_r ($imagick->getImageProfiles("icc",true));

Generating an array that actually mentions the profile but not a usable string. Any help appreciated.

I'm using these versions:

PHP Version 5.2.17 - imagick module version 3.0.1 - ImageMagick version 6.7.6-8

And print_r returns (for 'ProPhoto RGB' ICC profile):

Array ( [icc] => �KCMSmntrRGB XYZ � :acspMSFTKODAROMM���+KODAcprtHdesc\�wtpt�rTRC�gTRC�bTRC�rXYZgXYZbXYZ,dmnd@ndmdd��mmod�(textCopyright (c) Eastman Kodak Company, 1999, all rights reserved.desc ProPhoto RGB��ProPhoto RGB ProPhoto RGBXYZ ���,curv�XYZ �4I�XYZ "��>XYZ �-descKODAK��KODAKKODAKdesc'Reference Output Medium Metric(ROMM) (��Reference Output Medium Metric(ROMM) 'Reference Output Medium Metric(ROMM) mmod���;� )

in full (from Exiftool):

Profile CMM Type                : KCMS
Profile Version                 : 2.1.0
Profile Class                   : Display Device Profile
Color Space Data                : RGB
Profile Connection Space        : XYZ
Profile Date Time               : 1998:12:01 18:58:21
Profile File Signature          : acsp
Primary Platform                : Microsoft Corporation
CMM Flags                       : Not Embedded, Independent
Device Manufacturer             : KODA
Device Model                    : ROMM
Device Attributes               : Reflective, Glossy, Positive, Color
Rendering Intent                : Perceptual
Connection Space Illuminant     : 0.9642 1 0.82487
Profile Creator                 : KODA
Profile ID                      : 0
Profile Copyright               : Copyright (c) Eastman Kodak Company, 1999, all rights reserved.
Profile Description             : ProPhoto RGB
Media White Point               : 0.9642 1 0.82489
Red Tone Reproduction Curve     : (Binary data 14 bytes, use -b option to extract)
Green Tone Reproduction Curve   : (Binary data 14 bytes, use -b option to extract)
Blue Tone Reproduction Curve    : (Binary data 14 bytes, use -b option to extract)
Red Matrix Column               : 0.79767 0.28804 0
Green Matrix Column             : 0.13519 0.71188 0
Blue Matrix Column              : 0.03134 9e-005 0.82491
Device Mfg Desc                 : KODAK
Device Model Desc               : Reference Output Medium Metric(ROMM)
Make And Model                  : (Binary data 40 bytes, use -b option to extract)
Eaglewood answered 23/5, 2013 at 13:16 Comment(3)
What is the string that you are expecting backConstantia
I'm looking for a way to return the profile name, so in this example: ProPhoto RGBEaglewood
Maybe see what those unprintable characters actually are, to see if you can spot a pattern? They might be null (zero) characters, for example.Sheen
S
7

I'm not too sure, if this is the case for all images. At least the images i have, have this information in their "Properties". Thus to get a printable profile name it should work like this:

$imagick = new imagick('/some/filename');
$profile = $imagick->getImageProperties('icc:model', true);
/**
 * If the property 'icc:model' is set $profile now should be:
 * array( 'icc:model' => 'ICC model name')
 */

If you would like to see all the properties, which are set for an image, you could probe the image manually with identify -verbose /some/filename. There you will have to look for "Properties:", the ICC name should be set there.

The above is the easy way to obtain the ICC profile name. If you really need the ICC name from the icc profile you might want to take a look at the ICC Profile Format Specification

In short:

  • The first 128 bytes are the header. Then follows a tag table, where the first 4 bytes are the size of the table.
  • Each tag consists of 4 byte triplets. The first 4 byts are the name of the tag. The next four bytes are the offset of the data in the icc file. The next four bytes define the size of the tags data.

We are interested in the 'desc' tag (see page 63 in the specification).

  • The description itself starts again with 'desc' then four bytes are reserved. The next four bytes define the size of the ICC profiles name.

In code it works like this:

$image = new imagick('/path/to/img');
try {
    $existingICC = $image->getImageProfile('icc');
} catch (ImagickException $e) {
    // Handle it
    $existingICC = null;
}

if($existingICC) {
    // Search the start of the description tag in the tag table.:
    // We are not looking in the 128 bytes for the header + 4 bytes for the size of the table
    $descTagPos = stripos( $existingICC, 'desc', 131 );
    if( $descTagPos === false) {
       // There is no description, handle it.
    } else {
        // This is the description Tag ( 'desc'|offset|size each with a size of 4 bytes
        $descTag = substr( $existingICC, $descTagPos, 12 );

        // Get the offset out of the description tag, unpack it from binary to hex and then from hex to decimal
        $descTagOffset = substr ( $descTag, 4, 4 );
        $descTagOffset = unpack( 'H*', $descTagOffset );
        $descTagOffset = hexdec( $descTagOffset[1] );

        // Same for the description size
        $descTagSize = substr ( $existingICC, $descTagPos + 8, 4 );
        $descTagSize = unpack('H*', $descTagSize);
        $descTagSize = hexdec( $descTagSize[1] );

        // Here finally is the descripton
        $iccDesc = substr( $existingICC, $descTagOffset, $descTagSize );

        // See page 63 in the standard, here we extract the size of the ICC profile name string
        $iccNameSize = substr( $iccDesc, 8, 4 );
        $iccNameSize = unpack( 'H*', $iccNameSize);
        $iccNameSize = hexdec( $iccNameSize[1]);

        // Finally got the name.
        $iccName = substr( $iccDesc, 12, $iccNameSize );
        echo "ICC name: $iccName\n";
    }
}
Sabatier answered 21/5, 2015 at 10:4 Comment(3)
Thank you for this. The code to parse out the ICC profile description worked like a charm. The getImageProperties('icc:model', true) option did not work at all for my image set.Seedling
Not working for many images, which included description like "sRGB built-in".Wakashan
Which description? Do you read the description of the image or are you using the extracted ICC profiles description? My answer is for the ICC profile. Depending on the way the images were created/processed the ICC profile description of the image can be set to anything. Yet, if the ICC profile is embedded you can extract it and get the profile name from there. The above answer describes how to extract the ICC Profile name from the ICC profile itself.Sabatier

© 2022 - 2024 — McMap. All rights reserved.