⚠️ Ceci est un site de traduction non officiel, sans lien avec ImageMagick Studio LLC. Pour des informations officielles, consultez la page originale (https://imagemagick.org/magick-core/).

MagickCore (API C de bas niveau)

L'API MagickCore est une interface de bas niveau entre le langage de programmation C et les bibliothèques de traitement d'images ImageMagick, et elle est recommandée uniquement aux programmeurs de niveau expert. Contrairement à l'API C MagickWand, qui n'utilise que quelques types opaques et accesseurs, avec MagickCore vous accédez presque exclusivement aux membres de structure directement. Une description des méthodes publiques de MagickCore se trouve sur GitHub :

Après avoir écrit votre programme MagickCore, compilez-le ainsi :

cc `MagickCore-config --cflags --cppflags` -O2 -o core core.c `MagickCore-config --ldflags --libs`

Définissez la variable d'environnement PKG_CONFIG_PATH si ImageMagick n'est pas dans le chemin système par défaut :

export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig

Voici un exemple de programme qui utilise l'API MagickCore pour vous aider à démarrer, core.c. Il lit une image GIF, crée une vignette et l'écrit sur le disque au format d'image 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);
}

Effectuons maintenant la même amélioration de contraste tout en tirant parti de notre système de traitement à double ou quadruple cœur en exécutant l'algorithme en parallèle à l'aide des vues de wand. Le module sigmoidal-contrast.c lit une image, applique un contrôle de contraste à non-linéarité sigmoïde et écrit le résultat sur le disque, tout comme le programme d'amélioration de contraste précédent, mais cette fois il effectue son travail en parallèle (suppose qu'ImageMagick est compilé avec la prise en charge d'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() est une fonction de la bibliothèque ImageMagick qui sert à nettoyer et libérer les ressources lors de l'arrêt d'une application utilisant ImageMagick. Cette fonction doit être appelée dans le thread principal du processus de l'application pendant la procédure d'arrêt. Il est crucial que cette fonction ne soit invoquée qu'après la terminaison de tous les threads qui utilisent des fonctions ImageMagick.

ImageMagick peut utiliser des threads en interne via OpenMP (une méthode de programmation parallèle). Par conséquent, il est important de s'assurer que tous les appels de fonctions vers ImageMagick sont terminés avant d'appeler MagickCoreTerminus(). Cela évite les problèmes de threads de travail OpenMP accédant à des ressources détruites par cette fonction de terminaison.

Si OpenMP est utilisé (à partir de la version 5.0), l'implémentation OpenMP gère elle-même le démarrage et l'arrêt des threads de travail ainsi que l'allocation et la libération des ressources avec ses propres méthodes. Cela signifie qu'après l'appel de MagickCoreTerminus(), certaines ressources OpenMP et certains threads de travail peuvent rester alloués. Pour y remédier, la fonction omp_pause_resource_all(omp_pause_hard) peut être invoquée. Cette fonction, introduite dans OpenMP version 5.0, garantit que toutes les ressources allouées par OpenMP (telles que les threads et la mémoire spécifique aux threads) sont libérées. Il est recommandé d'appeler cette fonction après que MagickCoreTerminus() a terminé son exécution.