+#define IMAGER_NO_CONTEXT
+
#include "imager.h"
#include "imageri.h"
i_color *c;
c = i_color_new(red, green, blue, alpha);
ICL_DESTROY(c);
- i = i_img_new();
+ i = i_img_8_new();
i_img_destroy(i);
// and much more
=cut
*/
+im_context_t (*im_get_context)(void) = NULL;
+
#define XAXIS 0
#define YAXIS 1
#define XYAXIS 2
void i_linker_bug_fake(void) { ceil(1); }
/*
-=item i_img_alloc()
+=item im_img_alloc(aIMCTX)
+X<im_img_alloc API>X<i_img_alloc API>
=category Image Implementation
+=synopsis i_img *im = im_img_alloc(aIMCTX);
+=synopsis i_img *im = i_img_alloc();
Allocates a new i_img structure.
*/
i_img *
-i_img_alloc(void) {
+im_img_alloc(pIMCTX) {
return mymalloc(sizeof(i_img));
}
/*
-=item i_img_init(C<img>)
+=item im_img_init(aIMCTX, image)
+X<im_img_init API>X<i_img_init API>
=category Image Implementation
+=synopsis im_img_init(aIMCTX, im);
+=synopsis i_img_init(im);
Imager internal initialization of images.
-Currently this does very little, in the future it may be used to
-support threads, or color profiles.
+See L</im_img_alloc(aIMCTX)> for more information.
=cut
*/
void
-i_img_init(i_img *img) {
+im_img_init(pIMCTX, i_img *img) {
img->im_data = NULL;
+ img->context = aIMCTX;
+ im_context_refinc(aIMCTX, "img_init");
}
/*
i_color *
ICL_new_internal(unsigned char r,unsigned char g,unsigned char b,unsigned char a) {
i_color *cl = NULL;
+ dIMCTX;
- mm_log((1,"ICL_new_internal(r %d,g %d,b %d,a %d)\n", r, g, b, a));
+ im_log((aIMCTX,1,"ICL_new_internal(r %d,g %d,b %d,a %d)\n", r, g, b, a));
- if ( (cl=mymalloc(sizeof(i_color))) == NULL) i_fatal(2,"malloc() error\n");
+ if ( (cl=mymalloc(sizeof(i_color))) == NULL) im_fatal(aIMCTX, 2,"malloc() error\n");
cl->rgba.r = r;
cl->rgba.g = g;
cl->rgba.b = b;
cl->rgba.a = a;
- mm_log((1,"(%p) <- ICL_new_internal\n",cl));
+ im_log((aIMCTX,1,"(%p) <- ICL_new_internal\n",cl));
return cl;
}
i_color *
ICL_set_internal(i_color *cl,unsigned char r,unsigned char g,unsigned char b,unsigned char a) {
- mm_log((1,"ICL_set_internal(cl* %p,r %d,g %d,b %d,a %d)\n",cl,r,g,b,a));
+ dIMCTX;
+ im_log((aIMCTX,1,"ICL_set_internal(cl* %p,r %d,g %d,b %d,a %d)\n",cl,r,g,b,a));
if (cl == NULL)
if ( (cl=mymalloc(sizeof(i_color))) == NULL)
- i_fatal(2,"malloc() error\n");
+ im_fatal(aIMCTX, 2,"malloc() error\n");
cl->rgba.r=r;
cl->rgba.g=g;
cl->rgba.b=b;
cl->rgba.a=a;
- mm_log((1,"(%p) <- ICL_set_internal\n",cl));
+ im_log((aIMCTX,1,"(%p) <- ICL_set_internal\n",cl));
return cl;
}
void
ICL_info(i_color const *cl) {
- mm_log((1,"i_color_info(cl* %p)\n",cl));
- mm_log((1,"i_color_info: (%d,%d,%d,%d)\n",cl->rgba.r,cl->rgba.g,cl->rgba.b,cl->rgba.a));
+ dIMCTX;
+ im_log((aIMCTX, 1,"i_color_info(cl* %p)\n",cl));
+ im_log((aIMCTX, 1,"i_color_info: (%d,%d,%d,%d)\n",cl->rgba.r,cl->rgba.g,cl->rgba.b,cl->rgba.a));
}
/*
void
ICL_DESTROY(i_color *cl) {
- mm_log((1,"ICL_DESTROY(cl* %p)\n",cl));
+ dIMCTX;
+ im_log((aIMCTX, 1,"ICL_DESTROY(cl* %p)\n",cl));
myfree(cl);
}
*/
i_fcolor *i_fcolor_new(double r, double g, double b, double a) {
i_fcolor *cl = NULL;
+ dIMCTX;
- mm_log((1,"i_fcolor_new(r %g,g %g,b %g,a %g)\n", r, g, b, a));
+ im_log((aIMCTX, 1,"i_fcolor_new(r %g,g %g,b %g,a %g)\n", r, g, b, a));
- if ( (cl=mymalloc(sizeof(i_fcolor))) == NULL) i_fatal(2,"malloc() error\n");
+ if ( (cl=mymalloc(sizeof(i_fcolor))) == NULL) im_fatal(aIMCTX, 2,"malloc() error\n");
cl->rgba.r = r;
cl->rgba.g = g;
cl->rgba.b = b;
cl->rgba.a = a;
- mm_log((1,"(%p) <- i_fcolor_new\n",cl));
+ im_log((aIMCTX, 1,"(%p) <- i_fcolor_new\n",cl));
return cl;
}
void
i_img_exorcise(i_img *im) {
- mm_log((1,"i_img_exorcise(im* %p)\n",im));
+ dIMCTXim(im);
+ im_log((aIMCTX,1,"i_img_exorcise(im* %p)\n",im));
i_tags_destroy(&im->tags);
if (im->i_f_destroy)
(im->i_f_destroy)(im);
void
i_img_destroy(i_img *im) {
- mm_log((1,"i_img_destroy(im %p)\n",im));
+ dIMCTXim(im);
+ im_log((aIMCTX, 1,"i_img_destroy(im %p)\n",im));
i_img_exorcise(im);
- if (im) { myfree(im); }
+ myfree(im);
+ im_context_refdec(aIMCTX, "img_destroy");
}
/*
void
i_img_info(i_img *im, i_img_dim *info) {
- mm_log((1,"i_img_info(im %p)\n",im));
- if (im != NULL) {
- mm_log((1,"i_img_info: xsize=%" i_DF " ysize=%" i_DF " channels=%d "
- "mask=%ud\n",
- i_DFc(im->xsize), i_DFc(im->ysize), im->channels,im->ch_mask));
- mm_log((1,"i_img_info: idata=%p\n",im->idata));
- info[0] = im->xsize;
- info[1] = im->ysize;
- info[2] = im->channels;
- info[3] = im->ch_mask;
- } else {
- info[0] = 0;
- info[1] = 0;
- info[2] = 0;
- info[3] = 0;
- }
+ dIMCTXim(im);
+ im_log((aIMCTX,1,"i_img_info(im %p)\n",im));
+
+ im_log((aIMCTX,1,"i_img_info: xsize=%" i_DF " ysize=%" i_DF " channels=%d "
+ "mask=%ud\n",
+ i_DFc(im->xsize), i_DFc(im->ysize), im->channels,im->ch_mask));
+ im_log((aIMCTX,1,"i_img_info: idata=%p\n",im->idata));
+ info[0] = im->xsize;
+ info[1] = im->ysize;
+ info[2] = im->channels;
+ info[3] = im->ch_mask;
}
/*
return im->ysize;
}
+/*
+=item i_img_color_model(im)
+=category Image Information
+=synopsis i_color_model_t cm = i_img_color_model(im);
+
+Returns the color model for the image.
+
+A future version of Imager will allow for images with extra channels
+beyond gray/rgb and alpha.
+
+=cut
+*/
+i_color_model_t
+i_img_color_model(i_img *im) {
+ return (i_color_model_t)im->channels;
+}
+
+/*
+=item i_img_alpha_channel(im, &channel)
+=category Image Information
+=synopsis int alpha_channel;
+=synopsis int has_alpha = i_img_alpha_channel(im, &alpha_channel);
+
+Work out the alpha channel for an image.
+
+If the image has an alpha channel, sets C<*channel> to the alpha
+channel index and returns non-zero.
+
+If the image has no alpha channel, returns zero and C<*channel> is not
+modified.
+
+C<channel> may be C<NULL>.
+
+=cut
+*/
+
+int
+i_img_alpha_channel(i_img *im, int *channel) {
+ i_color_model_t model = i_img_color_model(im);
+ switch (model) {
+ case icm_gray_alpha:
+ case icm_rgb_alpha:
+ if (channel) *channel = (int)model - 1;
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+/*
+=item i_img_color_channels(im)
+=category Image Information
+=synopsis int color_channels = i_img_color_channels(im);
+
+Returns the number of color channels in the image. For now this is
+always 1 (for grayscale) or 3 (for RGB) but may be 0 in some special
+cases in a future release of Imager.
+
+=cut
+*/
+
+int
+i_img_color_channels(i_img *im) {
+ i_color_model_t model = i_img_color_model(im);
+ switch (model) {
+ case icm_gray_alpha:
+ case icm_rgb_alpha:
+ return (int)model - 1;
+
+ case icm_gray:
+ case icm_rgb:
+ return (int)model;
+
+ default:
+ return 0;
+ }
+}
+
/*
=item i_copyto_trans(C<im>, C<src>, C<x1>, C<y1>, C<x2>, C<y2>, C<tx>, C<ty>, C<trans>)
i_color pv;
i_img_dim x,y,t,ttx,tty,tt;
int ch;
+ dIMCTXim(im);
- mm_log((1,"i_copyto_trans(im* %p,src %p, p1(" i_DFp "), p2(" i_DFp "), "
+ im_log((aIMCTX, 1,"i_copyto_trans(im* %p,src %p, p1(" i_DFp "), p2(" i_DFp "), "
"to(" i_DFp "), trans* %p)\n",
im, src, i_DFcp(x1, y1), i_DFcp(x2, y2), i_DFcp(tx, ty), trans));
i_img *
i_copy(i_img *src) {
i_img_dim y, y1, x1;
+ dIMCTXim(src);
i_img *im = i_sametype(src, src->xsize, src->ysize);
- mm_log((1,"i_copy(src %p)\n", src));
+ im_log((aIMCTX,1,"i_copy(src %p)\n", src));
if (!im)
return NULL;
i_img *new_img;
int has_alpha = i_img_has_alpha(im);
int color_chans = i_img_color_channels(im);
+ dIMCTXim(im);
i_clear_error();
- mm_log((1,"i_scaleaxis(im %p,Value %.2f,Axis %d)\n",im,Value,Axis));
+ im_log((aIMCTX, 1,"i_scaleaxis(im %p,Value %.2f,Axis %d)\n",im,Value,Axis));
if (Axis == XAXIS) {
hsize = (i_img_dim)(0.5 + im->xsize * Value);
iEnd = hsize;
}
- new_img = i_img_empty_ch(NULL, hsize, vsize, im->channels);
+ new_img = i_img_8_new(hsize, vsize, im->channels);
if (!new_img) {
i_push_error(0, "cannot create output image");
return NULL;
myfree(l0);
myfree(l1);
- mm_log((1,"(%p) <- i_scaleaxis\n", new_img));
+ im_log((aIMCTX, 1,"(%p) <- i_scaleaxis\n", new_img));
return new_img;
}
i_img_dim nxsize,nysize,nx,ny;
i_img *new_img;
i_color val;
+ dIMCTXim(im);
- mm_log((1,"i_scale_nn(im %p,scx %.2f,scy %.2f)\n",im,scx,scy));
+ im_log((aIMCTX, 1,"i_scale_nn(im %p,scx %.2f,scy %.2f)\n",im,scx,scy));
nxsize = (i_img_dim) ((double) im->xsize * scx);
if (nxsize < 1) {
i_ppix(new_img,nx,ny,&val);
}
- mm_log((1,"(%p) <- i_scale_nn\n",new_img));
+ im_log((aIMCTX, 1,"(%p) <- i_scale_nn\n",new_img));
return new_img;
}
=cut
*/
-i_img *i_sametype(i_img *src, i_img_dim xsize, i_img_dim ysize) {
+i_img *
+i_sametype(i_img *src, i_img_dim xsize, i_img_dim ysize) {
+ dIMCTXim(src);
+
if (src->type == i_direct_type) {
if (src->bits == 8) {
return i_img_empty_ch(NULL, xsize, ysize, src->channels);
=cut
*/
-i_img *i_sametype_chans(i_img *src, i_img_dim xsize, i_img_dim ysize, int channels) {
+i_img *
+i_sametype_chans(i_img *src, i_img_dim xsize, i_img_dim ysize, int channels) {
+ dIMCTXim(src);
+
if (src->bits == 8) {
return i_img_empty_ch(NULL, xsize, ysize, channels);
}
i_img_dim nxsize,nysize,nx,ny;
i_img *new_img;
i_color val;
+ dIMCTXim(im);
- mm_log((1,"i_transform(im %p, opx %p, opxl %d, opy %p, opyl %d, parm %p, parmlen %d)\n",im,opx,opxl,opy,opyl,parm,parmlen));
+ im_log((aIMCTX, 1,"i_transform(im %p, opx %p, opxl %d, opy %p, opyl %d, parm %p, parmlen %d)\n",im,opx,opxl,opy,opyl,parm,parmlen));
nxsize = im->xsize;
nysize = im->ysize ;
i_ppix(new_img,nx,ny,&val);
}
- mm_log((1,"(%p) <- i_transform\n",new_img));
+ im_log((aIMCTX, 1,"(%p) <- i_transform\n",new_img));
return new_img;
}
int ch, chb;
float tdiff;
i_color val1,val2;
+ dIMCTXim(im1);
- mm_log((1,"i_img_diff(im1 %p,im2 %p)\n",im1,im2));
+ im_log((aIMCTX, 1,"i_img_diff(im1 %p,im2 %p)\n",im1,im2));
xb=(im1->xsize<im2->xsize)?im1->xsize:im2->xsize;
yb=(im1->ysize<im2->ysize)?im1->ysize:im2->ysize;
chb=(im1->channels<im2->channels)?im1->channels:im2->channels;
- mm_log((1,"i_img_diff: b=(" i_DFp ") chb=%d\n",
+ im_log((aIMCTX, 1,"i_img_diff: b=(" i_DFp ") chb=%d\n",
i_DFcp(xb,yb), chb));
tdiff=0;
for(ch=0;ch<chb;ch++) tdiff+=(val1.channel[ch]-val2.channel[ch])*(val1.channel[ch]-val2.channel[ch]);
}
- mm_log((1,"i_img_diff <- (%.2f)\n",tdiff));
+ im_log((aIMCTX, 1,"i_img_diff <- (%.2f)\n",tdiff));
return tdiff;
}
int ch, chb;
double tdiff;
i_fcolor val1,val2;
+ dIMCTXim(im1);
- mm_log((1,"i_img_diffd(im1 %p,im2 %p)\n",im1,im2));
+ im_log((aIMCTX, 1,"i_img_diffd(im1 %p,im2 %p)\n",im1,im2));
xb=(im1->xsize<im2->xsize)?im1->xsize:im2->xsize;
yb=(im1->ysize<im2->ysize)?im1->ysize:im2->ysize;
chb=(im1->channels<im2->channels)?im1->channels:im2->channels;
- mm_log((1,"i_img_diffd: b(" i_DFp ") chb=%d\n",
+ im_log((aIMCTX, 1,"i_img_diffd: b(" i_DFp ") chb=%d\n",
i_DFcp(xb, yb), chb));
tdiff=0;
tdiff += sdiff * sdiff;
}
}
- mm_log((1,"i_img_diffd <- (%.2f)\n",tdiff));
+ im_log((aIMCTX, 1,"i_img_diffd <- (%.2f)\n",tdiff));
return tdiff;
}
i_img_dim x,y,xb,yb;
int ch, chb;
i_fcolor val1,val2;
+ dIMCTXim(im1);
if (what == NULL)
what = "(null)";
- mm_log((1,"i_img_samef(im1 %p,im2 %p, epsilon %g, what '%s')\n", im1, im2, epsilon, what));
+ im_log((aIMCTX,1,"i_img_samef(im1 %p,im2 %p, epsilon %g, what '%s')\n", im1, im2, epsilon, what));
xb=(im1->xsize<im2->xsize)?im1->xsize:im2->xsize;
yb=(im1->ysize<im2->ysize)?im1->ysize:im2->ysize;
chb=(im1->channels<im2->channels)?im1->channels:im2->channels;
- mm_log((1,"i_img_samef: b(" i_DFp ") chb=%d\n",
+ im_log((aIMCTX, 1,"i_img_samef: b(" i_DFp ") chb=%d\n",
i_DFcp(xb, yb), chb));
for(y = 0; y < yb; y++) {
for(ch = 0; ch < chb; ch++) {
double sdiff = val1.channel[ch] - val2.channel[ch];
if (fabs(sdiff) > epsilon) {
- mm_log((1,"i_img_samef <- different %g @(" i_DFp ")\n",
+ im_log((aIMCTX, 1,"i_img_samef <- different %g @(" i_DFp ")\n",
sdiff, i_DFcp(x, y)));
return 0;
}
}
}
}
- mm_log((1,"i_img_samef <- same\n"));
+ im_log((aIMCTX, 1,"i_img_samef <- same\n"));
return 1;
}
i_img_dim mx,my;
i_img_dim fx,fy;
i_img_dim x,y;
- int ch,c;
+ int ch;
i_img *new_img,*new_img2;
i_color val1,val2,dval1,dval2;
+ dIMCTXim(im);
mx=im->xsize;
my=im->ysize;
new_img=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
new_img2=i_img_empty_ch(NULL,fx*2,fy*2,im->channels);
- c=0;
for(y=0;y<my;y++) for(x=0;x<fx;x++) {
i_gpix(im,x*2,y,&val1);
i_gpix(im,x*2+1,y,&val2);
for(x = 0; x < samp_cnt; ) {
colorcnt += octt_add(ct, samp[x], samp[x+1], samp[x+2]);
x += 3;
- if (colorcnt > maxc) {
+ if (colorcnt > maxc) {
+ myfree(samp);
octt_delete(ct);
return -1;
}
colorcnt += octt_add(ct, samp[x], samp[x+1], samp[x+2]);
x += 3;
if (colorcnt > maxc) {
- octt_delete(ct);
+ octt_delete(ct);
+ myfree(samp);
return -1;
}
}
i_color temp;
int ch;
- if (i_gpix(im, x, y, &temp)) {
+ if (i_gpix(im, x, y, &temp) == 0) {
for (ch = 0; ch < im->channels; ++ch)
pix->channel[ch] = Sample8ToF(temp.channel[ch]);
return 0;
i_img_dim
i_gsamp_bits_fb(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, unsigned *samps,
const int *chans, int chan_count, int bits) {
+ dIMCTXim(im);
+
if (bits < 1 || bits > 32) {
i_push_error(0, "Invalid bits, must be 1..32");
return -1;
/* make sure we have good channel numbers */
for (ch = 0; ch < chan_count; ++ch) {
if (chans[ch] < 0 || chans[ch] >= im->channels) {
- i_push_errorf(0, "No channel %d in this image", chans[ch]);
+ im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
return -1;
}
}
}
}
-struct magic_entry {
- unsigned char *magic;
- size_t magic_size;
- char *name;
- unsigned char *mask;
-};
-
static int
-test_magic(unsigned char *buffer, size_t length, struct magic_entry const *magic) {
+test_magic(unsigned char *buffer, size_t length, struct file_magic_entry const *magic) {
if (length < magic->magic_size)
return 0;
if (magic->mask) {
{ (unsigned char *)(magic ""), sizeof(magic)-1, type, (unsigned char *)(mask) }
const char *
-i_test_format_probe(io_glue *data, int length) {
- static const struct magic_entry formats[] = {
+im_test_format_probe(im_context_t ctx, io_glue *data, int length) {
+ static const struct file_magic_entry formats[] = {
FORMAT_ENTRY("\xFF\xD8", "jpeg"),
FORMAT_ENTRY("GIF87a", "gif"),
FORMAT_ENTRY("GIF89a", "gif"),
/* JPEG 2000
This might match a little loosely */
FORMAT_ENTRY("\x00\x00\x00\x0CjP \x0D\x0A\x87\x0A", "jp2"),
+
+ /* FLIF - Free Lossless Image Format - https://flif.info/spec.html */
+ FORMAT_ENTRY("FLIF", "flif")
};
- static const struct magic_entry more_formats[] = {
+ static const struct file_magic_entry more_formats[] = {
/* these were originally both listed as ico, but cur files can
include hotspot information */
FORMAT_ENTRY("\x00\x00\x01\x00", "ico"), /* Windows icon */
}
#endif
+ {
+ im_file_magic *p = ctx->file_magic;
+ while (p) {
+ if (test_magic(head, rc, &p->m)) {
+ return p->m.name;
+ }
+ p = p->next;
+ }
+ }
+
for(i=0; i<sizeof(formats)/sizeof(formats[0]); i++) {
- struct magic_entry const *entry = formats + i;
+ struct file_magic_entry const *entry = formats + i;
if (test_magic(head, rc, entry))
return entry->name;
return "tga";
for(i=0; i<sizeof(more_formats)/sizeof(more_formats[0]); i++) {
- struct magic_entry const *entry = more_formats + i;
+ struct file_magic_entry const *entry = more_formats + i;
if (test_magic(head, rc, entry))
return entry->name;
if (im->type == i_palette_type
&& i_colorcount(im) == 2) {
i_color colors[2];
- i_getcolors(im, 0, colors, 2);
+ if (!i_getcolors(im, 0, colors, 2))
+ return 0;
if (im->channels == 3) {
if (colors[0].rgb.r == 255 &&
colors[0].rgb.g == 255 &&
Retrieve the file write background color tag from the image.
-If not present, returns black.
+If not present, C<bg> is set to black.
+
+Returns 1 if the C<i_background> tag was found and valid.
=cut
*/
-void
+int
i_get_file_background(i_img *im, i_color *bg) {
- if (!i_tags_get_color(&im->tags, "i_background", 0, bg)) {
+ int result = i_tags_get_color(&im->tags, "i_background", 0, bg);
+ if (!result) {
/* black default */
bg->channel[0] = bg->channel[1] = bg->channel[2] = 0;
}
/* always full alpha */
bg->channel[3] = 255;
+
+ return result;
}
/*
Implemented in terms of i_get_file_background().
-If not present, returns black.
+If not present, C<bg> is set to black.
+
+Returns 1 if the C<i_background> tag was found and valid.
=cut
*/
-void
+int
i_get_file_backgroundf(i_img *im, i_fcolor *fbg) {
i_color bg;
-
- i_get_file_background(im, &bg);
+ int result = i_get_file_background(im, &bg);
fbg->rgba.r = Sample8ToF(bg.rgba.r);
fbg->rgba.g = Sample8ToF(bg.rgba.g);
fbg->rgba.b = Sample8ToF(bg.rgba.b);
fbg->rgba.a = 1.0;
+
+ return result;
}
/*