PHP e ImageMagick, conversión de imágenes CMYK a RGB

Según la teoría se puede visualizar correctamente una imagen CMYK siempre y cuando tenga información sobre el perfil de color… en teoría.

En la práctica puedes tener las imágenes (TIFF en mi caso) sin ningún tipo de información sobre el perfil de color por motivos prácticos. Además puede que también concurran limitaciones con el software de visualización.

En mi caso la imagen de origen tiene perfil WAN-IFRAnewspaper26v5 (sucesor del ISOnewspaper26v4) y para su correcta visualización en un visor sin gestión de color hay que convertirla al perfil sRGB ya que la gama de colores (aka gamut) del WAN-IFRA caben por completo en la gama del sRGB, como se puede comprobar mediante la fabulosa herramienta ICCView:

WAN-IFRAnewspaper26v5 vs sRGB (http://www.iccview.de/index.php/3d)
WAN-IFRAnewspaper26v5 vs sRGB (http://www.iccview.de/index.php/3d)

Así que ya tenemos una solución al problema ¿Cómo visualizar con suficiente precisión una imagen CMYK en un visor sin gestión de color?: convirtiendo la imagen al perfil sRGB.

Y es cierto, si en Photoshop (y aquí no vale Gimp porque no puede editar imágenes CMYK) abrimos nuestra imagen, asignamos el perfil WAN-IFRA, convertimos al sRGB compensando el punto negro, con propósito colorimétrico relativo y guardamos. Veremos como ahora tenemos una imagen en RGB con los colores casi idénticos al original CMYK. Esta es, digamos, la demostración práctica de nuestra solución.

Ahora que ya sabemos lo que hay que hacer y hemos hecho una prueba de concepto, toca automatizar la tarea, para lo cual nos apoyaremos en ImageMagick.

ImageMagick es una de esas piezas de código libre (licencia Apache) que suponen una auténtica joya. Nos pone al alcance de la mano una poderosa herramienta de manipulación de imágenes para su uso tanto de manera manual como para su integración tanto en scripts (PHP, Python…) como en aplicaciones de diverso tipo (C++, .NET…).

En este caso también hay que hacer una prueba de concepto, para ello se busca un poco por ahí y se da con la linea de comando correcta:

convert -black-point-compensation -intent Relative ImageCMYK.tif -profile ISOnewspaper26v4.icc -profile sRGB.icc ImageRGB.png

Es fácil comprobar como apenas hay diferencias entre la imagen que hemos hecho a mano con el Photoshop con la que hemos obtenido por medio de ImageMagick: vamos por buen camino.

Y llega la hora del PHP, utilizando la librería PECL para ImageMagick (IMagick):

$image = new Imagick('ImageCMYK.tif');

$image->setImageRenderingIntent(Imagick::RENDERINGINTENT_RELATIVE);
$image->setOption('black_point_compensation', true);

$icc_cmyk = file_get_contents('ISOnewspaper26v4.icc');
$image->profileImage('icc', $icc_cmyk);

$icc_rgb = file_get_contents('sRGB Color Space Profile.icm');
$image->profileImage('icc', $icc_rgb);

$image->setImageColorSpace(Imagick::COLORSPACE_SRGB);

$image->writeImage('ImageRGB.jpg');

Vale, el código tiene poco que comentar… abrimos la imagen convertida en sRGB y vemos cómo lo que tenemos es una imagen “lavada”, como si le hubieran dado un velo blanco. He remarcado antes que había que compensar el punto negro, sea lo que demonios sea (no voy a explicarlo ahora). Digamos que experimentalmente es lo que hemos comprobado que funciona. Pues bien, aunque hemos hecho un setOption para habilitar la compensación del punto negro, el IMagick no lo soporta (aún).

Así que hay que buscar otra manera, y yo he probado los objetos COM. El porqué he elegido esta técnica es porque la conozco al utilizarla para controlar Acrobat y otras aplicaciones mediante PHP. Para poder utilizar COM con PHP hay que habilitar la extensión php_dcom_dotnet.dll (¿no he mencionado que el entorno de este trabajo es Windows?, pues ya lo sabes). El código:

$MagickImage = new COM('ImageMagickObject.MagickImage') or die ('ImageMagickObject didn\'t load, too bad');

$cmyk = 'WAN-IFRAnewspaper26v5.icc';
$rgb = 'sRGB Color Space Profile.icm';

$files[] = ['i' => 'ImageCMYK.tif', 'o' => 'ImageRGB.png'];
foreach ($files as $file) {
  try {
    $MagickImage->Convert((string) $file['i'], '-black-point-compensation', '-intent', 'Relative', '-profile', (string) $cmyk, '-profile', (string) $rgb, (string) $file['o']);
  } catch (Exception $e) {
    print_r($e);
  }
}
$MagickImage = null;

Obviando que he habilitado un array para contener tantos ficheros a tratar como deseemos, hay varias consideraciones a tener en cuenta:

  • Los parámetros que espera el método Convert son:
    1. Fichero de entrada
    2. Parámetros de conversión (primero el parámetro y luego el valor si tuviera)
    3. Fichero de salida
  • En script para línea de comando las rutas pueden ser relativas, para web es preferible rutas absolutas en todos los ficheros.
  • Hay que evaluar como string todas las variables que utilicemos como parámetro del método Convert.
  • Hay que terminar el script destruyendo el objeto COM que hemos creado al inicio, especialmente en entorno web: $MagickImage = null;

Y ya está, no hemos acabado la guerra aún, pero ha sido una batalla importante la de hoy.

Leave a Reply

Your email address will not be published. Required fields are marked *