-#include "image.h"
-#include "imagei.h"
-#include "io.h"
+#include "imager.h"
+#include "imageri.h"
/*
=head1 NAME
Some of these functions are internal.
-=over 4
+=over
=cut
*/
#define minmax(a,b,i) ( ((a>=i)?a: ( (b<=i)?b:i )) )
/* Hack around an obscure linker bug on solaris - probably due to builtin gcc thingies */
-void fake(void) { ceil(1); }
+static void fake(void) { ceil(1); }
-static int i_ppix_d(i_img *im, int x, int y, i_color *val);
+static int i_ppix_d(i_img *im, int x, int y, const i_color *val);
static int i_gpix_d(i_img *im, int x, int y, i_color *val);
static int i_glin_d(i_img *im, int l, int r, int y, i_color *vals);
-static int i_plin_d(i_img *im, int l, int r, int y, i_color *vals);
-static int i_ppixf_d(i_img *im, int x, int y, i_fcolor *val);
+static int i_plin_d(i_img *im, int l, int r, int y, const i_color *vals);
+static int i_ppixf_d(i_img *im, int x, int y, const i_fcolor *val);
static int i_gpixf_d(i_img *im, int x, int y, i_fcolor *val);
static int i_glinf_d(i_img *im, int l, int r, int y, i_fcolor *vals);
-static int i_plinf_d(i_img *im, int l, int r, int y, i_fcolor *vals);
-static int i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, int *chans, int chan_count);
-static int i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, int *chans, int chan_count);
+static int i_plinf_d(i_img *im, int l, int r, int y, const i_fcolor *vals);
+static int i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, const int *chans, int chan_count);
+static int i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, const int *chans, int chan_count);
+/*static int i_psamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, int *chans, int chan_count);
+ static int i_psampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, int *chans, int chan_count);*/
/*
=item ICL_new_internal(r, g, b, a)
mm_log((1,"ICL_new_internal(r %d,g %d,b %d,a %d)\n", r, g, b, a));
- if ( (cl=mymalloc(sizeof(i_color))) == NULL) m_fatal(2,"malloc() error\n");
+ if ( (cl=mymalloc(sizeof(i_color))) == NULL) i_fatal(2,"malloc() error\n");
cl->rgba.r = r;
cl->rgba.g = g;
cl->rgba.b = b;
mm_log((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)
- m_fatal(2,"malloc() error\n");
+ i_fatal(2,"malloc() error\n");
cl->rgba.r=r;
cl->rgba.g=g;
cl->rgba.b=b;
*/
void
-ICL_info(i_color *cl) {
+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));
}
mm_log((1,"i_fcolor_new(r %g,g %g,b %g,a %g)\n", r, g, b, a));
- if ( (cl=mymalloc(sizeof(i_fcolor))) == NULL) m_fatal(2,"malloc() error\n");
+ if ( (cl=mymalloc(sizeof(i_fcolor))) == NULL) i_fatal(2,"malloc() error\n");
cl->rgba.r = r;
cl->rgba.g = g;
cl->rgba.b = b;
{
0, /* channels set */
0, 0, 0, /* xsize, ysize, bytes */
- ~0, /* ch_mask */
+ ~0U, /* ch_mask */
i_8_bits, /* bits */
i_direct_type, /* type */
0, /* virtual */
/*
=item IIM_new(x, y, ch)
-Creates a new image object I<x> pixels wide, and I<y> pixels high with I<ch> channels.
+=item i_img_8_new(x, y, ch)
+
+=category Image creation
+
+Creates a new image object I<x> pixels wide, and I<y> pixels high with
+I<ch> channels.
=cut
*/
/* myfree(cl); */
}
-
-
/*
=item i_img_new()
mm_log((1,"i_img_struct()\n"));
if ( (im=mymalloc(sizeof(i_img))) == NULL)
- m_fatal(2,"malloc() error\n");
+ i_fatal(2,"malloc() error\n");
*im = IIM_base_8bit_direct;
im->xsize=0;
i_img *
i_img_empty_ch(i_img *im,int x,int y,int ch) {
+ int bytes;
+
mm_log((1,"i_img_empty_ch(*im %p, x %d, y %d, ch %d)\n", im, x, y, ch));
+
+ if (x < 1 || y < 1) {
+ i_push_error(0, "Image sizes must be positive");
+ return NULL;
+ }
+ if (ch < 1 || ch > MAXCHANNELS) {
+ i_push_errorf(0, "channels must be between 1 and %d", MAXCHANNELS);
+ return NULL;
+ }
+ /* check this multiplication doesn't overflow */
+ bytes = x*y*ch;
+ if (bytes / y / ch != x) {
+ i_push_errorf(0, "integer overflow calculating image allocation");
+ return NULL;
+ }
+
if (im == NULL)
if ( (im=mymalloc(sizeof(i_img))) == NULL)
- m_fatal(2,"malloc() error\n");
+ i_fatal(2,"malloc() error\n");
memcpy(im, &IIM_base_8bit_direct, sizeof(i_img));
i_tags_new(&im->tags);
im->ysize = y;
im->channels = ch;
im->ch_mask = MAXINT;
- im->bytes=x*y*im->channels;
- if ( (im->idata=mymalloc(im->bytes)) == NULL) m_fatal(2,"malloc() error\n");
+ im->bytes=bytes;
+ if ( (im->idata=mymalloc(im->bytes)) == NULL)
+ i_fatal(2,"malloc() error\n");
memset(im->idata,0,(size_t)im->bytes);
im->ext_data = NULL;
/*
=item i_img_destroy(im)
+=category Image
+
Destroy image and free data via exorcise.
im - Image pointer
void
i_img_destroy(i_img *im) {
- mm_log((1,"i_img_destroy(im* 0x%x)\n",im));
+ mm_log((1,"i_img_destroy(im %p)\n",im));
i_img_exorcise(im);
if (im) { myfree(im); }
}
/*
=item i_img_info(im, info)
+=category Image
+
Return image information
im - Image pointer
i_img_getchannels(i_img *im) { return im->channels; }
-/*
-=item i_ppix(im, x, y, col)
-
-Sets the pixel at (I<x>,I<y>) in I<im> to I<col>.
-
-Returns true if the pixel could be set, false if x or y is out of
-range.
-
-=cut
-*/
-int
-(i_ppix)(i_img *im, int x, int y, i_color *val) { return im->i_f_ppix(im, x, y, val); }
-
-/*
-=item i_gpix(im, x, y, &col)
-
-Get the pixel at (I<x>,I<y>) in I<im> into I<col>.
-
-Returns true if the pixel could be retrieved, false otherwise.
-
-=cut
-*/
-int
-(i_gpix)(i_img *im, int x, int y, i_color *val) { return im->i_f_gpix(im, x, y, val); }
-
-/*
-=item i_ppix_pch(im, x, y, ch)
-
-Get the value from the channel I<ch> for pixel (I<x>,I<y>) from I<im>
-scaled to [0,1].
-
-Returns zero if x or y is out of range.
-
-Warning: this ignores the vptr interface for images.
-
-=cut
-*/
-float
-i_gpix_pch(i_img *im,int x,int y,int ch) {
- /* FIXME */
- if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) return ((float)im->idata[(x+y*im->xsize)*im->channels+ch]/255);
- else return 0;
-}
-
/*
=item i_copyto_trans(im, src, x1, y1, x2, y2, tx, ty, trans)
+=category Image
+
(x1,y1) (x2,y2) specifies the region to copy (in the source coordinates)
(tx,ty) specifies the upper left corner for the target image.
pass NULL in trans for non transparent i_colors.
*/
void
-i_copyto_trans(i_img *im,i_img *src,int x1,int y1,int x2,int y2,int tx,int ty,i_color *trans) {
+i_copyto_trans(i_img *im,i_img *src,int x1,int y1,int x2,int y2,int tx,int ty,const i_color *trans) {
i_color pv;
int x,y,t,ttx,tty,tt,ch;
/*
=item i_copyto(dest, src, x1, y1, x2, y2, tx, ty)
+=category Image
+
Copies image data from the area (x1,y1)-[x2,y2] in the source image to
a rectangle the same size with it's top-left corner at (tx,ty) in the
destination image.
if (x2<x1) { t=x1; x1=x2; x2=t; }
if (y2<y1) { t=y1; y1=y2; y2=t; }
-
+ if (tx < 0) {
+ /* adjust everything equally */
+ x1 += -tx;
+ x2 += -tx;
+ tx = 0;
+ }
+ if (ty < 0) {
+ y1 += -ty;
+ y2 += -ty;
+ ty = 0;
+ }
+ if (x1 >= src->xsize || y1 >= src->ysize)
+ return; /* nothing to do */
+ if (x2 > src->xsize)
+ x2 = src->xsize;
+ if (y2 > src->ysize)
+ y2 = src->ysize;
+ if (x1 == x2 || y1 == y2)
+ return; /* nothing to do */
+
mm_log((1,"i_copyto(im* %p, src %p, x1 %d, y1 %d, x2 %d, y2 %d, tx %d, ty %d)\n",
im, src, x1, y1, x2, y2, tx, ty));
if (im->bits == i_8_bits) {
- i_color pv;
+ i_color *row = mymalloc(sizeof(i_color) * (x2-x1));
tty = ty;
for(y=y1; y<y2; y++) {
ttx = tx;
- for(x=x1; x<x2; x++) {
- i_gpix(src, x, y, &pv);
- i_ppix(im, ttx, tty, &pv);
- ttx++;
- }
+ i_glin(src, x1, x2, y, row);
+ i_plin(im, tx, tx+x2-x1, tty, row);
tty++;
}
+ myfree(row);
}
else {
i_fcolor pv;
}
/*
-=item i_copy(im, src)
+=item i_copy(src)
+
+=category Image
-Copies the contents of the image I<src> over the image I<im>.
+Creates a new image that is a copy of src.
+
+Tags are not copied, only the image data.
+
+Returns: i_img *
=cut
*/
-void
-i_copy(i_img *im, i_img *src) {
+i_img *
+i_copy(i_img *src) {
int y, y1, x1;
+ i_img *im = i_sametype(src, src->xsize, src->ysize);
+
+ mm_log((1,"i_copy(src %p)\n", src));
- mm_log((1,"i_copy(im* %p,src %p)\n", im, src));
+ if (!im)
+ return NULL;
x1 = src->xsize;
y1 = src->ysize;
if (src->type == i_direct_type) {
if (src->bits == i_8_bits) {
i_color *pv;
- i_img_empty_ch(im, x1, y1, src->channels);
pv = mymalloc(sizeof(i_color) * x1);
for (y = 0; y < y1; ++y) {
myfree(pv);
}
else {
- /* currently the only other depth is 16 */
i_fcolor *pv;
- i_img_16_new_low(im, x1, y1, src->channels);
+
pv = mymalloc(sizeof(i_fcolor) * x1);
for (y = 0; y < y1; ++y) {
i_glinf(src, 0, x1, y, pv);
}
myfree(vals);
}
-}
-
-
-/*
-=item i_rubthru(im, src, tx, ty)
-
-Takes the image I<src> and applies it at an original (I<tx>,I<ty>) in I<im>.
-
-The alpha channel of each pixel in I<src> is used to control how much
-the existing colour in I<im> is replaced, if it is 255 then the colour
-is completely replaced, if it is 0 then the original colour is left
-unmodified.
-
-=cut
-*/
-
-int
-i_rubthru(i_img *im,i_img *src,int tx,int ty) {
- int x, y, ttx, tty;
- int chancount;
- int chans[3];
- int alphachan;
- int ch;
-
- mm_log((1,"i_rubthru(im %p, src %p, tx %d, ty %d)\n", im, src, tx, ty));
- i_clear_error();
-
- if (im->channels == 3 && src->channels == 4) {
- chancount = 3;
- chans[0] = 0; chans[1] = 1; chans[2] = 2;
- alphachan = 3;
- }
- else if (im->channels == 3 && src->channels == 2) {
- chancount = 3;
- chans[0] = chans[1] = chans[2] = 0;
- alphachan = 1;
- }
- else if (im->channels == 1 && src->channels == 2) {
- chancount = 1;
- chans[0] = 0;
- alphachan = 1;
- }
- else {
- i_push_error(0, "rubthru can only work where (dest, src) channels are (3,4), (3,2) or (1,2)");
- return 0;
- }
-
- if (im->bits <= 8) {
- /* if you change this code, please make sure the else branch is
- changed in a similar fashion - TC */
- int alpha;
- i_color pv, orig, dest;
- ttx = tx;
- for(x=0; x<src->xsize; x++) {
- tty=ty;
- for(y=0;y<src->ysize;y++) {
- /* fprintf(stderr,"reading (%d,%d) writing (%d,%d).\n",x,y,ttx,tty); */
- i_gpix(src, x, y, &pv);
- i_gpix(im, ttx, tty, &orig);
- alpha = pv.channel[alphachan];
- for (ch = 0; ch < chancount; ++ch) {
- dest.channel[ch] = (alpha * pv.channel[chans[ch]]
- + (255 - alpha) * orig.channel[ch])/255;
- }
- i_ppix(im, ttx, tty, &dest);
- tty++;
- }
- ttx++;
- }
- }
- else {
- double alpha;
- i_fcolor pv, orig, dest;
-
- ttx = tx;
- for(x=0; x<src->xsize; x++) {
- tty=ty;
- for(y=0;y<src->ysize;y++) {
- /* fprintf(stderr,"reading (%d,%d) writing (%d,%d).\n",x,y,ttx,tty); */
- i_gpixf(src, x, y, &pv);
- i_gpixf(im, ttx, tty, &orig);
- alpha = pv.channel[alphachan];
- for (ch = 0; ch < chancount; ++ch) {
- dest.channel[ch] = alpha * pv.channel[chans[ch]]
- + (1 - alpha) * orig.channel[ch];
- }
- i_ppixf(im, ttx, tty, &dest);
- tty++;
- }
- ttx++;
- }
- }
- return 1;
+ return im;
}
else return(sin(PIx) / PIx * sin(PIx2) / PIx2);
}
+
/*
=item i_scaleaxis(im, value, axis)
int hsize, vsize, i, j, k, l, lMax, iEnd, jEnd;
int LanczosWidthFactor;
float *l0, *l1, OldLocation;
- int T, TempJump1, TempJump2;
+ int T;
+ float t;
float F, PictureValue[MAXCHANNELS];
short psave;
i_color val,val1,val2;
i_img *new_img;
- mm_log((1,"i_scaleaxis(im 0x%x,Value %.2f,Axis %d)\n",im,Value,Axis));
+ mm_log((1,"i_scaleaxis(im %p,Value %.2f,Axis %d)\n",im,Value,Axis));
+
if (Axis == XAXIS) {
- hsize = (int) ((float) im->xsize * Value);
+ hsize = (int)(0.5 + im->xsize * Value);
+ if (hsize < 1) {
+ hsize = 1;
+ Value = 1.0 / im->xsize;
+ }
vsize = im->ysize;
jEnd = hsize;
iEnd = vsize;
-
- TempJump1 = (hsize - 1) * 3;
- TempJump2 = hsize * (vsize - 1) * 3 + TempJump1;
} else {
hsize = im->xsize;
- vsize = (int) ((float) im->ysize * Value);
-
+ vsize = (int)(0.5 + im->ysize * Value);
+
+ if (vsize < 1) {
+ vsize = 1;
+ Value = 1.0 / im->ysize;
+ }
+
jEnd = vsize;
iEnd = hsize;
-
- TempJump1 = 0;
- TempJump2 = 0;
}
- new_img=i_img_empty_ch(NULL,hsize,vsize,im->channels);
-
- if (Value >=1) LanczosWidthFactor = 1;
- else LanczosWidthFactor = (int) (1.0/Value);
+ new_img = i_img_empty_ch(NULL, hsize, vsize, im->channels);
+ /* 1.4 is a magic number, setting it to 2 will cause rather blurred images */
+ LanczosWidthFactor = (Value >= 1) ? 1 : (int) (1.4/Value);
lMax = LanczosWidthFactor << 1;
- l0 = (float *) mymalloc(lMax * sizeof(float));
- l1 = (float *) mymalloc(lMax * sizeof(float));
+ l0 = mymalloc(lMax * sizeof(float));
+ l1 = mymalloc(lMax * sizeof(float));
for (j=0; j<jEnd; j++) {
OldLocation = ((float) j) / Value;
T = (int) (OldLocation);
F = OldLocation - (float) T;
- for (l = 0; l < lMax; l++) {
+ for (l = 0; l<lMax; l++) {
l0[lMax-l-1] = Lanczos(((float) (lMax-l-1) + F) / (float) LanczosWidthFactor);
- l1[l] = Lanczos(((float) (l + 1) - F) / (float) LanczosWidthFactor);
+ l1[l] = Lanczos(((float) (l+1) - F) / (float) LanczosWidthFactor);
}
- if (Axis== XAXIS) {
+ /* Make sure filter is normalized */
+ t = 0.0;
+ for(l=0; l<lMax; l++) {
+ t+=l0[l];
+ t+=l1[l];
+ }
+ t /= (float)LanczosWidthFactor;
+
+ for(l=0; l<lMax; l++) {
+ l0[l] /= t;
+ l1[l] /= t;
+ }
+
+ if (Axis == XAXIS) {
for (i=0; i<iEnd; i++) {
for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
- for (l=0; l < lMax; l++) {
- i_gpix(im,T+l+1, i, &val1);
- i_gpix(im,T-lMax+l+1, i, &val2);
+ for (l=0; l<lMax; l++) {
+ int mx = T-lMax+l+1;
+ int Mx = T+l+1;
+ mx = (mx < 0) ? 0 : mx;
+ Mx = (Mx >= im->xsize) ? im->xsize-1 : Mx;
+
+ i_gpix(im, Mx, i, &val1);
+ i_gpix(im, mx, i, &val2);
+
for (k=0; k<im->channels; k++) {
- PictureValue[k] += l1[l] * val1.channel[k];
+ PictureValue[k] += l1[l] * val1.channel[k];
PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
}
}
for(k=0;k<im->channels;k++) {
- psave = (short)( PictureValue[k] / LanczosWidthFactor);
+ psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor));
val.channel[k]=minmax(0,255,psave);
}
- i_ppix(new_img,j,i,&val);
+ i_ppix(new_img, j, i, &val);
}
} else {
for (i=0; i<iEnd; i++) {
for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
for (l=0; l < lMax; l++) {
- i_gpix(im,i, T+l+1, &val1);
- i_gpix(im,i, T-lMax+l+1, &val2);
+ int mx = T-lMax+l+1;
+ int Mx = T+l+1;
+ mx = (mx < 0) ? 0 : mx;
+ Mx = (Mx >= im->ysize) ? im->ysize-1 : Mx;
+
+ i_gpix(im, i, Mx, &val1);
+ i_gpix(im, i, mx, &val2);
for (k=0; k<im->channels; k++) {
- PictureValue[k] += l1[l] * val1.channel[k];
+ PictureValue[k] += l1[l] * val1.channel[k];
PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
}
}
for (k=0; k<im->channels; k++) {
- psave = (short)( PictureValue[k] / LanczosWidthFactor);
- val.channel[k]=minmax(0,255,psave);
+ psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor));
+ val.channel[k] = minmax(0, 255, psave);
}
- i_ppix(new_img,i,j,&val);
+ i_ppix(new_img, i, j, &val);
}
}
myfree(l0);
myfree(l1);
- mm_log((1,"(0x%x) <- i_scaleaxis\n",new_img));
+ mm_log((1,"(%p) <- i_scaleaxis\n", new_img));
return new_img;
}
mm_log((1,"i_scale_nn(im 0x%x,scx %.2f,scy %.2f)\n",im,scx,scy));
nxsize = (int) ((float) im->xsize * scx);
+ if (nxsize < 1) {
+ nxsize = 1;
+ scx = 1 / im->xsize;
+ }
nysize = (int) ((float) im->ysize * scy);
+ if (nysize < 1) {
+ nysize = 1;
+ scy = 1 / im->ysize;
+ }
new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels);
/*
=item i_sametype(i_img *im, int xsize, int ysize)
+=category Image creation
+
Returns an image of the same type (sample size, channels, paletted/direct).
For paletted images the palette is copied from the source.
if (src->bits == 8) {
return i_img_empty_ch(NULL, xsize, ysize, src->channels);
}
- else if (src->bits == 16) {
+ else if (src->bits == i_16_bits) {
return i_img_16_new(xsize, ysize, src->channels);
}
+ else if (src->bits == i_double_bits) {
+ return i_img_double_new(xsize, ysize, src->channels);
+ }
else {
i_push_error(0, "Unknown image bits");
return NULL;
}
}
+/*
+=item i_sametype_chans(i_img *im, int xsize, int ysize, int channels)
+
+=category Image creation
+
+Returns an image of the same type (sample size).
+
+For paletted images the equivalent direct type is returned.
+
+=cut
+*/
+
+i_img *i_sametype_chans(i_img *src, int xsize, int ysize, int channels) {
+ if (src->bits == 8) {
+ return i_img_empty_ch(NULL, xsize, ysize, channels);
+ }
+ else if (src->bits == i_16_bits) {
+ return i_img_16_new(xsize, ysize, channels);
+ }
+ else if (src->bits == i_double_bits) {
+ return i_img_double_new(xsize, ysize, channels);
+ }
+ else {
+ i_push_error(0, "Unknown image bits");
+ return NULL;
+ }
+}
+
/*
=item i_transform(im, opx, opxl, opy, opyl, parm, parmlen)
parm[1]=(double)ny;
/* fprintf(stderr,"(%d,%d) ->",nx,ny); */
- rx=op_run(opx,opxl,parm,parmlen);
- ry=op_run(opy,opyl,parm,parmlen);
+ rx=i_op_run(opx,opxl,parm,parmlen);
+ ry=i_op_run(opy,opyl,parm,parmlen);
/* fprintf(stderr,"(%f,%f)\n",rx,ry); */
i_gpix(im,rx,ry,&val);
i_ppix(new_img,nx,ny,&val);
return colorcnt;
}
-
-symbol_table_t symbol_table={i_has_format,ICL_set_internal,ICL_info,
- i_img_new,i_img_empty,i_img_empty_ch,i_img_exorcise,
- i_img_info,i_img_setmask,i_img_getmask,i_ppix,i_gpix,
- i_box,i_draw,i_arc,i_copyto,i_copyto_trans,i_rubthru};
-
-
/*
=back
=cut
*/
+static
int
-i_ppix_d(i_img *im, int x, int y, i_color *val) {
+i_ppix_d(i_img *im, int x, int y, const i_color *val) {
int ch;
if ( x>-1 && x<im->xsize && y>-1 && y<im->ysize ) {
=cut
*/
+static
int
i_gpix_d(i_img *im, int x, int y, i_color *val) {
int ch;
if (x>-1 && x<im->xsize && y>-1 && y<im->ysize) {
for(ch=0;ch<im->channels;ch++)
- val->channel[ch]=im->idata[(x+y*im->xsize)*im->channels+ch];
+ val->channel[ch]=im->idata[(x+y*im->xsize)*im->channels+ch];
return 0;
}
+ for(ch=0;ch<im->channels;ch++) val->channel[ch] = 0;
return -1; /* error was cliped */
}
=cut
*/
+static
int
i_glin_d(i_img *im, int l, int r, int y, i_color *vals) {
int ch, count, i;
=cut
*/
+static
int
-i_plin_d(i_img *im, int l, int r, int y, i_color *vals) {
+i_plin_d(i_img *im, int l, int r, int y, const i_color *vals) {
int ch, count, i;
unsigned char *data;
if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
=cut
*/
+static
int
-i_ppixf_d(i_img *im, int x, int y, i_fcolor *val) {
+i_ppixf_d(i_img *im, int x, int y, const i_fcolor *val) {
int ch;
if ( x>-1 && x<im->xsize && y>-1 && y<im->ysize ) {
=cut
*/
+static
int
i_gpixf_d(i_img *im, int x, int y, i_fcolor *val) {
int ch;
=cut
*/
+static
int
i_glinf_d(i_img *im, int l, int r, int y, i_fcolor *vals) {
int ch, count, i;
count = r - l;
for (i = 0; i < count; ++i) {
for (ch = 0; ch < im->channels; ++ch)
- vals[i].channel[ch] = SampleFTo8(*data++);
+ vals[i].channel[ch] = Sample8ToF(*data++);
}
return count;
}
=cut
*/
+static
int
-i_plinf_d(i_img *im, int l, int r, int y, i_fcolor *vals) {
+i_plinf_d(i_img *im, int l, int r, int y, const i_fcolor *vals) {
int ch, count, i;
unsigned char *data;
if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
for (i = 0; i < count; ++i) {
for (ch = 0; ch < im->channels; ++ch) {
if (im->ch_mask & (1 << ch))
- *data = Sample8ToF(vals[i].channel[ch]);
+ *data = SampleFTo8(vals[i].channel[ch]);
++data;
}
}
=cut
*/
-int i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps,
- int *chans, int chan_count) {
+static
+int
+i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps,
+ const int *chans, int chan_count) {
int ch, count, i, w;
unsigned char *data;
=cut
*/
-int i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps,
- int *chans, int chan_count) {
+static
+int
+i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps,
+ const int *chans, int chan_count) {
int ch, count, i, w;
unsigned char *data;
for (ch = 0; ch < chan_count; ++ch) {
}
for (i = 0; i < w; ++i) {
for (ch = 0; ch < chan_count; ++ch) {
- *samps++ = data[chans[ch]];
+ *samps++ = Sample8ToF(data[chans[ch]]);
++count;
}
data += im->channels;
else {
for (i = 0; i < w; ++i) {
for (ch = 0; ch < chan_count; ++ch) {
- *samps++ = data[ch];
+ *samps++ = Sample8ToF(data[ch]);
++count;
}
data += im->channels;
=cut
*/
-int i_ppixf_fp(i_img *im, int x, int y, i_fcolor *pix) {
+int i_ppixf_fp(i_img *im, int x, int y, const i_fcolor *pix) {
i_color temp;
int ch;
=cut
*/
-int i_plinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix) {
+int i_plinf_fp(i_img *im, int l, int r, int y, const i_fcolor *pix) {
i_color *work;
if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
=cut
*/
int i_gsampf_fp(i_img *im, int l, int r, int y, i_fsample_t *samp,
- int *chans, int chan_count) {
+ int const *chans, int chan_count) {
i_sample_t *work;
if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) {
=over
-=item i_addcolors_forward(i_img *im, i_color *colors, int count)
+=item i_addcolors_forward(i_img *im, const i_color *colors, int count)
=cut
*/
-int i_addcolors_forward(i_img *im, i_color *colors, int count) {
+int i_addcolors_forward(i_img *im, const i_color *colors, int count) {
return i_addcolors(*(i_img **)im->ext_data, colors, count);
}
}
/*
-=item i_setcolors_forward(i_img *im, int i, i_color *color, int count)
+=item i_setcolors_forward(i_img *im, int i, const i_color *color, int count)
=cut
*/
-int i_setcolors_forward(i_img *im, int i, i_color *color, int count) {
+int i_setcolors_forward(i_img *im, int i, const i_color *color, int count) {
return i_setcolors(*(i_img **)im->ext_data, i, color, count);
}
}
/*
-=item i_findcolor_forward(i_img *im, i_color *color, i_palidx *entry)
+=item i_findcolor_forward(i_img *im, const i_color *color, i_palidx *entry)
=cut
*/
-int i_findcolor_forward(i_img *im, i_color *color, i_palidx *entry) {
+int i_findcolor_forward(i_img *im, const i_color *color, i_palidx *entry) {
return i_findcolor(*(i_img **)im->ext_data, color, entry);
}
gci->cpos = 0;
gci->length = did_read;
- copy_size = min(length, gci->length);
+ copy_size = i_min(length, gci->length);
memcpy(buf, gci->buffer, copy_size);
gci->cpos += copy_size;
buf += copy_size;
}
/*
-=item free_gen_read_data(i_gen_read_data *)
+=item i_free_gen_read_data(i_gen_read_data *)
Cleans up.
=cut
*/
-void free_gen_read_data(i_gen_read_data *self) {
+void i_free_gen_read_data(i_gen_read_data *self) {
myfree(self);
}
Allocates and initializes the data structure used by i_gen_writer.
-This should be released with L<image.c/free_gen_write_data>
+This should be released with L<image.c/i_free_gen_write_data>
=cut
*/
i_gen_write_data *self = mymalloc(sizeof(i_gen_write_data));
self->cb = cb;
self->userdata = userdata;
- self->maxlength = min(max_length, sizeof(self->buffer));
+ self->maxlength = i_min(max_length, sizeof(self->buffer));
if (self->maxlength < 0)
self->maxlength = sizeof(self->buffer);
self->filledto = 0;
}
/*
-=item free_gen_write_data(i_gen_write_data *info, int flush)
+=item i_free_gen_write_data(i_gen_write_data *info, int flush)
Cleans up the write buffer.
=cut
*/
-int free_gen_write_data(i_gen_write_data *info, int flush)
+int i_free_gen_write_data(i_gen_write_data *info, int flush)
{
int result = !flush ||
info->filledto == 0 ||
return result;
}
+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) {
+ if (length < magic->magic_size)
+ return 0;
+ if (magic->mask) {
+ int i;
+ unsigned char *bufp = buffer,
+ *maskp = magic->mask,
+ *magicp = magic->magic;
+
+ for (i = 0; i < magic->magic_size; ++i) {
+ int mask = *maskp == 'x' ? 0xFF : *maskp == ' ' ? 0 : *maskp;
+ ++maskp;
+
+ if ((*bufp++ & mask) != (*magicp++ & mask))
+ return 0;
+ }
+
+ return 1;
+ }
+ else {
+ return !memcmp(magic->magic, buffer, magic->magic_size);
+ }
+}
+
+/*
+=item i_test_format_probe(io_glue *data, int length)
+
+Check the beginning of the supplied file for a 'magic number'
+
+=cut
+*/
+
+#define FORMAT_ENTRY(magic, type) \
+ { (unsigned char *)(magic ""), sizeof(magic)-1, type }
+#define FORMAT_ENTRY2(magic, type, 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[] = {
+ FORMAT_ENTRY("\xFF\xD8", "jpeg"),
+ FORMAT_ENTRY("GIF87a", "gif"),
+ FORMAT_ENTRY("GIF89a", "gif"),
+ FORMAT_ENTRY("MM\0*", "tiff"),
+ FORMAT_ENTRY("II*\0", "tiff"),
+ FORMAT_ENTRY("BM", "bmp"),
+ FORMAT_ENTRY("\x89PNG\x0d\x0a\x1a\x0a", "png"),
+ FORMAT_ENTRY("P1", "pnm"),
+ FORMAT_ENTRY("P2", "pnm"),
+ FORMAT_ENTRY("P3", "pnm"),
+ FORMAT_ENTRY("P4", "pnm"),
+ FORMAT_ENTRY("P5", "pnm"),
+ FORMAT_ENTRY("P6", "pnm"),
+ FORMAT_ENTRY("/* XPM", "xpm"),
+ FORMAT_ENTRY("\x8aMNG", "mng"),
+ FORMAT_ENTRY("\x8aJNG", "jng"),
+ /* SGI RGB - with various possible parameters to avoid false positives
+ on similar files
+ values are: 2 byte magic, rle flags (0 or 1), bytes/sample (1 or 2)
+ */
+ FORMAT_ENTRY("\x01\xDA\x00\x01", "rgb"),
+ FORMAT_ENTRY("\x01\xDA\x00\x02", "rgb"),
+ FORMAT_ENTRY("\x01\xDA\x01\x01", "rgb"),
+ FORMAT_ENTRY("\x01\xDA\x01\x02", "rgb"),
+
+ FORMAT_ENTRY2("FORM ILBM", "ilbm", "xxxx xxxx"),
+
+ /* different versions of PCX format
+ http://www.fileformat.info/format/pcx/
+ */
+ FORMAT_ENTRY("\x0A\x00\x01", "pcx"),
+ FORMAT_ENTRY("\x0A\x02\x01", "pcx"),
+ FORMAT_ENTRY("\x0A\x03\x01", "pcx"),
+ FORMAT_ENTRY("\x0A\x04\x01", "pcx"),
+ FORMAT_ENTRY("\x0A\x05\x01", "pcx"),
+
+ /* FITS - http://fits.gsfc.nasa.gov/ */
+ FORMAT_ENTRY("SIMPLE =", "fits"),
+
+ /* PSD - Photoshop */
+ FORMAT_ENTRY("8BPS\x00\x01", "psd"),
+
+ /* EPS - Encapsulated Postscript */
+ /* only reading 18 chars, so we don't include the F in EPSF */
+ FORMAT_ENTRY("%!PS-Adobe-2.0 EPS", "eps"),
+
+ /* Utah RLE */
+ FORMAT_ENTRY("\x52\xCC", "utah"),
+
+ /* GZIP compressed, only matching deflate for now */
+ FORMAT_ENTRY("\x1F\x8B\x08", "gzip"),
+
+ /* bzip2 compressed */
+ FORMAT_ENTRY("BZh", "bzip2"),
+ };
+ static const struct 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 */
+ FORMAT_ENTRY("\x00\x00\x02\x00", "cur"), /* Windows cursor */
+ FORMAT_ENTRY2("\x00\x00\x00\x00\x00\x00\x00\x07",
+ "xwd", " xxxx"), /* X Windows Dump */
+ };
+
+ unsigned int i;
+ unsigned char head[18];
+ ssize_t rc;
+
+ io_glue_commit_types(data);
+ rc = data->readcb(data, head, 18);
+ if (rc == -1) return NULL;
+ data->seekcb(data, -rc, SEEK_CUR);
+
+ for(i=0; i<sizeof(formats)/sizeof(formats[0]); i++) {
+ struct magic_entry const *entry = formats + i;
+
+ if (test_magic(head, rc, entry))
+ return entry->name;
+ }
+
+ if ((rc == 18) &&
+ tga_header_verify(head))
+ return "tga";
+
+ for(i=0; i<sizeof(more_formats)/sizeof(more_formats[0]); i++) {
+ struct magic_entry const *entry = more_formats + i;
+
+ if (test_magic(head, rc, entry))
+ return entry->name;
+ }
+
+ return NULL;
+}
+
/*
+=item i_img_is_monochrome(img, &zero_is_white)
+
+Tests an image to check it meets our monochrome tests.
+
+The idea is that a file writer can use this to test where it should
+write the image in whatever bi-level format it uses, eg. pbm for pnm.
+
+For performance of encoders we require monochrome images:
+
+=over
+
+=item *
+
+be paletted
+
+=item *
+
+have a palette of two colors, containing only (0,0,0) and
+(255,255,255) in either order.
+
=back
+zero_is_white is set to non-zero iff the first palette entry is white.
+
+=cut
+*/
+
+int
+i_img_is_monochrome(i_img *im, int *zero_is_white) {
+ if (im->type == i_palette_type
+ && i_colorcount(im) == 2) {
+ i_color colors[2];
+ i_getcolors(im, 0, colors, 2);
+ if (im->channels == 3) {
+ if (colors[0].rgb.r == 255 &&
+ colors[0].rgb.g == 255 &&
+ colors[0].rgb.b == 255 &&
+ colors[1].rgb.r == 0 &&
+ colors[1].rgb.g == 0 &&
+ colors[1].rgb.b == 0) {
+ *zero_is_white = 0;
+ return 1;
+ }
+ else if (colors[0].rgb.r == 0 &&
+ colors[0].rgb.g == 0 &&
+ colors[0].rgb.b == 0 &&
+ colors[1].rgb.r == 255 &&
+ colors[1].rgb.g == 255 &&
+ colors[1].rgb.b == 255) {
+ *zero_is_white = 1;
+ return 1;
+ }
+ }
+ else if (im->channels == 1) {
+ if (colors[0].channel[0] == 255 &&
+ colors[1].channel[1] == 0) {
+ *zero_is_white = 0;
+ return 1;
+ }
+ else if (colors[0].channel[0] == 0 &&
+ colors[0].channel[0] == 255) {
+ *zero_is_white = 1;
+ return 1;
+ }
+ }
+ }
+
+ *zero_is_white = 0;
+ return 0;
+}
+
+/*
+=back
+
+=head1 AUTHOR
+
+Arnar M. Hrafnkelsson <addi@umich.edu>
+
+Tony Cook <tony@develop-help.com>
+
=head1 SEE ALSO
L<Imager>, L<gif.c>