-#include "image.h"
-#include "imagei.h"
-#include "io.h"
+#include "imager.h"
+#include "imageri.h"
/*
=head1 NAME
/* Hack around an obscure linker bug on solaris - probably due to builtin gcc thingies */
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_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);
*/
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));
}
/*
=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()
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");
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)
+ m_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
/*
=item i_img_info(im, info)
+=category Image
+
Return image information
im - Image pointer
/*
=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
+
+Creates a new image that is a copy of src.
-Copies the contents of the image I<src> over the image I<im>.
+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) {
}
else {
i_fcolor *pv;
- if (src->bits == i_16_bits)
- i_img_16_new_low(im, x1, y1, src->channels);
- else if (src->bits == i_double_bits)
- i_img_double_new_low(im, x1, y1, src->channels);
- else {
- fprintf(stderr, "i_copy(): Unknown image bit size %d\n", src->bits);
- return; /* I dunno */
- }
pv = mymalloc(sizeof(i_fcolor) * x1);
for (y = 0; y < y1; ++y) {
}
myfree(vals);
}
+
+ return im;
}
/*
-=item i_rubthru(im, src, tx, ty)
+=item i_rubthru(im, src, tx, ty, src_minx, src_miny, src_maxx, src_maxy )
-Takes the image I<src> and applies it at an original (I<tx>,I<ty>) in I<im>.
+=category Image
+
+Takes the sub image I<src[src_minx, src_maxx)[src_miny, src_maxy)> and
+overlays it at (I<tx>,I<ty>) on the image object.
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
*/
int
-i_rubthru(i_img *im,i_img *src,int tx,int ty) {
+i_rubthru(i_img *im, i_img *src, int tx, int ty, int src_minx, int src_miny,
+ int src_maxx, int src_maxy) {
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));
+ mm_log((1,"i_rubthru(im %p, src %p, tx %d, ty %d, src_minx %d, "
+ "src_miny %d, src_maxx %d, src_maxy %d)\n",
+ im, src, tx, ty, src_minx, src_miny, src_maxx, src_maxy));
i_clear_error();
if (im->channels == 3 && src->channels == 4) {
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); */
+ tty = ty;
+ for(y = src_miny; y < src_maxy; y++) {
+ ttx = tx;
+ for(x = src_minx; x < src_maxx; x++) {
i_gpix(src, x, y, &pv);
i_gpix(im, ttx, tty, &orig);
alpha = pv.channel[alphachan];
+ (255 - alpha) * orig.channel[ch])/255;
}
i_ppix(im, ttx, tty, &dest);
- tty++;
+ ttx++;
}
- ttx++;
+ tty++;
}
}
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); */
+ tty = ty;
+ for(y = src_miny; y < src_maxy; y++) {
+ ttx = tx;
+ for(x = src_minx; x < src_maxx; x++) {
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];
+ + (1 - alpha) * orig.channel[ch];
}
i_ppixf(im, ttx, tty, &dest);
- tty++;
+ ttx++;
}
- ttx++;
+ tty++;
}
}
}
-
-
-
-
-
-
-
-i_img*
-i_scaleaxis_3ch_8bit(i_img *im, int size, int Axis) {
-
- int i, j;
- int iEnd, jEnd;
-
- int hsize, vsize;
-
- short psave;
- unsigned long *pixels;
- i_color val;
- i_img *new_img;
-
- mm_log((1,"i_scaleaxis_3ch_8bit(im %p, size %d,Axis %d)\n",im, size, Axis));
-
- if (Axis == XAXIS) {
- hsize = size;
- vsize = im->ysize;
-
- jEnd = hsize;
- iEnd = vsize;
- pixels = mymalloc(sizeof(*pixels) * im->xsize);
- } else {
- hsize = im->xsize;
- vsize = size;
-
- jEnd = vsize;
- iEnd = hsize;
- pixels = mymalloc(sizeof(*pixels) * im->ysize);
- }
-
- new_img = i_img_empty_ch(NULL, hsize, vsize, im->channels);
-
-
- if (Axis == XAXIS) {
-
- for (i=0; i<iEnd; i++) {
- int end = im->xsize;
-
- for(j=0; j<im->xsize; j++) {
- i_gpix(im, j, i, &val);
- pixels[j] = (val.rgba.r<<24) | (val.rgba.g<<16) | (val.rgba.b<<8) | (val.rgba.a<<0);
- }
-
- /* printf("jEnd = %d, end = %d\n", jEnd, end); */
- while ((end+1)/2>=size) {
- int lend = end/2;
- end = (end+1) / 2;
-
- for(j=0; j<lend; j++) {
- unsigned long a = pixels[2*j];
- unsigned long b = pixels[2*j+1];
- pixels[j] = (((a ^ b) & 0xfefefefeUL) >> 1) + (a & b);
- }
- if (end>lend) {
- pixels[j] = pixels[2*j];
- j++;
- }
- }
-
- printf("end = %d size = %d\n", end, size);
-
- /* Replace this with Bresenham later */
- for(j=0; j<size; j++) {
- float f = i;
- /* if ((i*size)/end <) */
- unsigned long t = pixels[j];
- val.rgba.r = (t >> 24) & 0xff;
- val.rgba.g = (t >> 16) & 0xff;
- val.rgba.b = (t >> 8) & 0xff;
- val.rgba.a = t & 0xff;
- i_ppix(new_img, j, i, &val);
- }
- }
- }
-
- return new_img;
-}
-
-
-
-
-
-
-
/*
=item i_scaleaxis(im, value, axis)
if (Axis == XAXIS) {
- return i_scaleaxis_3ch_8bit(im, (int)(0.5+im->xsize*Value), Axis);
-
hsize = (int)(0.5 + im->xsize * Value);
+ if (hsize < 1) {
+ hsize = 1;
+ Value = 1.0 / im->xsize;
+ }
vsize = im->ysize;
jEnd = hsize;
hsize = im->xsize;
vsize = (int)(0.5 + im->ysize * Value);
+ if (vsize < 1) {
+ vsize = 1;
+ Value = 1.0 / im->ysize;
+ }
+
jEnd = vsize;
iEnd = hsize;
}
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.
/*
=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.
*/
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 ) {
*/
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) {
*/
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 ) {
*/
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) {
=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) {
=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);
}
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;
-/*
-=item i_test_format_probe(io_glue *data, int length)
+ for (i = 0; i < magic->magic_size; ++i) {
+ int mask = *maskp == 'x' ? 0xFF : *maskp == ' ' ? 0 : *maskp;
+ ++maskp;
-Cleans up the write buffer.
+ if ((*bufp++ & mask) != (*magicp++ & mask))
+ return 0;
+ }
-Will flush any left-over data if I<flush> is non-zero.
+ return 1;
+ }
+ else {
+ return !memcmp(magic->magic, buffer, magic->magic_size);
+ }
+}
-Returns non-zero if flush is zero or if info->cb() returns non-zero.
+/*
+=item i_test_format_probe(io_glue *data, int length)
-Return zero only if flush is non-zero and info->cb() returns zero.
-ie. if it fails.
+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, mask }
-char *
+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"),
- static struct {
- char *magic;
- char *name;
- } formats[] = {
- {"\xFF\xD8", "jpeg"},
- {"GIF87a", "gif"},
- {"GIF89a", "gif"},
- {"MM\0*", "tiff"},
- {"II*\0", "tiff"},
- {"BM", "bmp"},
- {"\x89PNG\x0d\x0a\x1a\x0a", "png"},
- {"P1", "pnm"},
- {"P2", "pnm"},
- {"P3", "pnm"},
- {"P4", "pnm"},
- {"P5", "pnm"},
- {"P6", "pnm"},
+ /* Utah RLE */
+ FORMAT_ENTRY("\x52\xCC", "utah"),
};
+ 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 */
+ };
+
unsigned int i;
- char head[18];
- char *match = NULL;
+ unsigned char head[18];
ssize_t rc;
io_glue_commit_types(data);
data->seekcb(data, -rc, SEEK_CUR);
for(i=0; i<sizeof(formats)/sizeof(formats[0]); i++) {
- int c;
- ssize_t len = strlen(formats[i].magic);
- if (rc<len) continue;
- c = !strncmp(formats[i].magic, head, len);
- if (c) {
- match = formats[i].name;
- break;
- }
+ struct magic_entry const *entry = formats + i;
+
+ if (test_magic(head, rc, entry))
+ return entry->name;
}
- if (match && !strcmp(match, "jpeg")) {
- unsigned int x0, x1;
- rc = data->readcb(data, head, 18);
- if (rc == -1) return NULL;
- x0 = (unsigned char)head[0];
- x1 = (unsigned char)head[1];
- data->seekcb(data, -rc, SEEK_CUR);
- printf("Jpeg reread: %x %x\n", x0, x1);
- }
+ 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;
+ }
- if (!match &&
- (rc == 18) &&
- tga_header_verify(head)) return "tga";
- return match;
+ return NULL;
}