/* $Id: magick.c,v 1.46 2005/07/01 12:07:06 agraef Exp $ */
/* This file is part of the Q programming system.
The Q programming system is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
The Q programming system is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#if defined (HAVE_CONFIG_H)
# include "config.h"
#endif
#ifdef _WIN32
#define STDC_HEADERS 1
#define HAVE_STRDUP 1
#define HAVE_MEMCPY 1
#define HAVE_LIMITS_H 1
#include <windows.h>
#endif
/* system headers */
#include <stdio.h>
#include <ctype.h>
#include <math.h>
/* check for standard C headers */
#if STDC_HEADERS
# include <stdlib.h>
# include <string.h>
#else
# ifndef HAVE_STRCHR
# define strchr index
# define strrchr rindex
# endif
char *strchr (), *strrchr ();
#endif
#ifdef HAVE_MALLOC_H
#include <stdlib.h>
#endif
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef DMALLOC
#include <dmalloc.h>
#endif
#include <libq.h>
#include <magick/api.h>
#if MagickLibVersion < 0x550
#define ScaleQuantumToChar(quantum) Downscale(quantum)
#define PixelIntensityToQuantum(color) Intensity(color)
#define RLECompression RunlengthEncodedCompression
#define ScaleCharToQuantum(value) Upscale(value)
#define ScaleShortToQuantum(value) XDownscale(value)
#define ScaleQuantumToShort(quantum) XUpscale(quantum)
#endif
MODULE(magick)
static ExceptionInfo exception;
static char msg[1024];
static inline int
check_exception(ExceptionInfo *exception)
{
int res = exception->severity != UndefinedException;
if (res)
sprintf(msg, "%d: %s%s%s%s", exception->severity,
exception->reason?exception->reason:"ERROR",
exception->description?" (":"",
exception->description?exception->description:"",
exception->description?")":"");
else
*msg = 0;
SetExceptionInfo(exception, UndefinedException);
return res;
}
INIT(magick)
{
InitializeMagick("magick");
GetExceptionInfo(&exception);
}
FINI(magick)
{
DestroyMagick();
}
/* ByteStr data structure, see clib.c */
typedef struct bstr {
long size;
unsigned char *v;
} bstr_t;
/* manifest constants */
FUNCTION(magick,magick_vars,argc,argv)
{
if (argc != 0) return __FAIL;
return mktuplel
(84,
mkuint(NoCompression),
mkuint(BZipCompression),
mkuint(FaxCompression),
mkuint(Group4Compression),
mkuint(JPEGCompression),
mkuint(LosslessJPEGCompression),
mkuint(LZWCompression),
mkuint(RLECompression),
mkuint(ZipCompression),
mkuint(ForgetGravity),
mkuint(NorthWestGravity),
mkuint(NorthGravity),
mkuint(NorthEastGravity),
mkuint(WestGravity),
mkuint(CenterGravity),
mkuint(EastGravity),
mkuint(SouthWestGravity),
mkuint(SouthGravity),
mkuint(SouthEastGravity),
mkuint(StaticGravity),
mkuint(RGBColorspace),
mkuint(GRAYColorspace),
mkuint(TransparentColorspace),
mkuint(OHTAColorspace),
mkuint(XYZColorspace),
mkuint(YCbCrColorspace),
mkuint(YCCColorspace),
mkuint(YIQColorspace),
mkuint(YPbPrColorspace),
mkuint(YUVColorspace),
mkuint(CMYKColorspace),
mkuint(sRGBColorspace),
mkuint(PointFilter),
mkuint(BoxFilter),
mkuint(TriangleFilter),
mkuint(HermiteFilter),
mkuint(HanningFilter),
mkuint(HammingFilter),
mkuint(BlackmanFilter),
mkuint(GaussianFilter),
mkuint(QuadraticFilter),
mkuint(CubicFilter),
mkuint(CatromFilter),
mkuint(MitchellFilter),
mkuint(LanczosFilter),
mkuint(BesselFilter),
mkuint(SincFilter),
mkuint(OverCompositeOp),
mkuint(InCompositeOp),
mkuint(OutCompositeOp),
mkuint(AtopCompositeOp),
mkuint(XorCompositeOp),
mkuint(PlusCompositeOp),
mkuint(MinusCompositeOp),
mkuint(AddCompositeOp),
mkuint(SubtractCompositeOp),
mkuint(DifferenceCompositeOp),
mkuint(MultiplyCompositeOp),
mkuint(BumpmapCompositeOp),
mkuint(CopyCompositeOp),
mkuint(CopyRedCompositeOp),
mkuint(CopyGreenCompositeOp),
mkuint(CopyBlueCompositeOp),
mkuint(CopyOpacityCompositeOp),
mkuint(ClearCompositeOp),
mkuint(DissolveCompositeOp),
mkuint(DisplaceCompositeOp),
mkuint(ModulateCompositeOp),
mkuint(ThresholdCompositeOp),
mkuint(NoCompositeOp),
mkuint(DarkenCompositeOp),
mkuint(LightenCompositeOp),
mkuint(HueCompositeOp),
mkuint(SaturateCompositeOp),
mkuint(ColorizeCompositeOp),
mkuint(LuminizeCompositeOp),
mkuint(ScreenCompositeOp),
mkuint(OverlayCompositeOp),
mkuint(UniformNoise),
mkuint(GaussianNoise),
mkuint(MultiplicativeGaussianNoise),
mkuint(ImpulseNoise),
mkuint(LaplacianNoise),
mkuint(PoissonNoise)
);
}
FUNCTION(magick,magick_info,argc,argv)
{
const MagickInfo *info;
expr x;
if (argc != 0) return __FAIL;
info = GetMagickInfo("*", &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!info)
return __FAIL;
while (info->next) info = info->next;
/* we're at the last info record now */
x = mknil;
while (x && info) {
char mode[10];
sprintf(mode, "%c%c%c%c",
info->blob_support?'*':'-',
info->decoder?'r':'-',
info->encoder?'w':'-',
info->adjoin?'+':'-');
x = mkcons(mktuplel(4, mkstr(strdup(info->name?info->name:"")),
mkstr(strdup(mode)),
mkstr(strdup(info->description?info->description:"")),
mkstr(strdup(info->version?info->version:""))),
x);
info = info->previous;
}
return x;
}
FUNCTION(magick,magick_limit,argc,argv)
{
#if MagickLibVersion >= 0x550
char *res;
unsigned long limit;
if (argc == 2 && isstr(argv[0], &res) && isuint(argv[1], &limit)) {
#if 0 /* not supported */
if (!strcmp(res, "file"))
SetMagickResourceLimit(FileResource, limit);
else
#endif
if (!strcmp(res, "memory"))
SetMagickResourceLimit(MemoryResource, limit);
else if (!strcmp(res, "map"))
SetMagickResourceLimit(MapResource, limit);
else if (!strcmp(res, "disk"))
SetMagickResourceLimit(DiskResource, limit);
else
return __FAIL;
return mkvoid;
} else
#endif
return __FAIL;
}
FUNCTION(magick,magick_limits,argc,argv)
{
#if MagickLibVersion >= 0x550
if (argc == 0) {
ListMagickResourceInfo(stdout, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else
return mkvoid;
} else
#endif
return __FAIL;
}
FUNCTION(magick,magick_resources,argc,argv)
{
#if MagickLibVersion >= 0x550
if (argc == 0)
return mktuplel(4, mkuint(GetMagickResource(FileResource)),
mkuint(GetMagickResource(MemoryResource)),
mkuint(GetMagickResource(MapResource)),
mkuint(GetMagickResource(DiskResource)));
else
#endif
return __FAIL;
}
/* private image data; we use this to store the draw info and other
information needed by the operations of this module */
typedef struct {
DrawInfo *draw_info;
int tag;
} ImageData;
static inline ImageData *init_data(void)
{
ImageData *data = malloc(sizeof(ImageData));
if (data) {
data->draw_info = NULL;
data->tag = 0;
}
return data;
}
static inline DrawInfo *get_draw_info(Image *img)
{
ImageData *data = (ImageData*)img->client_data;
if (data) {
if (!data->draw_info)
data->draw_info = CloneDrawInfo(NULL, NULL);
return data->draw_info;
} else
return NULL;
}
/* image type */
DESTRUCTOR(magick,Image,ptr)
{
Image *img = (Image*)ptr;
if (img->client_data) {
ImageData *data = (ImageData*)img->client_data;
if (data->draw_info) DestroyDrawInfo(data->draw_info);
free(img->client_data);
}
DestroyImage(img);
}
static expr mk_image(Image *img)
{
img->scene = 0;
if ((img->client_data = init_data()))
return mkobj(type(Image), img);
else {
DestroyImage(img);
return __ERROR;
}
}
static void decompose_image_list(Image *img)
{
Image *tmp, *tmp2;
for (tmp = img; tmp; tmp = tmp2) {
tmp2 = tmp->next;
tmp->previous = tmp->next = NULL;
if (!tmp->client_data)
/* dispose temporary */
DestroyImage(tmp);
else
((ImageData*)tmp->client_data)->tag = 0;
}
}
static expr mk_image_list(Image *img)
{
expr x = mknil;
Image *imgs;
/* convert image sequence into list of images */
for (imgs = img; imgs->next; imgs = imgs->next)
;
/* imgs now points at the last image in the sequence */
while (x && imgs) {
Image *tmp = imgs->previous;
imgs->scene = 0;
if ((imgs->client_data = init_data()))
x = mkcons(mkobj(type(Image), imgs), x);
else {
dispose(x); x = __ERROR;
}
imgs = tmp;
}
if (x)
decompose_image_list(img);
else {
for (imgs = img; imgs; imgs = imgs->next)
if (imgs->client_data) free(imgs->client_data);
DestroyImageList(img);
}
return x;
}
static int is_image_list(expr x, Image **img)
{
expr y, hd, tl;
Image *tmp, *tmp2;
for (y = x; iscons(y, &hd, &tl); y = tl)
if (!(isobj(hd, type(Image), (void**)&tmp) &&
tmp->columns > 0 && tmp->rows > 0))
return 0;
if (!isnil(y)) return 0;
*img = NULL;
if (isnil(x)) return 1;
tmp2 = NULL;
for (y = x; iscons(y, &hd, &tl); y = tl) {
isobj(hd, type(Image), (void**)&tmp);
if (tmp->client_data && ((ImageData*)tmp->client_data)->tag) {
/* this image is already in the list, create a temporary copy */
tmp = CloneImage(tmp, 0, 0, 1, &exception);
if (check_exception(&exception)) {
decompose_image_list(*img);
return 0;
}
tmp->client_data = NULL;
} else
((ImageData*)tmp->client_data)->tag = 1;
if (tmp2) {
tmp->previous = tmp2;
tmp2->next = tmp;
} else
*img = tmp;
tmp2 = tmp;
}
return 1;
}
/* Read RGBA pixels from a buffer. The color values are scaled to 16 bit and
returned in RGBA order which matches the layout of GGI color values. */
static void get_pixels(unsigned char *dest, PixelPacket *source,
unsigned long count, unsigned matte)
{
unsigned long i;
register PixelPacket *p;
register unsigned short *q;
p = source;
q = (unsigned short*)dest;
if (matte)
for (i = 0; i < count; i++) {
*q++=ScaleQuantumToShort(p->red);
*q++=ScaleQuantumToShort(p->green);
*q++=ScaleQuantumToShort(p->blue);
*q++=ScaleQuantumToShort(MaxRGB-p->opacity);
p++;
}
else
for (i = 0; i < count; i++) {
*q++=ScaleQuantumToShort(p->red);
*q++=ScaleQuantumToShort(p->green);
*q++=ScaleQuantumToShort(p->blue);
*q++=ScaleQuantumToShort(MaxRGB);
p++;
}
}
/* Write RGBA pixels to a buffer. */
static void set_pixels(PixelPacket *dest, unsigned char *source,
unsigned long count, unsigned matte)
{
unsigned long i;
register unsigned short *p;
register PixelPacket *q;
p = (unsigned short*)source;
q = dest;
if (matte)
for (i = 0; i < count; i++) {
q->red=ScaleShortToQuantum(*p++);
q->green=ScaleShortToQuantum(*p++);
q->blue=ScaleShortToQuantum(*p++);
q->opacity=ScaleShortToQuantum(0xffff-*p++);
q++;
}
else
for (i = 0; i < count; i++) {
q->red=ScaleShortToQuantum(*p++);
q->green=ScaleShortToQuantum(*p++);
q->blue=ScaleShortToQuantum(*p++);
p++;
q++;
}
}
static inline expr mkpixel(PixelPacket *pixel)
{
bstr_t *m;
if (!(m = malloc(sizeof(bstr_t))) || !(m->v = malloc(8))) {
if (m) free(m); return __ERROR;
}
m->size = 8;
get_pixels(m->v, pixel, 1, 1);
return mkobj(type(ByteStr), m);
}
/* parse info tuples */
static int parse_info(int n, expr *xv, ImageInfo *info, int *_matte)
{
int i = 0;
unsigned long width, height, depth, offset, matte;
char *magick;
static char geom[100];
*_matte = -1;
if (i >= n) return 1;
if (!isuint(xv[i++], &width)) return 0;
if (i >= n) return 1;
if (!isuint(xv[i++], &height)) return 0;
if (width > 0 && height > 0) {
sprintf(geom, "%ux%u", width, height);
info->size = geom;
}
if (i >= n) return 1;
if (!isuint(xv[i++], &offset)) return 0;
if (offset > 0) {
sprintf(geom, "%ux%u+%u", width, height, offset);
info->size = geom;
}
if (i >= n) return 1;
if (!isuint(xv[i++], &depth) || depth > QuantumDepth) return 0;
if (depth > 0)
info->depth = depth;
if (i >= n) return 1;
if (!isuint(xv[i++], &matte) || matte > 1) return 0;
*_matte = (int)matte;
if (i >= n) return 1;
if (!isstr(xv[i++], &magick)) return 0;
strncpy(info->magick, magick, MaxTextExtent-1);
if (i >= n) return 1;
return 0;
}
/* compression info used by write_image and image_to_blob */
static int parse_info2(int n, expr *xv, ImageInfo *info)
{
int i = 0;
unsigned long compression, quality;
char *sampling_factor;
if (i >= n) return 1;
if (!isuint(xv[i++], &compression)) return 0;
info->compression = compression;
if (i >= n) return 1;
if (!isuint(xv[i++], &quality)) return 0;
info->quality = quality;
if (i >= n) return 1;
if (!isstr(xv[i++], &sampling_factor)) return 0;
info->sampling_factor = sampling_factor;
if (i >= n) return 1;
return 0;
}
FUNCTION(magick,image_info,argc,argv)
{
Image *img;
if (argc == 1 && isobj(argv[0], type(Image), (void**)&img))
return mktuplel(6, mkuint(img->columns), mkuint(img->rows),
mkuint(img->offset), mkuint(img->depth),
mkuint((unsigned long)img->matte),
mkstr(strdup(img->magick)));
else
return __FAIL;
}
FUNCTION(magick,draw_info,argc,argv)
{
Image *img;
DrawInfo *draw_info;
if (argc == 1 && isobj(argv[0], type(Image), (void**)&img) &&
(draw_info = get_draw_info(img))) {
expr font, tile;
if (draw_info->font)
font = mkstr(strdup(draw_info->font));
else
font = mkvoid;
if (draw_info->tile)
tile = mkobj(type(Image), ReferenceImage(draw_info->tile));
else
tile = mkvoid;
return mktuplel(11, font,
mkfloat(draw_info->pointsize),
mkuint(draw_info->gravity),
mkpixel(&draw_info->fill),
mkpixel(&draw_info->stroke),
mkpixel(&draw_info->undercolor),
mkpixel(&draw_info->border_color),
mkfloat(draw_info->stroke_width),
mkbool(draw_info->stroke_antialias),
mkbool(draw_info->text_antialias),
tile);
} else
return __FAIL;
}
FUNCTION(magick,type_metrics,argc,argv)
{
Image *img;
DrawInfo *draw_info;
if (argc == 1 && isobj(argv[0], type(Image), (void**)&img) &&
(draw_info = get_draw_info(img))) {
TypeMetric metrics;
if (GetTypeMetrics(img, draw_info, &metrics))
return mktuplel(9, mkfloat(metrics.pixels_per_em.x),
mkfloat(metrics.pixels_per_em.y),
mkfloat(metrics.ascent),
mkfloat(metrics.descent),
mkfloat(metrics.width),
mkfloat(metrics.height),
mkfloat(metrics.max_advance),
mkfloat(metrics.underline_position),
mkfloat(metrics.underline_thickness));
else
return __FAIL;
} else
return __FAIL;
}
FUNCTION(magick,set_draw_font,argc,argv)
{
Image *img;
DrawInfo *draw_info;
char *font = NULL;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
(draw_info = get_draw_info(img)) &&
(isvoid(argv[1]) || isstr(argv[1], &font)))
if (!font) {
LiberateMemory((void**)&draw_info->font);
return mkvoid;
} else if (CloneString(&draw_info->font, font))
return mkvoid;
else
return __FAIL;
else
return __FAIL;
}
FUNCTION(magick,set_draw_pointsize,argc,argv)
{
Image *img;
DrawInfo *draw_info;
double val;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
(draw_info = get_draw_info(img)) &&
(isfloat(argv[1], &val) || ismpz_float(argv[1], &val))) {
draw_info->pointsize = val;
return mkvoid;
} else
return __FAIL;
}
FUNCTION(magick,set_draw_gravity,argc,argv)
{
Image *img;
DrawInfo *draw_info;
unsigned long val;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
(draw_info = get_draw_info(img)) && isuint(argv[1], &val)) {
draw_info->gravity = val;
return mkvoid;
} else
return __FAIL;
}
FUNCTION(magick,set_draw_fill,argc,argv)
{
Image *img;
DrawInfo *draw_info;
bstr_t *m;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
(draw_info = get_draw_info(img)) &&
isobj(argv[1], type(ByteStr), (void**)&m) && m->size == 8) {
set_pixels(&draw_info->fill, m->v, 1, 1);
return mkvoid;
} else
return __FAIL;
}
FUNCTION(magick,set_draw_stroke,argc,argv)
{
Image *img;
DrawInfo *draw_info;
bstr_t *m;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
(draw_info = get_draw_info(img)) &&
isobj(argv[1], type(ByteStr), (void**)&m) && m->size == 8) {
set_pixels(&draw_info->stroke, m->v, 1, 1);
return mkvoid;
} else
return __FAIL;
}
FUNCTION(magick,set_draw_undercolor,argc,argv)
{
Image *img;
DrawInfo *draw_info;
bstr_t *m;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
(draw_info = get_draw_info(img)) &&
isobj(argv[1], type(ByteStr), (void**)&m) && m->size == 8) {
set_pixels(&draw_info->undercolor, m->v, 1, 1);
return mkvoid;
} else
return __FAIL;
}
FUNCTION(magick,set_draw_border_color,argc,argv)
{
Image *img;
DrawInfo *draw_info;
bstr_t *m;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
(draw_info = get_draw_info(img)) &&
isobj(argv[1], type(ByteStr), (void**)&m) && m->size == 8) {
set_pixels(&draw_info->border_color, m->v, 1, 1);
return mkvoid;
} else
return __FAIL;
}
FUNCTION(magick,set_draw_stroke_width,argc,argv)
{
Image *img;
DrawInfo *draw_info;
double val;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
(draw_info = get_draw_info(img)) &&
(isfloat(argv[1], &val) || ismpz_float(argv[1], &val))) {
draw_info->stroke_width = val;
return mkvoid;
} else
return __FAIL;
}
FUNCTION(magick,set_draw_stroke_antialias,argc,argv)
{
Image *img;
DrawInfo *draw_info;
int val;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
(draw_info = get_draw_info(img)) && isbool(argv[1], &val)) {
draw_info->stroke_antialias = val;
return mkvoid;
} else
return __FAIL;
}
FUNCTION(magick,set_draw_text_antialias,argc,argv)
{
Image *img;
DrawInfo *draw_info;
int val;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
(draw_info = get_draw_info(img)) && isbool(argv[1], &val)) {
draw_info->text_antialias = val;
return mkvoid;
} else
return __FAIL;
}
FUNCTION(magick,set_draw_tile,argc,argv)
{
Image *img, *tile = NULL;
DrawInfo *draw_info;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
(draw_info = get_draw_info(img)) &&
(isvoid(argv[1]) || isobj(argv[1], type(Image), (void**)&tile))) {
if (tile) {
/* we better clone the image here, to avoid nasty circular references */
tile = CloneImage(tile, 0, 0, 1, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (tile)
draw_info->tile = tile;
else
return __FAIL;
} else {
if (draw_info->tile) DestroyImage(draw_info->tile);
draw_info->tile = NULL;
}
return mkvoid;
} else
return __FAIL;
}
FUNCTION(magick,image_background_color,argc,argv)
{
Image *img;
if (argc == 1 && isobj(argv[0], type(Image), (void**)&img)) {
bstr_t *m;
if (!(m = malloc(sizeof(bstr_t))) || !(m->v = malloc(8))) {
if (m) free(m); return __ERROR;
}
m->size = 8;
get_pixels(m->v, &img->background_color, 1, img->matte);
return mkobj(type(ByteStr), m);
} else
return __FAIL;
}
FUNCTION(magick,set_image_background_color,argc,argv)
{
Image *img;
bstr_t *m;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
isobj(argv[1], type(ByteStr), (void**)&m) && m->size == 8) {
set_pixels(&img->background_color, m->v, 1, 1);
return mkvoid;
} else
return __FAIL;
}
FUNCTION(magick,image_border_color,argc,argv)
{
Image *img;
if (argc == 1 && isobj(argv[0], type(Image), (void**)&img)) {
bstr_t *m;
if (!(m = malloc(sizeof(bstr_t))) || !(m->v = malloc(8))) {
if (m) free(m); return __ERROR;
}
m->size = 8;
get_pixels(m->v, &img->border_color, 1, img->matte);
return mkobj(type(ByteStr), m);
} else
return __FAIL;
}
FUNCTION(magick,set_image_border_color,argc,argv)
{
Image *img;
bstr_t *m;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
isobj(argv[1], type(ByteStr), (void**)&m) && m->size == 8) {
set_pixels(&img->border_color, m->v, 1, 1);
return mkvoid;
} else
return __FAIL;
}
FUNCTION(magick,image_matte_color,argc,argv)
{
Image *img;
if (argc == 1 && isobj(argv[0], type(Image), (void**)&img)) {
bstr_t *m;
if (!(m = malloc(sizeof(bstr_t))) || !(m->v = malloc(8))) {
if (m) free(m); return __ERROR;
}
m->size = 8;
get_pixels(m->v, &img->matte_color, 1, img->matte);
return mkobj(type(ByteStr), m);
} else
return __FAIL;
}
FUNCTION(magick,set_image_matte_color,argc,argv)
{
Image *img;
bstr_t *m;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
isobj(argv[1], type(ByteStr), (void**)&m) && m->size == 8) {
set_pixels(&img->matte_color, m->v, 1, 1);
return mkvoid;
} else
return __FAIL;
}
FUNCTION(magick,image_compression,argc,argv)
{
Image *img;
if (argc == 1 && isobj(argv[0], type(Image), (void**)&img))
return mkuint(img->compression);
else
return __FAIL;
}
FUNCTION(magick,set_image_compression,argc,argv)
{
Image *img;
unsigned long compression;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
isuint(argv[1], &compression)) {
img->compression = compression;
return mkvoid;
} else
return __FAIL;
}
FUNCTION(magick,image_fuzz,argc,argv)
{
Image *img;
if (argc == 1 && isobj(argv[0], type(Image), (void**)&img))
return mkfloat(img->fuzz);
else
return __FAIL;
}
FUNCTION(magick,set_image_fuzz,argc,argv)
{
Image *img;
double fuzz;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
(isfloat(argv[1], &fuzz) || ismpz_float(argv[1], &fuzz))) {
img->fuzz = fuzz;
return mkvoid;
} else
return __FAIL;
}
FUNCTION(magick,image_page,argc,argv)
{
Image *img;
if (argc == 1 && isobj(argv[0], type(Image), (void**)&img))
return mktuplel(4, mkint(img->page.x), mkint(img->page.y),
mkuint(img->page.width), mkuint(img->page.height));
else
return __FAIL;
}
FUNCTION(magick,set_image_page,argc,argv)
{
Image *img;
int n;
expr *xv;
long x, y;
unsigned long w, h;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
istuple(argv[1], &n, &xv)) {
if (n == 2)
if (isint(xv[0], &x) && isint(xv[1], &y)) {
img->page.x = x;
img->page.y = y;
} else
return __FAIL;
else if (n == 4)
if (isint(xv[0], &x) && isint(xv[1], &y) &&
isuint(xv[2], &w) && isuint(xv[3], &h)) {
img->page.x = x;
img->page.y = y;
img->page.width = w;
img->page.height = h;
} else
return __FAIL;
else
return __FAIL;
return mkvoid;
} else
return __FAIL;
}
FUNCTION(magick,image_attr,argc,argv)
{
Image *img;
char *key;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
isstr(argv[1], &key)) {
const ImageAttribute *attr = GetImageAttribute(img, key);
if (attr)
return mkstr(strdup(attr->value));
else
return __FAIL;
} else
return __FAIL;
}
FUNCTION(magick,set_image_attr,argc,argv)
{
Image *img;
char *key, *val = NULL;
if (argc == 3 && isobj(argv[0], type(Image), (void**)&img) &&
isstr(argv[1], &key) &&
(isvoid(argv[2]) || isstr(argv[2], &val))) {
SetImageAttribute(img, key, val);
return mkvoid;
} else
return __FAIL;
}
FUNCTION(magick,count_image_colors,argc,argv)
{
Image *img;
if (argc == 1 && isobj(argv[0], type(Image), (void**)&img)) {
unsigned long colors = GetNumberColors(img, NULL, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else
return mkuint(colors);
} else
return __FAIL;
}
FUNCTION(magick,is_gray_image,argc,argv)
{
Image *img;
if (argc == 1 && isobj(argv[0], type(Image), (void**)&img)) {
unsigned res = IsGrayImage(img, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else
return mkbool(res);
} else
return __FAIL;
}
FUNCTION(magick,is_monochrome_image,argc,argv)
{
Image *img;
if (argc == 1 && isobj(argv[0], type(Image), (void**)&img)) {
unsigned res = IsMonochromeImage(img, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else
return mkbool(res);
} else
return __FAIL;
}
FUNCTION(magick,is_opaque_image,argc,argv)
{
Image *img;
if (argc == 1 && isobj(argv[0], type(Image), (void**)&img)) {
unsigned res = IsOpaqueImage(img, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else
return mkbool(res);
} else
return __FAIL;
}
FUNCTION(magick,is_palette_image,argc,argv)
{
Image *img;
if (argc == 1 && isobj(argv[0], type(Image), (void**)&img)) {
unsigned res = IsPaletteImage(img, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else
return mkbool(res);
} else
return __FAIL;
}
FUNCTION(magick,magick_pixel,argc,argv)
{
char *s;
expr *xv, x, hd, tl;
int n;
unsigned long r, g, b, a = 0xffff;
PixelPacket pixel;
bstr_t *m;
char *v;
if (argc != 1) return __FAIL;
/* treat the case of a single color value: */
if (isstr(argv[0], &s)) {
if (!QueryColorDatabase(s, &pixel, &exception))
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else
return __FAIL;
} else if (istuple(argv[0], &n, &xv) && n >= 3 && n <= 4 &&
isuint(xv[0], &r) && isuint(xv[1], &g) && isuint(xv[2], &b) &&
(n == 3 || isuint(xv[3], &a)) &&
r <= 0xffff && g <= 0xffff && b <= 0xffff && a <= 0xffff) {
pixel.red = ScaleShortToQuantum(r);
pixel.green = ScaleShortToQuantum(g);
pixel.blue = ScaleShortToQuantum(b);
pixel.opacity = ScaleShortToQuantum(0xffff-a);
} else
goto skip;
if (!(m = malloc(sizeof(bstr_t))) || !(m->v = malloc(8))) {
if (m) free(m); return __ERROR;
}
m->size = 8;
get_pixels(m->v, &pixel, 1, 1);
return mkobj(type(ByteStr), m);
skip:
/* if we come here, we should deal with a list of color values */
for (n = 0, x = argv[0]; iscons(x, &hd, &tl); x = tl) n++;
if (!isnil(x)) return __FAIL;
if (n == 0) {
if (!(m = malloc(sizeof(bstr_t)))) return __ERROR;
m->size = 0;
m->v = NULL;
return mkobj(type(ByteStr), m);
}
if (n < 0 || ULONG_MAX/8 < n) return __ERROR;
if (!(m = malloc(sizeof(bstr_t))) || !(m->v = malloc(n*8))) {
if (m) free(m); return __ERROR;
}
m->size = n*8;
for (v = m->v, x = argv[0]; iscons(x, &hd, &tl); x = tl, v += 8) {
if (isstr(hd, &s)) {
if (!QueryColorDatabase(s, &pixel, &exception))
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else {
free(m->v); free(m);
return __FAIL;
}
} else if (istuple(hd, &n, &xv) && n >= 3 && n <= 4 &&
isuint(xv[0], &r) && isuint(xv[1], &g) && isuint(xv[2], &b) &&
(n == 3 || isuint(xv[3], &a)) &&
r <= 0xffff && g <= 0xffff && b <= 0xffff && a <= 0xffff) {
pixel.red = ScaleShortToQuantum(r);
pixel.green = ScaleShortToQuantum(g);
pixel.blue = ScaleShortToQuantum(b);
pixel.opacity = ScaleShortToQuantum(0xffff-a);
} else {
free(m->v); free(m);
return __FAIL;
}
get_pixels(v, &pixel, 1, 1);
}
return mkobj(type(ByteStr), m);
}
FUNCTION(magick,magick_color,argc,argv)
{
bstr_t *m;
if (argc == 1 && isobj(argv[0], type(ByteStr), (void**)&m) &&
m->size%8 == 0) {
if (m->size == 0)
return mknil;
else if (m->size == 8) {
unsigned short *v = (unsigned short*)m->v;
unsigned short r, g, b, a;
r = *v++; g = *v++; b = *v++; a = *v++;
return mktuplel(4, mkuint(r), mkuint(g), mkuint(b), mkuint(a));
} else {
expr x = mknil;
int i, n = m->size/8;
unsigned short *v = (unsigned short*)(m->v+m->size);
unsigned short r, g, b, a;
for (i = 0; x && i < n; i++) {
a = *--v; b = *--v; g = *--v; r = *--v;
x = mkcons(mktuplel(4, mkuint(r), mkuint(g), mkuint(b), mkuint(a)),
x);
}
return x;
}
} else
return __FAIL;
}
FUNCTION(magick,magick_colors,argc,argv)
{
char *s;
if (argc == 1 && isstr(argv[0], &s)) {
#if MagickLibVersion < 0x550
int n;
#else
unsigned long n;
#endif
#if MagickLibVersion < 0x610
char **color_list = GetColorList(s, &n);
#else
char **color_list = GetColorList(s, &n, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else
#endif
if (color_list) {
expr *x = mknil;
while (n > 0 && x)
x = mkcons(mkstr(color_list[--n]), x);
return x;
} else
return __FAIL;
} else
return __FAIL;
}
FUNCTION(magick,create_image,argc,argv)
{
expr *xv = NULL;
int n = 0;
bstr_t *m;
unsigned long w, h;
if (argc == 2 && istuple(argv[0], &n, &xv) && n >= 2 &&
isuint(xv[0], &w) && isuint(xv[1], &h) && w > 0 && h > 0 &&
isobj(argv[1], type(ByteStr), (void**)&m)) {
unsigned long size = w*h*8;
ImageInfo info;
Image *img;
int matte;
GetImageInfo(&info);
if (ULONG_MAX/8 < w*h || m->size != 8 && m->size != size ||
!parse_info(n, xv, &info, &matte))
return __FAIL;
img = AllocateImage(&info);
if (!img)
return __ERROR;
else {
PixelPacket *pixels;
if (matte >= 0) img->matte = (unsigned)matte;
if (!(pixels = SetImagePixels(img, 0, 0, w, h))) {
DestroyImage(img);
return __FAIL;
}
if (m->size > 8)
set_pixels(pixels, m->v, w*h, img->matte);
else {
unsigned long x, y;
for (y = 0; y < h; y++, pixels += w)
for (x = 0; x < w; x++)
set_pixels(pixels+x, m->v, 1, img->matte);
}
img->storage_class = DirectClass;
if (SyncImagePixels(img))
return mk_image(img);
else {
DestroyImage(img);
return __FAIL;
}
}
} else
return __FAIL;
}
FUNCTION(magick,clone_image,argc,argv)
{
Image *img;
if (argc == 1 && isobj(argv[0], type(Image), (void**)&img)) {
img = CloneImage(img, 0, 0, 1, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __ERROR;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,read_image,argc,argv)
{
char *s;
expr *xv = NULL;
int n = 0;
if (argc == 2 && isstr(argv[0], &s) &&
(istuple(argv[1], &n, &xv) || isvoid(argv[1]))) {
ImageInfo info;
Image *img;
int matte;
GetImageInfo(&info);
if (!parse_info(n, xv, &info, &matte))
return __FAIL;
strncpy(info.filename, s, MaxTextExtent-1);
img = ReadImage(&info, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
if (!img)
return __FAIL;
else if (img->next) {
Image *imgs;
if (matte >= 0)
for (imgs = img; imgs; imgs = imgs->next)
imgs->matte = (unsigned)matte;
return mk_image_list(img);
} else {
if (matte >= 0) img->matte = (unsigned)matte;
return mk_image(img);
}
} else
return __FAIL;
}
FUNCTION(magick,ping_image,argc,argv)
{
char *s;
expr *xv = NULL;
int n = 0;
if (argc == 2 && isstr(argv[0], &s) &&
(istuple(argv[1], &n, &xv) || isvoid(argv[1]))) {
ImageInfo info;
Image *img;
int matte;
GetImageInfo(&info);
if (!parse_info(n, xv, &info, &matte))
return __FAIL;
strncpy(info.filename, s, MaxTextExtent-1);
img = PingImage(&info, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
if (!img)
return __FAIL;
else if (img->next) {
Image *imgs;
if (matte >= 0)
for (imgs = img; imgs; imgs = imgs->next)
imgs->matte = (unsigned)matte;
return mk_image_list(img);
} else {
if (matte >= 0) img->matte = (unsigned)matte;
return mk_image(img);
}
} else
return __FAIL;
}
FUNCTION(magick,write_image,argc,argv)
{
char *s;
expr *xv = NULL;
int n = 0;
if (argc == 3 && isstr(argv[0], &s)) {
Image *img = NULL;
ImageInfo info;
int res;
if (isnil(argv[1]))
return __FAIL;
GetImageInfo(&info);
if (!isvoid(argv[2]) && !istuple(argv[2], &n, &xv)) {
xv = argv+2;
n = 1;
}
if (!parse_info2(n, xv, &info))
return __FAIL;
if (is_image_list(argv[1], &img)) {
res = WriteImages(&info, img, s, &exception);
decompose_image_list(img);
} else {
/* must be a singleton image */
if (!(isobj(argv[1], type(Image), (void**)&img) &&
img->columns > 0 && img->rows > 0))
return __FAIL;
strncpy(img->filename, s, MaxTextExtent-1);
res = WriteImage(&info, img);
exception = img->exception;
}
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!res)
return __FAIL;
else
return mkvoid;
} else
return __FAIL;
}
FUNCTION(magick,image_to_blob,argc,argv)
{
char *s = NULL;
Image *img;
expr *xv;
int n = 0;
if (argc == 3 &&
(isobj(argv[1], type(Image), (void**)&img) ||
is_image_list(argv[1], &img)) &&
img->columns > 0 && img->rows > 0 &&
(isvoid(argv[0]) && *img->magick || isstr(argv[0], &s) && *s)) {
ImageInfo info;
size_t len;
void *blob;
bstr_t *m;
char magick[MaxTextExtent];
GetImageInfo(&info);
if (!isvoid(argv[2]) && !istuple(argv[2], &n, &xv)) {
xv = argv+2;
n = 1;
}
if (!parse_info2(n, xv, &info))
return __FAIL;
if (s) {
strncpy(magick, img->magick, MaxTextExtent-1);
strncpy(img->magick, s, MaxTextExtent-1);
}
blob = ImageToBlob(&info, img, &len, &exception);
decompose_image_list(img);
if (s)
strncpy(img->magick, magick, MaxTextExtent-1);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!blob)
return __FAIL;
else if ((int)len < 0 || !(m = malloc(sizeof(bstr_t)))) {
free(blob);
return __ERROR;
} else {
m->size = (int)len;
m->v = (char*)blob;
return mkobj(type(ByteStr), m);
}
} else
return __FAIL;
}
FUNCTION(magick,blob_to_image,argc,argv)
{
bstr_t *m;
expr *xv = NULL;
int n = 0;
if (argc == 2 && isobj(argv[0], type(ByteStr), (void**)&m) &&
m->size > 0 &&
(istuple(argv[1], &n, &xv) || isvoid(argv[1]))) {
ImageInfo info;
Image *img;
int matte;
size_t len = (size_t)m->size;
void *blob = m->v;
GetImageInfo(&info);
if (!parse_info(n, xv, &info, &matte))
return __FAIL;
img = BlobToImage(&info, blob, len, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
if (!img)
return __FAIL;
else if (img->next) {
Image *imgs;
if (matte >= 0)
for (imgs = img; imgs; imgs = imgs->next)
imgs->matte = (unsigned)matte;
return mk_image_list(img);
} else {
if (matte >= 0) img->matte = (unsigned)matte;
return mk_image(img);
}
} else
return __FAIL;
}
FUNCTION(magick,get_image_pixels,argc,argv)
{
Image *img;
expr *xv;
int n;
long x, y;
unsigned long w, h;
PixelPacket *pixels;
if (argc == 3 && isobj(argv[0], type(Image), (void**)&img) &&
istuple(argv[1], &n, &xv) && n == 2 &&
isint(xv[0], &x) && isint(xv[1], &y) &&
istuple(argv[2], &n, &xv) && n == 2 &&
isuint(xv[0], &w) && isuint(xv[1], &h) &&
(pixels = GetImagePixels(img, x, y, w, h))) {
unsigned long size = w*h*8;
bstr_t *m;
if (ULONG_MAX/8 < w*h) return __ERROR;
if (!(m = malloc(sizeof(bstr_t)))) return __ERROR;
if (size == 0) {
m->size = 0;
m->v = NULL;
return mkobj(type(ByteStr), m);
} else if (!(m->v = malloc(size))) {
free(m);
return __ERROR;
}
m->size = size;
get_pixels(m->v, pixels, w*h, img->matte);
return mkobj(type(ByteStr), m);
} else
return __FAIL;
}
FUNCTION(magick,set_image_pixels,argc,argv)
{
Image *img;
expr *xv;
int n;
long x, y;
unsigned long w, h;
bstr_t *m;
PixelPacket *pixels;
if (argc == 4 && isobj(argv[0], type(Image), (void**)&img) &&
istuple(argv[1], &n, &xv) && n == 2 &&
isint(xv[0], &x) && isint(xv[1], &y) &&
istuple(argv[2], &n, &xv) && n == 2 &&
isuint(xv[0], &w) && isuint(xv[1], &h) &&
isobj(argv[3], type(ByteStr), (void**)&m)) {
unsigned long size = w*h*8;
if (ULONG_MAX/8 < w*h || size != m->size)
return __FAIL;
else if (size == 0)
return mkvoid;
if (!(pixels = SetImagePixels(img, x, y, w, h)))
return __FAIL;
set_pixels(pixels, m->v, w*h, img->matte);
img->storage_class = DirectClass;
if (SyncImagePixels(img))
return mkvoid;
else
return __FAIL;
} else
return __FAIL;
}
FUNCTION(magick,quantize,argc,argv)
{
Image *img = NULL, *imgs = NULL, *img2 = NULL;
unsigned long space = RGBColorspace, ncolors = 255;
int dither = 0, res;
int n;
expr *xv;
if (argc == 2 &&
(isobj(argv[0], type(Image), (void**)&img) ||
is_image_list(argv[0], &imgs)) &&
(isuint(argv[1], &space) ||
isobj(argv[1], type(Image), (void**)&img2) ||
istuple(argv[1], &n, &xv) &&
(n == 1 &&
(isuint(xv[0], &space) ||
isobj(xv[0], type(Image), (void**)&img2)) ||
n == 2 &&
(isuint(xv[0], &space) &&
(isuint(xv[1], &ncolors) || isbool(xv[1], &dither)) ||
isobj(xv[0], type(Image), (void**)&img2) &&
isbool(xv[1], &dither)) ||
n == 3 &&
isuint(xv[0], &space) &&
isuint(xv[1], &ncolors) &&
isbool(xv[2], &dither))) &&
ncolors <= MaxRGB) {
if (img2) {
if (imgs) {
res = MapImages(imgs, img2, dither);
decompose_image_list(imgs);
} else
res = MapImage(img, img2, dither);
} else {
QuantizeInfo info;
GetQuantizeInfo(&info);
info.dither = dither;
info.number_colors = ncolors;
info.colorspace = space;
if (imgs) {
res = QuantizeImages(&info, imgs);
decompose_image_list(imgs);
} else
res = QuantizeImage(&info, img);
}
if (res)
return mkvoid;
else
return __FAIL;
} else
return __FAIL;
}
FUNCTION(magick,chop,argc,argv)
{
Image *img;
int n;
expr *xv;
long x, y;
unsigned long w, h;
if (argc == 3 && isobj(argv[0], type(Image), (void**)&img) &&
istuple(argv[1], &n, &xv) &&
isint(xv[0], &x) && isint(xv[1], &y) &&
istuple(argv[2], &n, &xv) && n == 2 &&
isuint(xv[0], &w) && isuint(xv[1], &h)) {
RectangleInfo info;
info.x = x; info.y = y;
info.width = w; info.height = h;
img = ChopImage(img, &info, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,crop,argc,argv)
{
Image *img;
int n;
expr *xv;
long x, y;
unsigned long w, h;
if (argc == 3 && isobj(argv[0], type(Image), (void**)&img) &&
istuple(argv[1], &n, &xv) &&
isint(xv[0], &x) && isint(xv[1], &y) &&
istuple(argv[2], &n, &xv) && n == 2 &&
isuint(xv[0], &w) && isuint(xv[1], &h)) {
RectangleInfo info;
info.x = x; info.y = y;
info.width = w; info.height = h;
img = CropImage(img, &info, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,roll,argc,argv)
{
Image *img;
int n;
expr *xv;
long x, y;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
istuple(argv[1], &n, &xv) && n == 2 &&
isint(xv[0], &x) && isint(xv[1], &y)) {
img = RollImage(img, x, y, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,shave,argc,argv)
{
Image *img;
int n;
expr *xv;
unsigned long w, h;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
istuple(argv[1], &n, &xv) && n == 2 &&
isuint(xv[0], &w) && isuint(xv[1], &h)) {
RectangleInfo info;
info.x = 0; info.y = 0;
info.width = w; info.height = h;
img = ShaveImage(img, &info, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,magnify,argc,argv)
{
Image *img;
if (argc == 1 && isobj(argv[0], type(Image), (void**)&img)) {
img = MagnifyImage(img, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,minify,argc,argv)
{
Image *img;
if (argc == 1 && isobj(argv[0], type(Image), (void**)&img)) {
img = MinifyImage(img, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,resize,argc,argv)
{
Image *img;
int n;
expr *xv;
unsigned long w, h, filter;
double blur;
if (argc == 4 && isobj(argv[0], type(Image), (void**)&img) &&
istuple(argv[1], &n, &xv) && n == 2 &&
isuint(xv[0], &w) && isuint(xv[1], &h) &&
isuint(argv[2], &filter) &&
(isfloat(argv[3], &blur) || ismpz_float(argv[3], &blur))) {
img = ResizeImage(img, w, h, filter, blur, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,sample,argc,argv)
{
Image *img;
int n;
expr *xv;
unsigned long w, h;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
istuple(argv[1], &n, &xv) && n == 2 &&
isuint(xv[0], &w) && isuint(xv[1], &h)) {
img = SampleImage(img, w, h, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,scale,argc,argv)
{
Image *img;
int n;
expr *xv;
unsigned long w, h;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
istuple(argv[1], &n, &xv) && n == 2 &&
isuint(xv[0], &w) && isuint(xv[1], &h)) {
img = ScaleImage(img, w, h, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,thumbnail,argc,argv)
{
#if MagickLibVersion >= 0x550
Image *img;
int n;
expr *xv;
unsigned long w, h;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
istuple(argv[1], &n, &xv) && n == 2 &&
isuint(xv[0], &w) && isuint(xv[1], &h)) {
img = ThumbnailImage(img, w, h, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
#endif
return __FAIL;
}
FUNCTION(magick,flipx,argc,argv)
{
Image *img;
if (argc == 1 && isobj(argv[0], type(Image), (void**)&img)) {
img = FlopImage(img, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,flipy,argc,argv)
{
Image *img;
if (argc == 1 && isobj(argv[0], type(Image), (void**)&img)) {
img = FlipImage(img, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,rotate,argc,argv)
{
Image *img;
double angle;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
(isfloat(argv[1], &angle) || ismpz_float(argv[1], &angle))) {
img = RotateImage(img, angle, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,shear,argc,argv)
{
Image *img;
int n;
expr *xv;
double xshear, yshear;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
istuple(argv[1], &n, &xv) && n == 2 &&
(isfloat(xv[0], &xshear) || ismpz_float(xv[0], &xshear)) &&
(isfloat(xv[1], &yshear) || ismpz_float(xv[1], &yshear))) {
img = ShearImage(img, xshear, yshear, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,affine_transform,argc,argv)
{
Image *img;
int n;
expr *xv;
AffineMatrix matrix;
if (argc == 3 && isobj(argv[0], type(Image), (void**)&img) &&
istuple(argv[1], &n, &xv) && n == 4 &&
(isfloat(xv[0], &matrix.sx) || ismpz_float(xv[0], &matrix.sx)) &&
(isfloat(xv[1], &matrix.rx) || ismpz_float(xv[1], &matrix.rx)) &&
(isfloat(xv[2], &matrix.ry) || ismpz_float(xv[2], &matrix.ry)) &&
(isfloat(xv[3], &matrix.sy) || ismpz_float(xv[3], &matrix.sy)) &&
istuple(argv[2], &n, &xv) && n == 2 &&
(isfloat(xv[0], &matrix.tx) || ismpz_float(xv[0], &matrix.tx)) &&
(isfloat(xv[1], &matrix.ty) || ismpz_float(xv[1], &matrix.ty))) {
img = AffineTransformImage(img, &matrix, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,coalesce,argc,argv)
{
Image *imgs;
if (argc == 1 && is_image_list(argv[0], &imgs) && imgs) {
Image *img = CoalesceImages(imgs, &exception);
decompose_image_list(imgs);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image_list(img);
} else
return __FAIL;
}
FUNCTION(magick,flatten,argc,argv)
{
Image *imgs;
if (argc == 1 && is_image_list(argv[0], &imgs) && imgs) {
Image *img = FlattenImages(imgs, &exception);
decompose_image_list(imgs);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,mosaic,argc,argv)
{
Image *imgs;
if (argc == 1 && is_image_list(argv[0], &imgs) && imgs) {
Image *img = MosaicImages(imgs, &exception);
decompose_image_list(imgs);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
/* info structure used by montage */
static int parse_montage_info(int n, expr *xv, MontageInfo *info)
{
int i = 0, b;
unsigned long u;
double f;
char *s;
bstr_t *m;
if (i >= n) return 1;
s = NULL;
if (!isvoid(xv[i]) && !isstr(xv[i], &s)) return 0;
if (s) info->title = s;
i++;
if (i >= n) return 1;
s = NULL;
if (!isvoid(xv[i]) && !isstr(xv[i], &s)) return 0;
if (s) info->tile = s;
i++;
if (i >= n) return 1;
s = NULL;
if (!isvoid(xv[i]) && !isstr(xv[i], &s)) return 0;
if (s) info->geometry = s;
i++;
if (i >= n) return 1;
s = NULL;
if (!isvoid(xv[i]) && !isstr(xv[i], &s)) return 0;
if (s) info->frame = s;
i++;
if (i >= n) return 1;
if (!isuint(xv[i++], &u)) return 0;
if (u > 0) info->border_width = u;
if (i >= n) return 1;
if (!isbool(xv[i++], &b)) return 0;
info->shadow = b;
if (i >= n) return 1;
s = NULL;
if (!isvoid(xv[i]) && !isstr(xv[i], &s)) return 0;
if (s) info->texture = s;
i++;
if (i >= n) return 1;
s = NULL;
if (!isvoid(xv[i]) && !isstr(xv[i], &s)) return 0;
if (s) info->font = s;
i++;
if (i >= n) return 1;
if (!isfloat(xv[i], &f) && !ismpz_float(xv[i], &f)) return 0;
if (f > 0.0) info->pointsize = f;
i++;
if (i >= n) return 1;
if (!isobj(xv[i++], type(ByteStr), (void**)&m) || m->size != 8) return 0;
set_pixels(&info->background_color, m->v, 1, 1);
if (i >= n) return 1;
if (!isobj(xv[i++], type(ByteStr), (void**)&m) || m->size != 8) return 0;
set_pixels(&info->fill, m->v, 1, 1);
if (i >= n) return 1;
if (!isobj(xv[i++], type(ByteStr), (void**)&m) || m->size != 8) return 0;
set_pixels(&info->matte_color, m->v, 1, 1);
if (i >= n) return 1;
return 0;
}
FUNCTION(magick,montage,argc,argv)
{
static int montage_init = 0;
static MontageInfo montage_info0;
Image *imgs;
if (argc == 2 && is_image_list(argv[0], &imgs) && imgs) {
Image *img, *next;
MontageInfo montage_info;
int n;
expr *xv;
if (!montage_init) {
/* this is only initialized once */
ImageInfo image_info;
GetImageInfo(&image_info);
GetMontageInfo(&image_info, &montage_info0);
montage_init = 1;
}
montage_info = montage_info0;
if (!istuple(argv[1], &n, &xv)) {
n = 1;
xv = argv+1;
}
if (!parse_montage_info(n, xv, &montage_info))
return __FAIL;
img = MontageImages(imgs, &montage_info, &exception);
decompose_image_list(imgs);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else if (img->next)
return mk_image_list(img);
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,deconstruct,argc,argv)
{
Image *imgs;
if (argc == 1 && is_image_list(argv[0], &imgs) && imgs) {
Image *img = DeconstructImages(imgs, &exception);
decompose_image_list(imgs);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image_list(img);
} else
return __FAIL;
}
FUNCTION(magick,segment,argc,argv)
{
Image *img;
unsigned long space;
int verbose;
double cluster, smooth;
if (argc == 5 && isobj(argv[0], type(Image), (void**)&img) &&
isuint(argv[1], &space) &&
isbool(argv[2], &verbose) &&
(isfloat(argv[3], &cluster) || ismpz_float(argv[3], &cluster)) &&
(isfloat(argv[4], &smooth) || ismpz_float(argv[4], &smooth))) {
int res = SegmentImage(img, space, verbose, cluster, smooth);
if (!res)
return __FAIL;
else
return mkvoid;
} else
return __FAIL;
}
FUNCTION(magick,composite,argc,argv)
{
Image *img, *img2;
unsigned long op;
long x, y;
int n;
expr *xv;
if (argc == 4 && isobj(argv[0], type(Image), (void**)&img) &&
isuint(argv[1], &op) &&
isobj(argv[2], type(Image), (void**)&img2) &&
istuple(argv[3], &n, &xv) &&
isint(xv[0], &x) && isint(xv[1], &y)) {
int res = CompositeImage(img, op, img2, x, y);
if (!res)
return __FAIL;
else
return mkvoid;
} else
return __FAIL;
}
FUNCTION(magick,contrast,argc,argv)
{
Image *img;
int sharpen;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
isbool(argv[1], &sharpen)) {
/* With IM 5.5 this always returns false, bug? Therfore we just ignore the
return value. */
ContrastImage(img, sharpen);
return mkvoid;
} else
return __FAIL;
}
FUNCTION(magick,equalize,argc,argv)
{
Image *img;
if (argc == 1 && isobj(argv[0], type(Image), (void**)&img)) {
int res = EqualizeImage(img);
if (!res)
return __FAIL;
else
return mkvoid;
} else
return __FAIL;
}
FUNCTION(magick,gamma,argc,argv)
{
Image *img;
char *val;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
isstr(argv[1], &val) && GammaImage(img, val))
return mkvoid;
else
return __FAIL;
}
FUNCTION(magick,level,argc,argv)
{
Image *img;
char *val;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
isstr(argv[1], &val) && LevelImage(img, val))
return mkvoid;
else
return __FAIL;
}
FUNCTION(magick,modulate,argc,argv)
{
Image *img;
char *val;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
isstr(argv[1], &val) && ModulateImage(img, val))
return mkvoid;
else
return __FAIL;
}
FUNCTION(magick,negate,argc,argv)
{
Image *img;
if (argc == 1 && isobj(argv[0], type(Image), (void**)&img)) {
int res = NegateImage(img, 0);
if (!res)
return __FAIL;
else
return mkvoid;
} else
return __FAIL;
}
FUNCTION(magick,normalize,argc,argv)
{
Image *img;
if (argc == 1 && isobj(argv[0], type(Image), (void**)&img)) {
int res = NormalizeImage(img);
if (!res)
return __FAIL;
else
return mkvoid;
} else
return __FAIL;
}
FUNCTION(magick,adaptive_threshold,argc,argv)
{
#if MagickLibVersion >= 0x550
Image *img;
unsigned long w, h;
long offs;
int n;
expr *xv;
if (argc == 3 && isobj(argv[0], type(Image), (void**)&img) &&
istuple(argv[1], &n, &xv) && n == 2 &&
isuint(xv[0], &w) && isuint(xv[1], &h) &&
isint(argv[2], &offs)) {
img = AdaptiveThresholdImage(img, w, h, offs, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
#endif
return __FAIL;
}
FUNCTION(magick,add_noise,argc,argv)
{
Image *img;
unsigned long noise;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
isuint(argv[1], &noise)) {
img = AddNoiseImage(img, noise, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,blur,argc,argv)
{
Image *img;
double radius, sigma;
if (argc == 3 && isobj(argv[0], type(Image), (void**)&img) &&
(isfloat(argv[1], &radius) || ismpz_float(argv[1], &radius)) &&
(isfloat(argv[2], &sigma) || ismpz_float(argv[2], &sigma))) {
img = BlurImage(img, radius, sigma, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,despeckle,argc,argv)
{
Image *img;
if (argc == 1 && isobj(argv[0], type(Image), (void**)&img)) {
img = DespeckleImage(img, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,edge,argc,argv)
{
Image *img;
double radius;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
(isfloat(argv[1], &radius) || ismpz_float(argv[1], &radius))) {
img = EdgeImage(img, radius, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,emboss,argc,argv)
{
Image *img;
double radius, sigma;
if (argc == 3 && isobj(argv[0], type(Image), (void**)&img) &&
(isfloat(argv[1], &radius) || ismpz_float(argv[1], &radius)) &&
(isfloat(argv[2], &sigma) || ismpz_float(argv[2], &sigma))) {
img = EmbossImage(img, radius, sigma, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,enhance,argc,argv)
{
Image *img;
if (argc == 1 && isobj(argv[0], type(Image), (void**)&img)) {
img = EnhanceImage(img, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,gaussian_blur,argc,argv)
{
Image *img;
double radius, sigma;
if (argc == 3 && isobj(argv[0], type(Image), (void**)&img) &&
(isfloat(argv[1], &radius) || ismpz_float(argv[1], &radius)) &&
(isfloat(argv[2], &sigma) || ismpz_float(argv[2], &sigma))) {
img = GaussianBlurImage(img, radius, sigma, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,median_filter,argc,argv)
{
Image *img;
double radius;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
(isfloat(argv[1], &radius) || ismpz_float(argv[1], &radius))) {
img = MedianFilterImage(img, radius, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,motion_blur,argc,argv)
{
Image *img;
double radius, sigma, angle;
if (argc == 4 && isobj(argv[0], type(Image), (void**)&img) &&
(isfloat(argv[1], &radius) || ismpz_float(argv[1], &radius)) &&
(isfloat(argv[2], &sigma) || ismpz_float(argv[2], &sigma)) &&
(isfloat(argv[3], &angle) || ismpz_float(argv[3], &angle))) {
img = MotionBlurImage(img, radius, sigma, angle, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,reduce_noise,argc,argv)
{
Image *img;
double radius;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
(isfloat(argv[1], &radius) || ismpz_float(argv[1], &radius))) {
img = ReduceNoiseImage(img, radius, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,shade,argc,argv)
{
Image *img;
double azimuth, elevation;
if (argc == 3 && isobj(argv[0], type(Image), (void**)&img) &&
(isfloat(argv[1], &azimuth) || ismpz_float(argv[1], &azimuth)) &&
(isfloat(argv[2], &elevation) || ismpz_float(argv[2], &elevation))) {
img = ShadeImage(img, 0, azimuth, elevation, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,sharpen,argc,argv)
{
Image *img;
double radius, sigma;
if (argc == 3 && isobj(argv[0], type(Image), (void**)&img) &&
(isfloat(argv[1], &radius) || ismpz_float(argv[1], &radius)) &&
(isfloat(argv[2], &sigma) || ismpz_float(argv[2], &sigma))) {
img = SharpenImage(img, radius, sigma, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,spread,argc,argv)
{
Image *img;
double radius;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
(isfloat(argv[1], &radius) || ismpz_float(argv[1], &radius)) &&
radius >= 0.0) {
img = SpreadImage(img, (unsigned)radius, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,threshold,argc,argv)
{
/* This one doesn't seem to be implemented in older IM versions. */
#if MagickLibVersion >= 0x550
Image *img;
char *val;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
isstr(argv[1], &val)) {
int res = ThresholdImageChannel(img, val);
if (!res)
return __FAIL;
else
return mkvoid;
} else
#endif
return __FAIL;
}
FUNCTION(magick,unsharp_mask,argc,argv)
{
Image *img;
double radius, sigma, amount, threshold;
if (argc == 5 && isobj(argv[0], type(Image), (void**)&img) &&
(isfloat(argv[1], &radius) || ismpz_float(argv[1], &radius)) &&
(isfloat(argv[2], &sigma) || ismpz_float(argv[2], &sigma)) &&
(isfloat(argv[3], &amount) || ismpz_float(argv[3], &amount)) &&
(isfloat(argv[3], &threshold) || ismpz_float(argv[3], &threshold))) {
img = UnsharpMaskImage(img, radius, sigma, amount, threshold, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,charcoal,argc,argv)
{
Image *img;
double radius, sigma;
if (argc == 3 && isobj(argv[0], type(Image), (void**)&img) &&
(isfloat(argv[1], &radius) || ismpz_float(argv[1], &radius)) &&
(isfloat(argv[2], &sigma) || ismpz_float(argv[2], &sigma))) {
img = CharcoalImage(img, radius, sigma, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,colorize,argc,argv)
{
Image *img;
char *val;
bstr_t *m;
if (argc == 3 && isobj(argv[0], type(Image), (void**)&img) &&
isstr(argv[1], &val) &&
isobj(argv[2], type(ByteStr), (void**)&m) && m->size == 8) {
PixelPacket pixel;
set_pixels(&pixel, m->v, 1, 1);
img = ColorizeImage(img, val, pixel, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,convolve,argc,argv)
{
Image *img;
int n;
expr *xv;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
istuple(argv[1], &n, &xv) && n > 0) {
int order = (int)sqrt(n), i;
double *kernel;
if (order*order != n) return __FAIL;
if (!(kernel = malloc(n*sizeof(double)))) return __ERROR;
for (i = 0; i < n; i++)
if (!isfloat(xv[i], kernel+i) && !ismpz_float(xv[i], kernel+i)) {
free(kernel);
return __FAIL;
}
img = ConvolveImage(img, order, kernel, &exception);
free(kernel);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,implode,argc,argv)
{
Image *img;
double amount;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
(isfloat(argv[1], &amount) || ismpz_float(argv[1], &amount))) {
img = ImplodeImage(img, amount, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,morph,argc,argv)
{
Image *imgs, *imgs2;
unsigned long frames;
if (argc == 2 && is_image_list(argv[0], &imgs) && imgs &&
isuint(argv[1], &frames)) {
imgs2 = MorphImages(imgs, frames, &exception);
decompose_image_list(imgs);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!imgs2)
return __FAIL;
else
return mk_image_list(imgs2);
} else
return __FAIL;
}
FUNCTION(magick,oil_paint,argc,argv)
{
Image *img;
double radius;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
(isfloat(argv[1], &radius) || ismpz_float(argv[1], &radius))) {
img = OilPaintImage(img, radius, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,solarize,argc,argv)
{
Image *img;
double threshold;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
ismpz_float(argv[1], &threshold)) {
SolarizeImage(img, threshold);
return mkvoid;
} else
return __FAIL;
}
FUNCTION(magick,stegano,argc,argv)
{
Image *img, *img2;
long offset;
if (argc == 3 && isobj(argv[0], type(Image), (void**)&img) &&
isobj(argv[1], type(Image), (void**)&img2) &&
isint(argv[2], &offset)) {
img->offset = offset;
img = SteganoImage(img, img2, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,stereo,argc,argv)
{
Image *img, *img2;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
isobj(argv[1], type(Image), (void**)&img2)) {
img = StereoImage(img, img2, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,swirl,argc,argv)
{
Image *img;
double angle;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
(isfloat(argv[1], &angle) || ismpz_float(argv[1], &angle))) {
img = SwirlImage(img, angle, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,wave,argc,argv)
{
Image *img;
double amp, wavelen;
if (argc == 3 && isobj(argv[0], type(Image), (void**)&img) &&
(isfloat(argv[1], &) || ismpz_float(argv[1], &)) &&
(isfloat(argv[2], &wavelen) || ismpz_float(argv[2], &wavelen))) {
img = WaveImage(img, amp, wavelen, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,border,argc,argv)
{
Image *img;
int n;
expr *xv;
unsigned long w, h;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
istuple(argv[1], &n, &xv) && n == 2 &&
isuint(xv[0], &w) && isuint(xv[1], &h)) {
RectangleInfo rect;
rect.x = rect.y = 0; rect.width = w; rect.height = h;
img = BorderImage(img, &rect, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,frame,argc,argv)
{
Image *img;
int n;
expr *xv;
long x, y;
unsigned long w, h;
long inner, outer;
if (argc == 4 && isobj(argv[0], type(Image), (void**)&img) &&
istuple(argv[1], &n, &xv) && n == 2 &&
isint(xv[0], &x) && isint(xv[1], &y) &&
istuple(argv[2], &n, &xv) && n == 2 &&
isuint(xv[0], &w) && isuint(xv[1], &h) &&
istuple(argv[3], &n, &xv) && n == 2 &&
isint(xv[0], &inner) && isint(xv[1], &outer)) {
FrameInfo frame;
frame.x = x; frame.y = y; frame.width = w; frame.height = h;
frame.inner_bevel = inner; frame.outer_bevel = outer;
img = FrameImage(img, &frame, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
else if (!img)
return __FAIL;
else
return mk_image(img);
} else
return __FAIL;
}
FUNCTION(magick,button,argc,argv)
{
Image *img;
int n;
expr *xv;
unsigned long w, h;
int raise;
if (argc == 3 && isobj(argv[0], type(Image), (void**)&img) &&
istuple(argv[1], &n, &xv) && n == 2 &&
isuint(xv[0], &w) && isuint(xv[1], &h) &&
isbool(argv[2], &raise)) {
RectangleInfo rect;
rect.x = rect.y = 0; rect.width = w; rect.height = h;
if (RaiseImage(img, &rect, raise))
return mkvoid;
else
return __FAIL;
} else
return __FAIL;
}
FUNCTION(magick,annotate,argc,argv)
{
Image *img;
DrawInfo *draw_info;
expr *xv;
int n;
long x, y;
char *s;
if (argc == 3 && isobj(argv[0], type(Image), (void**)&img) &&
(draw_info = get_draw_info(img)) && istuple(argv[1], &n, &xv) &&
isint(xv[0], &x) && isint(xv[1], &y) &&
isstr(argv[2], &s)) {
int res;
char geom[100];
sprintf(geom, "%+d%+d", x, y);
draw_info->text = s;
draw_info->geometry = geom;
res = AnnotateImage(img, draw_info);
draw_info->text = draw_info->geometry = NULL;
if (!res)
return __FAIL;
else
return mkvoid;
} else
return __FAIL;
}
FUNCTION(magick,draw,argc,argv)
{
Image *img;
DrawInfo *draw_info;
char *s;
if (argc == 2 && isobj(argv[0], type(Image), (void**)&img) &&
(draw_info = get_draw_info(img)) && isstr(argv[1], &s)) {
int res;
draw_info->primitive = s;
res = DrawImage(img, draw_info);
draw_info->primitive = NULL;
if (!res)
return __FAIL;
else
return mkvoid;
} else
return __FAIL;
}
FUNCTION(magick,color_flood_fill,argc,argv)
{
Image *img;
int n;
expr *xv;
long x, y;
bstr_t *m1, *m2 = NULL;
if (argc == 4 && isobj(argv[0], type(Image), (void**)&img) &&
istuple(argv[1], &n, &xv) && n == 2 &&
isint(xv[0], &x) && isint(xv[1], &y) &&
x >= 0 && x < img->columns && y >= 0 && y < img->rows &&
isobj(argv[2], type(ByteStr), (void**)&m1) && m1->size == 8 &&
(isvoid(argv[3]) ||
isobj(argv[3], type(ByteStr), (void**)&m2) && m2->size == 8)) {
int res;
DrawInfo *draw_info = CloneDrawInfo(NULL, NULL);
PixelPacket fill, target;
if (!draw_info) return __ERROR;
set_pixels(&fill, m1->v, 1, 1);
draw_info->fill = fill;
if (m2)
set_pixels(&target, m2->v, 1, 1);
else {
target = AcquireOnePixel(img, x, y, &exception);
if (check_exception(&exception)) {
DestroyDrawInfo(draw_info);
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
}
}
res = ColorFloodfillImage(img, draw_info, target, x, y,
m2?FillToBorderMethod:FloodfillMethod);
DestroyDrawInfo(draw_info);
if (!res)
return __FAIL;
else
return mkvoid;
} else
return __FAIL;
}
FUNCTION(magick,matte_flood_fill,argc,argv)
{
Image *img;
int n;
expr *xv;
long x, y;
unsigned long opacity;
bstr_t *m2 = NULL;
if (argc == 4 && isobj(argv[0], type(Image), (void**)&img) &&
istuple(argv[1], &n, &xv) && n == 2 &&
isint(xv[0], &x) && isint(xv[1], &y) &&
x >= 0 && x < img->columns && y >= 0 && y < img->rows &&
isuint(argv[2], &opacity) && opacity <= 0xffff &&
(isvoid(argv[3]) ||
isobj(argv[3], type(ByteStr), (void**)&m2) && m2->size == 8)) {
int res;
PixelPacket target;
if (m2)
set_pixels(&target, m2->v, 1, 1);
else {
target = AcquireOnePixel(img, x, y, &exception);
if (check_exception(&exception))
return mkapp(mksym(sym(magick_error)), mkstr(strdup(msg)));
}
res = MatteFloodfillImage(img, target, 0xffff-opacity, x, y,
m2?FillToBorderMethod:FloodfillMethod);
if (!res)
return __FAIL;
else
return mkvoid;
} else
return __FAIL;
}
FUNCTION(magick,opaque,argc,argv)
{
Image *img;
bstr_t *m1, *m2;
if (argc == 3 && isobj(argv[0], type(Image), (void**)&img) &&
isobj(argv[1], type(ByteStr), (void**)&m1) && m1->size == 8 &&
isobj(argv[2], type(ByteStr), (void**)&m2) && m2->size == 8) {
int res;
PixelPacket target, fill;
set_pixels(&target, m1->v, 1, 1);
set_pixels(&fill, m2->v, 1, 1);
res = OpaqueImage(img, target, fill);
if (!res)
return __FAIL;
else
return mkvoid;
} else
return __FAIL;
}
FUNCTION(magick,transparent,argc,argv)
{
Image *img;
bstr_t *m1;
unsigned long opacity;
if (argc == 3 && isobj(argv[0], type(Image), (void**)&img) &&
isobj(argv[1], type(ByteStr), (void**)&m1) && m1->size == 8 &&
isuint(argv[2], &opacity) && opacity <= 0xffff) {
int res;
PixelPacket target;
set_pixels(&target, m1->v, 1, 1);
res = TransparentImage(img, target, 0xffff-opacity);
if (!res)
return __FAIL;
else
return mkvoid;
} else
return __FAIL;
}
syntax highlighted by Code2HTML, v. 0.9.1