⚠️ Ini adalah situs terjemahan tidak resmi dan tidak berafiliasi dengan ImageMagick Studio LLC. Untuk informasi resmi, lihat halaman asli (https://imagemagick.org/magick-wand/).

MagickWand API adalah antarmuka yang direkomendasikan antara bahasa pemrograman C dan pustaka (library) pemrosesan gambar ImageMagick. Berbeda dengan API C MagickCore, MagickWand hanya menggunakan beberapa tipe data opaque. Terdapat accessor untuk mengatur atau mendapatkan properti wand yang penting. Deskripsi metode publik MagickWand dapat ditemukan di GitHub:

Setelah Anda menulis program MagickWand, kompilasilah seperti berikut:

cc `MagickWand-config --cflags --cppflags` -O2 -o wand wand.c `MagickWand-config --ldflags --libs`

Atur variabel lingkungan PKG_CONFIG_PATH jika ImageMagick tidak berada di path sistem default Anda:

export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig

Berikut adalah contoh program yang memanfaatkan API MagickWand untuk membantu Anda memulai, wand.c. Program ini membaca gambar, membuat thumbnail, dan menulis hasilnya ke disk.

#include <stdio.h>
#include <stdlib.h>
#include <MagickWand/MagickWand.h>

int main(int argc,char **argv)
{
#define ThrowWandException(wand) \
{ \
  char \
    *description; \
 \
  ExceptionType \
    severity; \
 \
  description=MagickGetException(wand,&severity); \
  (void) fprintf(stderr,"%s %s %lu %s\n",GetMagickModule(),description); \
  description=(char *) MagickRelinquishMemory(description); \
  exit(-1); \
}

  MagickBooleanType
    status;

  MagickWand
    *magick_wand;

  if (argc != 3)
    {
      (void) fprintf(stdout,"Usage: %s image thumbnail\n",argv[0]);
      exit(0);
    }
  /*
    Read an image.
  */
  MagickWandGenesis();
  magick_wand=NewMagickWand();
  status=MagickReadImage(magick_wand,argv[1]);
  if (status == MagickFalse)
    ThrowWandException(magick_wand);
  /*
    Turn the images into a thumbnail sequence.
  */
  MagickResetIterator(magick_wand);
  while (MagickNextImage(magick_wand) != MagickFalse)
    MagickResizeImage(magick_wand,106,80,LanczosFilter,1.0);
  /*
    Write the image then destroy it.
  */
  status=MagickWriteImages(magick_wand,argv[2],MagickTrue);
  if (status == MagickFalse)
    ThrowWandException(magick_wand);
  magick_wand=DestroyMagickWand(magick_wand);
  MagickWandTerminus();
  return(0);
}

Berikut adalah program lain yang menunjukkan salah satu cara mendapatkan dan mengatur piksel gambar dengan API MagickWand, contrast.c. Program ini membaca gambar, menerapkan kontrol kontras nonlinier sigmoidal, dan menulis hasilnya ke disk.

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <MagickWand/MagickWand.h>

int main(int argc,char **argv)
{
#define SigmoidalContrast(x) \
  (QuantumRange*(1.0/(1+exp(10.0*(0.5-QuantumScale*x)))-0.0066928509)*1.0092503)
#define ThrowWandException(wand) \
{ \
  char \
    *description; \
 \
  ExceptionType \
    severity; \
 \
  description=MagickGetException(wand,&severity); \
  (void) fprintf(stderr,"%s %s %lu %s\n",GetMagickModule(),description); \
  description=(char *) MagickRelinquishMemory(description); \
  exit(-1); \
}

  long
    y;

  MagickBooleanType
    status;

  MagickWand
    *contrast_wand,
    *image_wand;

  PixelInfo
    pixel;

  PixelIterator
    *contrast_iterator,
    *iterator;

  PixelWand
    **contrast_pixels,
    **pixels;

  register long
    x;

  unsigned long
    width;

  if (argc != 3)
    {
      (void) fprintf(stdout,"Usage: %s image sigmoidal-image\n",argv[0]);
      exit(0);
    }
  /*
    Read an image.
  */
  MagickWandGenesis();
  image_wand=NewMagickWand();
  status=MagickReadImage(image_wand,argv[1]);
  if (status == MagickFalse)
    ThrowWandException(image_wand);
  contrast_wand=CloneMagickWand(image_wand);
  /*
    Sigmoidal non-linearity contrast control.
  */
  iterator=NewPixelIterator(image_wand);
  contrast_iterator=NewPixelIterator(contrast_wand);
  if ((iterator == (PixelIterator *) NULL) ||
      (contrast_iterator == (PixelIterator *) NULL))
    ThrowWandException(image_wand);
  for (y=0; y < (long) MagickGetImageHeight(image_wand); y++)
  {
    pixels=PixelGetNextIteratorRow(iterator,&width);
    contrast_pixels=PixelGetNextIteratorRow(contrast_iterator,&width);
    if ((pixels == (PixelWand **) NULL) ||
        (contrast_pixels == (PixelWand **) NULL))
      break;
    for (x=0; x < (long) width; x++)
    {
      PixelGetMagickColor(pixels[x],&pixel);
      pixel.red=SigmoidalContrast(pixel.red);
      pixel.green=SigmoidalContrast(pixel.green);
      pixel.blue=SigmoidalContrast(pixel.blue);
      pixel.index=SigmoidalContrast(pixel.index);
      PixelSetPixelColor(contrast_pixels[x],&pixel);
    }
    (void) PixelSyncIterator(contrast_iterator);
  }
  if (y < (long) MagickGetImageHeight(image_wand))
    ThrowWandException(image_wand);
  contrast_iterator=DestroyPixelIterator(contrast_iterator);
  iterator=DestroyPixelIterator(iterator);
  image_wand=DestroyMagickWand(image_wand);
  /*
    Write the image then destroy it.
  */
  status=MagickWriteImages(contrast_wand,argv[2],MagickTrue);
  if (status == MagickFalse)
    ThrowWandException(image_wand);
  contrast_wand=DestroyMagickWand(contrast_wand);
  MagickWandTerminus();
  return(0);
}

Sekarang mari kita lakukan peningkatan kontras yang sama sambil memanfaatkan sistem pemrosesan dual-core atau quad-core dengan menjalankan algoritma secara paralel menggunakan wand view. Modul sigmoidal-contrast.c membaca gambar, menerapkan kontrol kontras nonlinier sigmoidal, dan menulis hasilnya ke disk sama seperti program peningkatan kontras sebelumnya, tetapi sekarang prosesnya berjalan secara paralel (dengan asumsi ImageMagick telah dibangun (build) dengan dukungan OpenMP).

#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <MagickWand/MagickWand.h>

static MagickBooleanType SigmoidalContrast(WandView *contrast_view,
  const ssize_t y,const int thread_id,void *context)
{
#define SigmoidalContrast(x) \
  (QuantumRange*(1.0/(1+exp(10.0*(0.5-QuantumScale*x)))-0.0066928509)*1.0092503)

  PixelInfo
    pixel;

  PixelWand
    **pixels;

  RectangleInfo
    extent;

  register ssize_t
    x;

  extent=GetWandViewExtent(contrast_view);
  pixels=GetWandViewPixels(contrast_view);
  for (x=0; x < (ssize_t) extent.width; x++)
  {
    PixelGetMagickColor(pixels[x],&pixel);
    pixel.red=SigmoidalContrast(pixel.red);
    pixel.green=SigmoidalContrast(pixel.green);
    pixel.blue=SigmoidalContrast(pixel.blue);
    pixel.index=SigmoidalContrast(pixel.index);
    PixelSetPixelColor(pixels[x],&pixel);
  }
  return(MagickTrue);
}

int main(int argc,char **argv)
{
#define ThrowWandException(wand) \
{ \
  char \
    *description; \
 \
  ExceptionType \
    severity; \
 \
  description=MagickGetException(wand,&severity); \
  (void) fprintf(stderr,"%s %s %lu %s\n",GetMagickModule(),description); \
  description=(char *) MagickRelinquishMemory(description); \
  exit(-1); \
}

  MagickBooleanType
    status;

  MagickWand
    *contrast_wand;

  PixelInfo
    pixel;

  WandView
    *contrast_view;

  if (argc != 3)
    {
      (void) fprintf(stdout,"Usage: %s image sigmoidal-image\n",argv[0]);
      exit(0);
    }
  /*
    Read an image.
  */
  MagickWandGenesis();
  contrast_wand=NewMagickWand();
  status=MagickReadImage(contrast_wand,argv[1]);
  if (status == MagickFalse)
    ThrowWandException(contrast_wand);
  /*
    Sigmoidal non-linearity contrast control.
  */
  contrast_view=NewWandView(contrast_wand);
  if (contrast_view == (WandView *) NULL)
    ThrowWandException(contrast_wand);
  status=UpdateWandViewIterator(contrast_view,SigmoidalContrast,(void *) NULL);
  if (status == MagickFalse)
    ThrowWandException(contrast_wand);
  contrast_view=DestroyWandView(contrast_view);
  /*
    Write the image then destroy it.
  */
  status=MagickWriteImages(contrast_wand,argv[2],MagickTrue);
  if (status == MagickFalse)
    ThrowWandException(contrast_wand);
  contrast_wand=DestroyMagickWand(contrast_wand);
  MagickWandTerminus();
  return(0);
}

MagickWandTerminus() adalah fungsi dalam pustaka ImageMagick yang digunakan untuk membersihkan dan melepaskan sumber daya saat mematikan aplikasi yang menggunakan ImageMagick. Fungsi ini harus dipanggil di thread utama proses aplikasi selama proses mematikan. Sangat penting bahwa fungsi ini hanya dipanggil setelah semua thread yang menggunakan fungsi ImageMagick berakhir.

ImageMagick mungkin menggunakan thread secara internal melalui OpenMP (metode pemrograman paralel). Karena itu, penting untuk memastikan bahwa semua pemanggilan fungsi ke ImageMagick telah selesai sebelum memanggil MagickWandTerminus(). Hal ini mencegah masalah ketika thread worker OpenMP mengakses sumber daya yang telah dihancurkan oleh fungsi penghentian ini.

Jika OpenMP digunakan (mulai dari versi 5.0), implementasi OpenMP itu sendiri menangani proses memulai dan menghentikan thread worker serta mengalokasikan dan membebaskan sumber daya menggunakan metodenya sendiri. Ini berarti bahwa setelah memanggil MagickWandTerminus(), beberapa sumber daya dan thread worker OpenMP mungkin masih tetap teralokasi. Untuk mengatasi hal ini, fungsi omp_pause_resource_all(omp_pause_hard) dapat dipanggil. Fungsi ini, yang diperkenalkan pada OpenMP versi 5.0, memastikan bahwa semua sumber daya yang dialokasikan oleh OpenMP (seperti thread dan memori khusus thread) dibebaskan. Disarankan untuk memanggil fungsi ini setelah MagickWandTerminus() selesai dijalankan.

Contoh MagickWand dalam C menunjukkan cara menggunakan API MagickWand ImageMagick. Setiap contoh disajikan sebagai fungsi C, lengkap dengan header, sehingga dapat disalin ke file lalu disertakan dalam proyek C Anda sendiri.