⚠️ Este é um site de tradução não oficial, sem relação com a ImageMagick Studio LLC. Para informações oficiais, consulte a página original (https://imagemagick.org/magick-core/).

MagickCore (API C de baixo nível)

A MagickCore API é uma interface de baixo nível entre a linguagem de programação C e as bibliotecas de processamento de imagens do ImageMagick, e é recomendada apenas para programadores de nível avançado. Diferentemente da API C MagickWand, que usa apenas alguns poucos tipos opacos e acessadores, com o MagickCore você acessa quase exclusivamente os membros das estruturas diretamente. Uma descrição dos métodos públicos do MagickCore está disponível no GitHub:

Depois de escrever seu programa MagickCore, compile-o assim:

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

Defina a variável de ambiente PKG_CONFIG_PATH se o ImageMagick não estiver no caminho padrão do seu sistema:

export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig

Para começar, aqui está um programa de exemplo que utiliza a MagickCore API, core.c. Ele lê uma imagem GIF, cria uma miniatura e a grava em disco no formato de imagem 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);
}

Agora vamos realizar o mesmo aprimoramento de contraste aproveitando nosso sistema de processamento dual ou quad-core, executando o algoritmo em paralelo com o uso de wand views. O módulo sigmoidal-contrast.c lê uma imagem, aplica o controle de contraste por não linearidade sigmoidal e grava o resultado em disco, exatamente como o programa de aprimoramento de contraste anterior, mas agora ele faz seu trabalho em paralelo (presume que o ImageMagick foi compilado com suporte a 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() é uma função da biblioteca ImageMagick usada para limpar e liberar recursos ao encerrar uma aplicação que utiliza o ImageMagick. Essa função deve ser chamada na thread principal do processo da aplicação durante o processo de encerramento. É crucial que essa função seja invocada apenas depois que quaisquer threads que estejam usando funções do ImageMagick tenham terminado.

O ImageMagick pode usar threads internamente por meio do OpenMP (um método de programação paralela). Como resultado, é importante garantir que todas as chamadas de função ao ImageMagick tenham sido concluídas antes de chamar MagickCoreTerminus(). Isso evita problemas com threads de trabalho (worker threads) do OpenMP acessando recursos que são destruídos por essa função de encerramento.

Se o OpenMP estiver em uso (a partir da versão 5.0), a própria implementação do OpenMP cuida de iniciar e parar as worker threads e de alocar e liberar recursos usando seus próprios métodos. Isso significa que, depois de chamar MagickCoreTerminus(), alguns recursos e worker threads do OpenMP podem permanecer alocados. Para resolver isso, a função omp_pause_resource_all(omp_pause_hard) pode ser invocada. Essa função, introduzida na versão 5.0 do OpenMP, garante que quaisquer recursos alocados pelo OpenMP (como threads e memória específica de thread) sejam liberados. Recomenda-se chamar essa função depois que MagickCoreTerminus() tiver concluído sua execução.