MagickCore (API C de bajo nivel)
La API MagickCore es una interfaz de bajo nivel entre el lenguaje de programación C y las bibliotecas de procesamiento de imágenes de ImageMagick, y se recomienda únicamente para programadores de nivel experto. A diferencia de la API C de MagickWand, que usa solo unos pocos tipos opacos y accesores, con MagickCore se accede casi exclusivamente a los miembros de las estructuras de forma directa. La descripción de los métodos públicos de MagickCore se encuentra en GitHub:
- Inicializar o destruir el entorno de ImageMagick
- Constituir una imagen
- Componer una imagen
- Métodos de imagen
- Métodos de canal de imagen
- Contar los colores de una imagen
- Métodos de mapa de colores
- Métodos de espacio de color
- Distorsiones de imagen
- Trabajar con capas de imagen
- Trabajar con perfiles de imagen
- Reducir el número de colores únicos de una imagen
- Histogramas de imagen
- Segmentar una imagen con umbralización por c-medias difusas
- Redimensionar una imagen
- Transformar una imagen
- Sesgar o rotar una imagen un ángulo arbitrario
- Realzar una imagen
- Añadir un efecto
- Erosiones, dilataciones, aperturas y cierres morfológicos
- Añadir un efecto especial
- Decorar una imagen
- Obtener/establecer un atributo de imagen
- Obtener/establecer propiedades de imagen
- Obtener estadísticas de imagen
- Obtener características de imagen
- Anotar una imagen
- Pintar sobre una imagen
- Dibujar sobre una imagen
- Crear una miniatura de imagen
- Calcular la transformada discreta de Fourier (DFT)
- Comparar una imagen con una imagen reconstruida
- Visión por computador
- Mostrar y editar una imagen de forma interactiva
- Animar una secuencia de imágenes de forma interactiva
- Convertir hacia y desde píxeles cifrados
- Trabajar con listas de imágenes
- Métodos de vista de imagen
- Obtener o establecer píxeles de imagen
- Trabajar con vistas de caché
- La FIFO de píxeles
- Leer o escribir objetos binarios grandes (BLOB)
- Módulos cargables
- Calcular un resumen de mensaje (message digest) de una imagen
- El registro de imágenes
- Manejo de excepciones
- Asignación de memoria
- Monitorizar o limitar el consumo de recursos
- Monitorizar el progreso de una operación de imagen
- Obtener la versión y los derechos de autor
- Métodos Mime
- Métodos obsoletos
- Códigos de error y advertencia
Después de escribir tu programa MagickCore, compílalo así:
cc `MagickCore-config --cflags --cppflags` -O2 -o core core.c `MagickCore-config --ldflags --libs`
Establece la variable de entorno PKG_CONFIG_PATH si ImageMagick no está en la ruta predeterminada de tu sistema:
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
Para empezar, aquí tienes un programa de ejemplo que utiliza la API MagickCore, core.c. Lee una imagen GIF, crea una miniatura y la escribe en disco en el formato de imagen PNG.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <MagickCore/MagickCore.h>
int main(int argc,char **argv)
{
ExceptionInfo
*exception;
Image
*image,
*images,
*resize_image,
*thumbnails;
ImageInfo
*image_info;
if (argc != 3)
{
(void) fprintf(stdout,"Usage: %s image thumbnail\n",argv[0]);
exit(0);
}
/*
Initialize the image info structure and read an image.
*/
MagickCoreGenesis(*argv,MagickTrue);
exception=AcquireExceptionInfo();
image_info=CloneImageInfo((ImageInfo *) NULL);
(void) strcpy(image_info->filename,argv[1]);
images=ReadImage(image_info,exception);
if (exception->severity != UndefinedException)
CatchException(exception);
if (images == (Image *) NULL)
exit(1);
/*
Convert the image to a thumbnail.
*/
thumbnails=NewImageList();
while ((image=RemoveFirstImageFromList(&images)) != (Image *) NULL)
{
resize_image=ResizeImage(image,106,80,LanczosFilter,exception);
if (resize_image == (Image *) NULL)
MagickError(exception->severity,exception->reason,exception->description);
(void) AppendImageToList(&thumbnails,resize_image);
DestroyImage(image);
}
/*
Write the image thumbnail.
*/
(void) strcpy(thumbnails->filename,argv[2]);
WriteImage(image_info,thumbnails,exception);
/*
Destroy the image thumbnail and exit.
*/
thumbnails=DestroyImageList(thumbnails);
image_info=DestroyImageInfo(image_info);
exception=DestroyExceptionInfo(exception);
MagickCoreTerminus();
return(0);
}
Ahora realicemos el mismo realce de contraste aprovechando nuestro sistema de procesamiento de doble o cuádruple núcleo, ejecutando el algoritmo en paralelo mediante vistas de wand. El módulo sigmoidal-contrast.c lee una imagen, aplica un control de contraste no lineal sigmoidal y escribe el resultado en disco igual que el programa anterior de realce de contraste, pero ahora lo hace en paralelo (asume que ImageMagick está compilado con soporte de OpenMP).
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <MagickCore/MagickCore.h>
static MagickBooleanType SigmoidalContrast(ImageView *contrast_view,
const ssize_t y,const int id,void *context)
{
#define QuantumScale ((MagickRealType) 1.0/(MagickRealType) QuantumRange)
#define SigmoidalContrast(x) \
(QuantumRange*(1.0/(1+exp(10.0*(0.5-QuantumScale*x)))-0.0066928509)*1.0092503)
RectangleInfo
extent;
register IndexPacket
*indexes;
register PixelPacket
*pixels;
register ssize_t
x;
extent=GetImageViewExtent(contrast_view);
pixels=GetImageViewAuthenticPixels(contrast_view);
for (x=0; x < (ssize_t) (extent.width-extent.x); x++)
{
SetPixelRed(pixels,RoundToQuantum(SigmoidalContrast(GetPixelRed(pixels)));
SetPixelGreen(pixels,RoundToQuantum(SigmoidalContrast(GetPixelGreen(pixels)));
SetPixelBlue(pixels,RoundToQuantum(SigmoidalContrast(GetPixelBlue(pixels)));
SetPixelOpacity(pixels,RoundToQuantum(SigmoidalContrast(GetPixelOpacity(pixels)));
pixels++;
}
indexes=GetImageViewAuthenticIndexes(contrast_view);
if (indexes != (IndexPacket *) NULL)
for (x=0; x < (ssize_t) (extent.width-extent.x); x++)
SetPixelIndex(indexes+x,RoundToQuantum(SigmoidalContrast(GetPixelIndex(indexes+x))));
return(MagickTrue);
}
int main(int argc,char **argv)
{
#define ThrowImageException(image) \
{ \
\
CatchException(exception); \
if (contrast_image != (Image *) NULL) \
contrast_image=DestroyImage(contrast_image); \
exit(-1); \
}
#define ThrowViewException(view) \
{ \
char \
*description; \
\
ExceptionType \
severity; \
\
description=GetImageViewException(view,&severity); \
(void) fprintf(stderr,"%s %s %lu %s\n",GetMagickModule(),description); \
description=DestroyString(description); \
exit(-1); \
}
ExceptionInfo
*exception;
Image
*contrast_image;
ImageInfo
*image_info;
ImageView
*contrast_view;
MagickBooleanType
status;
if (argc != 3)
{
(void) fprintf(stdout,"Usage: %s image sigmoidal-image\n",argv[0]);
exit(0);
}
/*
Read an image.
*/
MagickCoreGenesis(*argv,MagickTrue);
image_info=AcquireImageInfo();
(void) CopyMagickString(image_info->filename,argv[1],MaxTextExtent);
exception=AcquireExceptionInfo();
contrast_image=ReadImage(image_info,exception);
if (contrast_image == (Image *) NULL)
ThrowImageException(contrast_image);
/*
Sigmoidal non-linearity contrast control.
*/
contrast_view=NewImageView(contrast_image);
if (contrast_view == (ImageView *) NULL)
ThrowImageException(contrast_image);
status=UpdateImageViewIterator(contrast_view,SigmoidalContrast,(void *) NULL);
if (status == MagickFalse)
ThrowImageException(contrast_image);
contrast_view=DestroyImageView(contrast_view);
/*
Write the image then destroy it.
*/
status=WriteImages(image_info,contrast_image,argv[2],exception);
if (status == MagickFalse)
ThrowImageException(contrast_image);
contrast_image=DestroyImage(contrast_image);
exception=DestroyExceptionInfo(exception);
image_info=DestroyImageInfo(image_info);
MagickCoreTerminus();
return(0);
}
MagickCoreTerminus() es una función de la biblioteca ImageMagick que se usa para limpiar y liberar recursos al cerrar una aplicación que utiliza ImageMagick. Esta función debe llamarse en el hilo principal del proceso de la aplicación durante el proceso de cierre. Es crucial que esta función se invoque únicamente después de que hayan terminado todos los hilos que estén usando funciones de ImageMagick.
ImageMagick podría usar hilos internamente mediante OpenMP (un método de programación paralela). Por ello, es importante asegurarse de que todas las llamadas a funciones de ImageMagick hayan finalizado antes de llamar a MagickCoreTerminus(). Esto evita problemas con los hilos de trabajo de OpenMP que accedan a recursos destruidos por esta función de terminación.
Si se está usando OpenMP (a partir de la versión 5.0), la propia implementación de OpenMP se encarga de iniciar y detener los hilos de trabajo y de asignar y liberar recursos mediante sus propios métodos. Esto significa que, tras llamar a MagickCoreTerminus(), algunos recursos de OpenMP y algunos hilos de trabajo podrían seguir asignados. Para abordar esto, se puede invocar la función omp_pause_resource_all(omp_pause_hard). Esta función, introducida en la versión 5.0 de OpenMP, garantiza que se liberen todos los recursos asignados por OpenMP (como hilos y memoria específica de hilo). Se recomienda llamar a esta función después de que MagickCoreTerminus() haya completado su ejecución.