MagickCore(底层 C API)
MagickCore API 是 C 编程语言与 ImageMagick 图像处理库之间的底层接口,仅推荐给巫师级别的程序员使用。与仅使用少数不透明类型和访问器的 MagickWand C API 不同,使用 MagickCore 时你几乎完全是直接访问结构体成员。MagickCore 公开方法的说明可在 GitHub 上找到:
- 初始化或销毁 ImageMagick 环境
- 构成图像(Constitute)
- 合成图像
- 图像方法
- 图像通道方法
- 统计图像中的颜色数
- 颜色映射表方法
- 色彩空间方法
- 图像扭曲
- 处理图像图层
- 处理图像配置文件
- 减少图像中的唯一颜色数
- 图像直方图
- 用模糊 c-均值阈值法对图像分割
- 调整图像尺寸
- 变换图像
- 按任意角度错切或旋转图像
- 增强图像
- 添加效果
- 形态学腐蚀、膨胀、开运算与闭运算
- 添加特殊效果
- 装饰图像
- 获取/设置图像属性
- 获取/设置图像属性(Properties)
- 获取图像统计信息
- 获取图像特征
- 为图像添加注释
- 在图像上绘画
- 在图像上绘图
- 创建图像缩略图
- 计算离散傅里叶变换(DFT)
- 将图像与重建图像比较
- 计算机视觉
- 交互式显示和编辑图像
- 交互式播放图像序列动画
- 与密文像素相互转换
- 处理图像列表
- 图像视图方法
- 获取或设置图像像素
- 处理缓存视图
- 像素 FIFO
- 读写二进制大对象
- 可加载模块
- 计算图像的消息摘要
- 图像注册表
- 处理异常
- 内存分配
- 监控或限制资源消耗
- 监控图像操作的进度
- 获取版本与版权信息
- Mime 方法
- 已弃用的方法
- 错误与警告代码
写好 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);
}
现在,我们利用 wand 视图并行运行算法,从而在执行相同的对比度增强时充分发挥双核或四核处理系统的优势。sigmoidal-contrast.c 模块读取一张图像,应用 S 形(sigmoidal)非线性对比度控制,并像之前的对比度增强程序一样将结果写入磁盘,但这次是并行完成(前提是 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() 执行完成后调用此函数。