Color Modes

MagickCore、低レベル C API

MagickCore API は、C プログラミング言語と ImageMagick 画像処理ライブラリ間の低レベルインターフェースであり、熟練プログラマーのみに推奨されます。いくつかの不透明な型とアクセサのみを使用する MagickWand C API とは異なり、MagickCore ではほぼ排他的に構造体のメンバーに直接アクセスします。MagickCore の公開メソッドの説明は、こちらにあります。

MagickCore プログラムを作成したら、次のようにコンパイルします。

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

ImageMagick がデフォルトのシステムパスにない場合は、PKG_CONFIG_PATH 環境変数を設定します。

export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig 

MagickCore API を使用して開始するためのサンプルプログラム core.c を示します。これは、GIF 画像を読み取り、サムネイルを作成し、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);
}

次に、デュアルまたはクアッドコア処理システムを利用して、同じコントラスト強調を並列に実行してみましょう。 sigmoidal-contrast.c モジュールは、画像を読み取り、シグモイド非線形コントラスト制御を適用し、前のコントラスト強調プログラムと同様に結果をディスクに書き込みますが、現在は並列で処理を行います(ImageMagick が 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() は、ImageMagick ライブラリの関数で、ImageMagick を使用するアプリケーションをシャットダウンするときに、リソースをクリーンアップして解放するために使用されます。この関数は、シャットダウンプロセス中にアプリケーションプロセスのプライマリスレッドで呼び出す必要があります。この関数が、ImageMagick 関数を使用しているすべてのスレッドが終了した後にのみ呼び出されることが重要です。

ImageMagick は、OpenMP (並列プログラミングの方法) を介して内部的にスレッドを使用する場合があります。その結果、MagickCoreTerminus() を呼び出す前に、ImageMagick へのすべての関数呼び出しが完了していることを確認することが重要です。これにより、この終了関数によって破棄されるリソースに OpenMP ワーカー スレッドがアクセスする問題を回避できます。

OpenMP を使用している場合(バージョン 5.0 から)、OpenMP の実装自体がワーカー スレッドの開始と停止を処理し、独自の方法を使用してリソースを割り当てて解放します。つまり、MagickCoreTerminus() を呼び出した後でも、一部の OpenMP リソースとワーカー スレッドが割り当てられたままになっている可能性があります。これに対処するために、関数 omp_pause_resource_all(omp_pause_hard) を呼び出すことができます。この関数は OpenMP バージョン 5.0 で導入され、OpenMP によって割り当てられたすべてのリソース(スレッドやスレッド固有のメモリなど)が解放されるようにします。MagickCoreTerminus() の実行が完了した後にこの関数を呼び出すことをお勧めします。